Google Trends API in Python: Interest Over Time as JSON
To get Google Trends interest over time in Python, send a GET request to /v1/google-trends/interest with requests, passing the keyword as q. The response is JSON with a timeline_data array of dated values and an interest_over_time summary. Each successful call costs 1 credit, and you get 1,000 free credits a month. No scraping and no browser session on your side.
Is there an official Google Trends API for Python?
Google announced the Google Trends API as an alpha in July 2025 and opened it to a limited group of early-access testers rather than as a generally available API (Google Search Central, "Introducing the Google Trends API (alpha)", 2025; Search Engine Journal, 2025). Unless you've been given alpha access, don't build a production job on it. The alternatives are an unofficial library, a scraper you maintain, or a hosted endpoint like the one below.
The best-known unofficial option is pytrends. Its repository was archived and made read-only on April 17, 2025, and its README warns it is "only good until Google changes their backend again" (pytrends on GitHub, 2025). Libraries like this parse Google's pages, so a page change can break your job without a code change on your side. If you only need a one-off export, Google Trends' own site works fine. This guide is for code that has to keep running. For the wider trade-off, see what maintaining a scraper really involves.
How do you call the Interest endpoint from Python?
You call GET /v1/google-trends/interest with your key in the X-API-Key header and the keyword in q. The endpoint belongs to the Google Trends API and is documented on the Interest endpoint page. Get a key first: sign up for a free API key, then read how authentication works.
Here is the call as cURL:
curl "https://api.perceptlayer.com/v1/google-trends/interest?q=tesla&geo=US&time_range=1y" \
-H "X-API-Key: $API_KEY"
And the same call with requests:
import os
import requests
BASE = "https://api.perceptlayer.com"
HEADERS = {"X-API-Key": os.environ["API_KEY"]}
def get(path, **params):
resp = requests.get(f"{BASE}{path}", params=params, headers=HEADERS, timeout=30)
resp.raise_for_status()
return resp
resp = get("/v1/google-trends/interest", q="tesla", geo="US", time_range="1y")
data = resp.json()
for point in data["timeline_data"]:
print(point["date"], point["value"])
print("credits used:", resp.headers["X-Credits-Used"])
print("credits left:", resp.headers["X-Credits-Remaining"])
Set API_KEY in your environment first. Keys start with sk_live_. The two credit headers come back on every successful response, so you can log spend per call without extra requests.
Which parameters does the Interest endpoint take?
The Interest endpoint takes q (required) and four optional parameters: geo, time_range, hl and search_type. The table lists the types and allowed values documented for it. Nothing else is documented about them, so check the playground on the API page before you rely on behaviour beyond what's listed here.
| Parameter | Type | Required | Allowed values / limits |
|---|---|---|---|
q |
string | yes | up to 550 characters |
geo |
string | no | up to 10 characters |
time_range |
string | no | 1h, 4h, 1d, 7d, 30d, 90d, 1y, 5y, all |
hl |
string | no | up to 2 characters |
search_type |
string | no | web, images, news, youtube, shopping |
Use time_range to change the window and search_type to ask about image, news, YouTube or shopping searches instead of web search. Use geo to scope the keyword to a place, as in geo=US above. For the full request rules, see the Requests docs.
What does the interest-over-time response look like?
The response has four top-level parts: search_parameters (what was queried), timeline_data (the dated points), interest_over_time (the same points plus summary figures) and response_time_ms. This excerpt is trimmed from a recorded response to the cURL request above, with the cut marked by …:
{
"search_parameters": {
"keyword": "tesla",
"geo": "US",
"time_range": "today+12-m",
"hl": "en",
"search_type": "web"
},
"timeline_data": [
{
"timestamp": 1760832000,
"date": "Oct 19 – 25, 2025",
"value": 40
},
{
"timestamp": 1761436800,
"date": "Oct 26 – Nov 1, 2025",
"value": 39
},
…
],
"interest_over_time": {
"average": 49.13,
"max_value": 100,
"min_value": 39,
…
},
"response_time_ms": 320
}
Each point has a Unix timestamp, a human-readable date range and a value. The time_range of 1y comes back echoed as today+12-m, and the points in this sample are weekly. In the recorded response max_value is 100, which tells you value is an index, not a search count. Compare values against each other, not against other keywords' raw volume.
Turning it into a table is a few lines:
import csv
rows = data["interest_over_time"]["data_points"]
with open("tesla_interest.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["timestamp", "date", "value"])
for r in rows:
writer.writerow([r["timestamp"], r["date"], r["value"]])
How do you get interest by region and related queries?
Interest By Region and Related are separate endpoints on the same API, each 1 credit per call and each taking q as the one required parameter. Call them the same way as Interest, with the get helper above. The responses aren't excerpted here because we haven't recorded them for this guide; open each endpoint page to see its response shape.
| Endpoint | Page | Required | Optional |
|---|---|---|---|
/v1/google-trends/interest-by-region |
Interest By Region | q |
geo, region, date, cat, gprop, tz, hl |
/v1/google-trends/related |
Related | q |
geo, time_range, hl, search_type |
region = get(
"/v1/google-trends/interest-by-region",
q="tesla", geo="US", region="REGION",
).json()
related = get(
"/v1/google-trends/related",
q="tesla", geo="US", time_range="1y",
).json()
region accepts REGION or COUNTRY. On Related, q is limited to 100 characters, lower than Interest's 550. The API also has Autocomplete, Trending Now and Trending News, six endpoints in total, each 1 credit. If you want news articles for a keyword rather than search interest, see the Google News API guide.
What does a Google Trends call cost?
Every successful call to these endpoints costs 1 credit, and failed calls cost nothing. You get 1,000 free credits every month after verifying an email address, with no credit card. Purchased credits last 12 months, with no subscription (pricing). The Credits docs explain the headers.
Here is the arithmetic for a keyword tracker:
- One keyword, three endpoints (interest, region, related): 3 calls × 1 credit = 3 credits.
- 100 keywords refreshed once: 100 × 3 = 300 credits, inside the 1,000 free credits.
- 100 keywords refreshed weekly for a month (4 runs): 300 × 4 = 1,200 credits. That exceeds the free tier by 200 credits.
Past the free tier, credits come in prepaid packs of 10,000 (Starter), 50,000 (Build), 200,000 (Growth), 500,000 (Pro), 1,000,000 (Scale) and 5,000,000 (Volume). The 200 credits over the free tier in the last example fit easily inside the Starter pack's 10,000, and 100 keywords refreshed weekly would use that pack for about eight months at 1,200 credits a month. See pricing for what each pack costs. The service is prepaid: when the balance runs out, calls return insufficient_credits (402) and nothing more is debited. There is no automatic top-up.
How should you handle errors and retries?
Errors return an HTTP status and a JSON body shaped as {"error": {"code", "message", "request_id"}}, and a failed call returns X-Credits-Used: 0. Rate-limited (429) and temporarily unavailable (503) responses carry a Retry-After header with the seconds to wait. The full list of codes is in the Errors docs, and limits are in Rate limits.
import time
def get_with_retry(path, attempts=3, **params):
for attempt in range(attempts):
resp = requests.get(
f"{BASE}{path}", params=params, headers=HEADERS, timeout=30
)
if resp.status_code in (429, 503) and attempt < attempts - 1:
time.sleep(int(resp.headers.get("Retry-After", 5)))
continue
resp.raise_for_status()
return resp
One caveat: requests have no idempotency key. If your client times out, the call may have succeeded and been billed, so a retry can cost a second credit. For a keyword job that's 1 credit, but read how to retry without paying twice before looping over thousands of keywords. To avoid repeat spend on keywords you query often, cache the responses.
Next step: get a free API key, then run the Interest call from this guide in the playground on the Google Trends API page. For agents, the same endpoints are available as tools over MCP.
APIs in this post
Frequently asked questions
Does Google have an official Trends API?
Google announced a Google Trends API in alpha in July 2025 and invited developers to sign up for early access as alpha testers (Google Search Central, 2025). If you haven't been given access, don't plan on it. Perceptlayer exposes Google Trends data as JSON endpoints you can call with a free key today.
Does pytrends still work?
Its repository was archived on April 17, 2025 and is read-only, and its README says it is only good until Google changes its backend (pytrends on GitHub, 2025). It may still run for you, but nobody will patch it if Google changes something. A hosted endpoint moves that maintenance off your code.
How much does it cost to track keywords with the Google Trends API?
Each call costs 1 credit, and failed calls cost nothing. Tracking 100 keywords with interest, region and related calls is 300 credits per run, inside the 1,000 free monthly credits. Beyond that, the Starter pack is 10,000 credits, enough for 3,333 keywords at 3 credits each. See pricing for what credits cost.
Can I use the endpoint to compare several keywords?
The Interest endpoint takes one q of up to 550 characters, and the documentation doesn't describe multi-keyword comparison, so this guide doesn't claim it. The safe approach is one call per keyword, 1 credit each. Check the Interest page and its playground before sending comma-separated terms.
What happens if the call fails or my credits run out?
A failed call returns an HTTP status and a JSON error body with a code, and costs nothing (X-Credits-Used: 0). When your balance reaches zero, calls return insufficient_credits (402) and nothing more is debited. Rate-limited and unavailable responses include Retry-After with the seconds to wait.
Should I use a Google Trends scraper instead?
Scraping Google Trends yourself means handling its request limits and page changes, and maintaining unofficial libraries such as pytrends, whose repository is archived. The interest endpoint returns weekly interest over time as JSON for 1 credit per successful call. A scraper makes sense only for a Trends view the endpoints don't cover.