Appearance
Historical SERPs (Live) Fresh
The Historical SERPs endpoint returns complete Google SERP snapshots collected within a specified date range. You get full ranking data including organic positions, featured snippets, knowledge panels, local packs, and all other SERP elements — by month — for the past 12 months.
Endpoint: POST https://api.dataforseo.com/v3/dataforseo_labs/google/historical_serps/live
Use this endpoint to analyze how rankings have changed over time, detect SERP volatility, and study featured snippet ownership history for any keyword.
Data Availability
- Historical data covers up to 12 months back from the current date.
- Each result object in the response represents one SERP snapshot (one month).
- Each SERP item within a snapshot reflects the ranking state at that point in time.
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
keyword | string | Yes | Target keyword. Max 700 characters. All %## sequences decoded; + decoded to space. |
location_name | string | Conditional | Full location name (e.g., "United Kingdom"). Required unless location_code is set. |
location_code | integer | Conditional | Location code (e.g., 2840 for USA). Required unless location_name is set. |
language_name | string | Conditional | Full language name (e.g., "English"). Required unless language_code is set. |
language_code | string | Conditional | Language code (e.g., "en"). Required unless language_name is set. |
date_from | string | No | Start of date range. Format: "yyyy-mm-dd". Min: 365 days ago. If omitted, defaults to 365 days back. |
date_to | string | No | End of date range. Format: "yyyy-mm-dd". Defaults to today if omitted. |
tag | string | No | Custom task identifier. Max 255 characters. |
Note: Each Live API call for this endpoint may contain only one task. Rate limit: 2,000 calls/minute, max 30 simultaneous.
Response Structure
Top-Level Task Fields
| Field | Type | Description |
|---|---|---|
tasks[].result[].keyword | string | Input keyword (decoded) |
tasks[].result[].location_code | integer | Location from request |
tasks[].result[].language_code | string | Language from request |
tasks[].result[].total_count | integer | Total SERP snapshots in database for this query |
tasks[].result[].items_count | integer | Snapshots returned in this response |
tasks[].result[].items[] | array | Individual SERP snapshots (one per month) |
SERP Snapshot Fields (per item)
| Field | Type | Description |
|---|---|---|
datetime | string | Date/time of SERP capture in UTC (yyyy-mm-dd hh-mm-ss +00:00) |
se_domain | string | Search engine domain used |
check_url | string | Direct URL to verify results in search engine |
item_types | array | All SERP element types present in this snapshot |
se_results_count | integer | Total organic results count |
items_count | integer | Number of result items in this snapshot |
spell | object | Autocorrection info (if search engine corrected the query) |
items[] | array | Individual SERP result elements |
SERP Item Types
The item_types array lists all element types present in the snapshot. Possible values include:
answer_box, carousel, multi_carousel, featured_snippet, google_flights, google_reviews, google_posts, images, jobs, knowledge_graph, local_pack, hotels_pack, map, organic, paid, people_also_ask, related_searches, people_also_search, shopping, top_stories, twitter, video, events, mention_carousel, recipes, top_sights, scholarly_articles, popular_products, podcasts, questions_and_answers, find_results_on, stocks_box, visual_stories, commercial_units, local_services, google_hotels, math_solver, ai_overview
Organic Result Fields
| Field | Type | Description |
|---|---|---|
type | string | Always "organic" |
rank_group | integer | Position within organic results |
rank_absolute | integer | Absolute position among all SERP elements |
position | string | "left" or "right" |
domain | string | Domain of the ranking result |
title | string | Page title |
url | string | Ranking URL |
breadcrumb | string | Breadcrumb shown in SERP |
description | string | Meta description or snippet |
is_featured_snippet | boolean | Whether the result also holds the featured snippet |
is_image | boolean | Includes an image |
is_video | boolean | Includes a video |
is_malicious | boolean | Flagged as malicious by Google |
amp_version | boolean | Has AMP version |
highlighted | array | Words bolded in the snippet |
rating | object | Star rating if shown (type, value, votes count, max) |
links | array | Sitelinks below the result |
about_this_result | object | "About this result" panel data |
extended_snippet | string | Additional snippet text after the description |
pre_snippet | string | Additional text before the description |
cURL Example
bash
curl --request POST \
--url https://api.dataforseo.com/v3/dataforseo_labs/google/historical_serps/live \
--header 'Authorization: Basic BASE64(login:password)' \
--header 'Content-Type: application/json' \
--data '[
{
"keyword": "best roofing contractor miami",
"location_code": 2840,
"language_code": "en",
"date_from": "2024-06-01",
"date_to": "2025-05-01"
}
]'Python Example
python
import requests
from requests.auth import HTTPBasicAuth
import json
from datetime import datetime, timedelta
def historical_serps(keyword, location_code=2840, language_code="en", months_back=12):
date_to = datetime.now().strftime("%Y-%m-%d")
date_from = (datetime.now() - timedelta(days=months_back * 30)).strftime("%Y-%m-%d")
payload = [{
"keyword": keyword,
"location_code": location_code,
"language_code": language_code,
"date_from": date_from,
"date_to": date_to
}]
response = requests.post(
"https://api.dataforseo.com/v3/dataforseo_labs/google/historical_serps/live",
auth=HTTPBasicAuth("your_login", "your_password"),
headers={"Content-Type": "application/json"},
data=json.dumps(payload)
)
data = response.json()
snapshots = data["tasks"][0]["result"][0]["items"]
return snapshots
def track_domain_rank_over_time(keyword, target_domain, location_code=2840):
snapshots = historical_serps(keyword, location_code)
rankings = []
for snapshot in snapshots:
date = snapshot["datetime"][:10] # yyyy-mm-dd
serp_items = snapshot.get("items", [])
rank = None
for item in serp_items:
if item.get("type") == "organic" and target_domain in item.get("domain", ""):
rank = item["rank_absolute"]
break
rankings.append({"date": date, "rank": rank})
return rankings
# Usage
history = track_domain_rank_over_time(
"roof repair miami fl",
"bestroofingmiami.com"
)
for entry in history:
rank_display = entry["rank"] if entry["rank"] else "not ranking"
print(f"{entry['date']}: position {rank_display}")Use Cases
Rank Tracking History — Plot a domain's organic position for a keyword over 12 months without requiring a separate rank tracking subscription.
SERP Volatility Analysis — Compare item_types across months to detect when features like local_pack or ai_overview appeared or disappeared.
Featured Snippet Ownership — Track which domain held the featured snippet and when ownership changed.
Competitor Monitoring — Identify when a competitor entered or dropped out of the top 10 for a target keyword.
Algorithm Impact Assessment — Correlate ranking changes with known Google algorithm update dates.
Notes
- Each POST request for this endpoint can contain only one task (unlike most other endpoints that allow batching).
- The
check_urlfield in each snapshot can be opened in Incognito mode to verify results. - The
spellobject indicates when Google's autocorrection redirected the query — important for understanding which keyword the SERP actually represents. - Use
%25for literal%characters in keywords and%2Bfor literal+characters.