# Google Trends API Python: ~4.6s Typical (Was ~9s) (https://www.socialcrawl.dev/blog/google-trends-api-faster)
> A Google Trends API Python GET is ~4.6s typical (was ~9s on 22 billed calls). Live interest-over-time and related queries, same 5 credits, 2026-09-08 UTC.
A Google Trends API Python GET now typically returns in **~4.6s** on a billed miss (was **~9s**). That was measured on production across **22 billed calls** after 2026-09-07. Credits stayed **5**. Interest-over-time (`GET /v1/google_trends/explore`) and related/rising (`GET /v1/google_trends/rising`) share that contract.
Google [announced a Trends API alpha on 24 Jul 2025](https://developers.google.com/search/blog/2025/07/trends-api). Access is apply-only for limited testers — not a public REST key. [pytrends](https://pypi.org/project/pytrends/) is the unofficial pandas library people already `pip install` — last release 13 Apr 2023, looking for maintainers. You call it with `x-api-key` and a GET.
Which Google Trends API to pick, and what it costs, is on [best Google Trends APIs 2026](/blog/best-google-trends-apis-2026). This post is the speed change and how to call `explore` / `rising`.
**Stack:** Python 3 · `requests` · `GET https://www.socialcrawl.dev/v1/google_trends/explore` and `/v1/google_trends/rising` · header `x-api-key`. JSON is trimmed from a 2026-09-08 production harvest on the SocialCrawl API — not a screenshot, not a DataFrame stub. A free 404 and a free 400 are in here too, so a dead keyword does not look like a timeout.
## How do you pull Google Trends interest over time in Python?
`GET /v1/google_trends/explore` is the Google Trends interest over time API. Pass 1–5 keywords, an optional `location`, and a `timeframe`. The response is dated `series` plus per-keyword `averages` on Google's relative 0–100 index, not search volume. The request is one GET. No SDK.
This Google Trends API Python example compares three US terms over `past_12_months` (the default window). Harvest row `#2`, 2026-09-08, cache miss, `request_id` `req-xyaesW1MDftWKcMP`. HTTP 200, **5 credits**, **6,751 ms**.
```python
BASE = "https://www.socialcrawl.dev"
r = requests.get(
f"{BASE}/v1/google_trends/explore",
params={
"keywords": "oat milk,almond milk,soy milk",
"location": "US",
"timeframe": "past_12_months",
},
headers={"x-api-key": os.environ["SOCIALCRAWL_API_KEY"]},
timeout=90,
)
r.raise_for_status()
payload = r.json()
print(payload["credits_used"], payload["data"]["averages"])
# 5, oat milk 51 / almond milk 68 / soy milk 24
```
Curl twin of the same GET:
```bash
curl -s --max-time 90 -H "x-api-key: $SOCIALCRAWL_API_KEY" \
"https://www.socialcrawl.dev/v1/google_trends/explore?keywords=oat%20milk,almond%20milk,soy%20milk&location=US&timeframe=past_12_months"
```
Trimmed envelope from that call (three series × **53** weekly points; first and last bucket only):
```json
{
"success": true,
"data": {
"averages": [
{ "keyword": "oat milk", "value": 51 },
{ "keyword": "almond milk", "value": 68 },
{ "keyword": "soy milk", "value": 24 }
],
"series": [
{
"keyword": "oat milk",
"points": [
{ "date": "2025-09-07", "value": 43, "partial": false },
{ "date": "2026-09-06", "value": 60, "partial": true }
]
},
{
"keyword": "almond milk",
"points": [
{ "date": "2025-09-07", "value": 56, "partial": false },
{ "date": "2026-09-06", "value": 71, "partial": true }
]
},
{
"keyword": "soy milk",
"points": [
{ "date": "2025-09-07", "value": 18, "partial": false },
{ "date": "2026-09-06", "value": 22, "partial": true }
]
}
]
},
"credits_used": 5,
"request_id": "req-xyaesW1MDftWKcMP"
}
```
Read the averages as **one** 0–100 scale across the set. Almond milk 68, oat milk 51, soy milk 24. Those three numbers are comparable **only inside this call**. Almond milk is the only term that hits **100** (week of 2026-04-12). Soy milk never exceeds **36** in the full series. That is the normalisation proof: three terms, one request, directly comparable. Two separate explores are not comparable. [Google's own FAQ](https://support.google.com/trends/answer/4365533) is blunt about this — a point is a share of searches in that geography and window, scaled 0–100, not a headcount.
The envelope also carries `success`, `platform`, `endpoint`, `credits_used`, and `request_id`. `credits_used` is **5** on a billed miss. Drop the last bucket before you chart: every explore series in this harvest set `partial: true` on the week of 2026-09-06 (still counting).
Same object, one term. `keywords=solid state battery` (`req-T98bfg3d2yGqBi4r`) returned 53 points, average **42**, peak **100** the week of 2026-06-07, min **17** on 2025-09-28. **7,284 ms**, 5 credits, cache miss. Same `series` / `averages` shape. Swap the `keywords` param; do not learn a second schema.
Caveats that bite in practice:
- Relative index ≠ search volume. Almond milk at 68 does not mean 68 searches.
- 1–5 keywords. More than five is a free 400.
- `location` accepts ISO (`US`, `KR`), the full country name as Trends spells it (`South Korea`), or a numeric code. Default leans worldwide-US.
- Default `timeframe` is `past_12_months`. Eight presets, no arbitrary date range.
## How do you get Google Trends related queries from an API?
`GET /v1/google_trends/rising` returns `rising` and `top` for **one** keyword. The resource name is `rising`, not `related-queries`. Google's alpha announcement is about consistently scaled interest data, not related-query lists. This path is the related queries API: breakouts with a percent `growth`, plus the most-searched related queries on a 0–100 `value`.
Rising is the list you want when a term is about to move — breakouts that are not yet large enough to dominate the interest-over-time series. Top is where demand is concentrated right now. The param is **`keyword` (singular)**. A comma-separated list is a free 400. Usual order: `explore` to size the series, then `rising` on the winner.
Harvest row `#4`. `keyword=solid state battery`, US, `past_12_months`. HTTP 200, **5 credits**, **19,059 ms**, cache miss, `req-JmaL2ZAMP0bYaoVT`. 15 rising rows (numeric `growth` on **7** of 15), 25 top rows.
```python
r = requests.get(
f"{BASE}/v1/google_trends/rising",
params={
"keyword": "solid state battery",
"location": "US",
"timeframe": "past_12_months",
},
headers={"x-api-key": os.environ["SOCIALCRAWL_API_KEY"]},
timeout=90,
)
r.raise_for_status()
payload = r.json()
print(
payload["credits_used"],
len(payload["data"]["rising"]),
len(payload["data"]["top"]),
)
# 5, 15, 25
```
```bash
curl -s --max-time 90 -H "x-api-key: $SOCIALCRAWL_API_KEY" \
"https://www.socialcrawl.dev/v1/google_trends/rising?keyword=solid%20state%20battery&location=US&timeframe=past_12_months"
```
Trimmed body. Numeric growth kept; two `null`s left as Google sent them:
```json
{
"success": true,
"data": {
"rising": [
{ "query": "donut battery", "growth": null },
{ "query": "donut lab", "growth": null },
{ "query": "solid state portable battery", "growth": 650 },
{ "query": "solid state drive", "growth": 500 },
{ "query": "silver solid state battery", "growth": 200 },
{ "query": "solid state battery phone", "growth": 200 },
{ "query": "samsung solid state battery", "growth": 180 }
],
"top": [
{ "query": "solid state drive", "value": 100 },
{ "query": "what is solid state battery", "value": 64 },
{ "query": "solid power", "value": 59 },
{ "query": "solid state battery toyota", "value": 57 },
{ "query": "samsung solid state battery", "value": 56 }
]
},
"credits_used": 5,
"request_id": "req-JmaL2ZAMP0bYaoVT"
}
```
`rising[].growth` is percent growth. A true breakout can read into the thousands; this harvest's max is **+650** (`solid state portable battery`), then **+500**, **+200**, **+200**, **+180**. Eight of the 15 rising rows came back `growth: null`. Google omitted the number; the envelope carries `_warnings` for those. Do not fill them in. `top[].value` is 0–100 relative. `solid state drive` at 100 is the related-query ceiling in this window, not a volume count.
This rising call was **19.1s** on this run — that number belongs with the n=4 session below, not as the production typical.
## How long does a Google Trends API Python call take?
Typical billed call is **~4.6s** now (was **~9s**), measured on **22 billed calls** after 2026-09-07. Two tables. Do not mix them.
Production claim, **22 billed calls** after 2026-09-07:
| Fact | Before → after (22 billed calls, 2026-09-07) |
| --- | --- |
| Typical billed call | **~9s → ~4.6s** |
| Slow tail | **p95 ~47s → ~12s** as the worst of those 22 |
| Timeouts | **273 of 19,459** over 30 days, each after **~48s** → now rare |
| Unchanged | Same params, same shape, same **5 credits**, same free **400** / **404** |
This Google Trends Python API run, **n=4** cache-miss billed calls on 2026-09-08 (window 00:23:27Z–00:26:45Z), all 5 credits:
| Call | latency |
| --- | ---: |
| explore multi (`oat milk,almond milk,soy milk`, US) | **6.8s** (6,751 ms) |
| explore single (`solid state battery`, US) | **7.3s** (7,284 ms) |
| rising (`solid state battery`, US) | **19.1s** (19,059 ms) |
| explore Hangul (`선풍기`, South Korea) | **19.7s** (19,745 ms) |
US English explore answered in ~7s. Hangul and rising sat near **19s** — **slower than the 22-call worst of ~12s**, on a sample of four. Still inside a 60s client timeout; not a 48s timeout failure. Cold, non-English and non-US terms are where the update shows most. Do not overwrite the production table with a four-call mean.
Captured call, harvest `#3`. `keywords=선풍기` (electric fan), `location=South Korea`, `past_12_months`. 53 points, average **21**, winter floor **4** (week of 2026-02-15), summer peak **100** (week of 2026-07-26), last point 13 `partial: true`. **19,745 ms**, 5 credits, cache miss, `req-PIzuSdK1giC8D5Zw`.
```python
r = requests.get(
f"{BASE}/v1/google_trends/explore",
params={
"keywords": "선풍기",
"location": "South Korea",
"timeframe": "past_12_months",
},
headers={"x-api-key": os.environ["SOCIALCRAWL_API_KEY"]},
timeout=90,
)
r.raise_for_status()
payload = r.json()
print(payload["credits_used"], payload["data"]["averages"][0]["value"])
# 5, 21
```
```json
{
"success": true,
"data": {
"series": [
{
"keyword": "선풍기",
"points": [
{ "date": "2025-09-07", "value": 18, "partial": false },
{ "date": "2026-02-15", "value": 4, "partial": false },
{ "date": "2026-07-26", "value": 100, "partial": false },
{ "date": "2026-09-06", "value": 13, "partial": true }
]
}
],
"averages": [{ "keyword": "선풍기", "value": 21 }]
},
"credits_used": 5,
"request_id": "req-PIzuSdK1giC8D5Zw"
}
```
A seasonal series is the easy read: winter 4, July 100, window average 21. The latency is not tidy. 19.7s is not ~4.6s. The upgrade note says this lane improved most; this one pull, on a sample of four, was still the slowest billed call of the morning.
Empty interest is a **404** at **0 credits**, and that 404 can be slow. `keywords=zzqxjbv7wmpl3nonsense99` explore took **52,918 ms**, `req-Q2kdMXZn17dS9X6l`. That is a fallback confirming no data, not a billed timeout. The message names that location and timeframe were accepted, so you know it is the keyword. Some nonsense strings return a sparse 200 and get billed 5 — only the 404 that actually 404'd is below. The matching rising 404 (`req-JSVh0G2ZHHUy7YbJ`) is the same contract: 0 credits, 11.7s.
```json
{
"success": false,
"error": {
"type": "RESOURCE_NOT_FOUND",
"message": "No search-interest data were returned for this keyword. The location and timeframe were accepted; Google Trends simply holds too little search volume for this keyword in that combination to build a result. Try a wider `timeframe`, a broader keyword, or the keyword in the local language of the location you requested. You were not charged for this request.",
"status": 404,
"doc_url": "https://www.socialcrawl.dev/docs/errors#resource-not-found"
},
"credits_used": 0,
"request_id": "req-Q2kdMXZn17dS9X6l"
}
```
Bad location is a **400** at **0 credits**, and it is fast. `location=Atlantis` returned in **413 ms**, `req-xOeHKo1Bw5ZaRyJP`. The message names ISO / full name / numeric forms so the caller knows it is the location, not the keyword. Error taxonomy: [`/docs/errors`](/docs/errors).
```json
{
"success": false,
"error": {
"type": "INVALID_REQUEST",
"message": "Google Trends did not recognise one of the request parameters. `location` must be an ISO country code (\"KR\", \"US\"), the full country name as Google Trends spells it (\"South Korea\", \"United States\"), or a numeric location code (\"2410\"). Google Trends does not publish every country, so a location it has no data for is refused here as well. `category` must be a numeric Google Trends category code. Your credits have been refunded.",
"status": 400,
"doc_url": "https://www.socialcrawl.dev/docs/errors#invalid-request"
},
"credits_used": 0,
"request_id": "req-xOeHKo1Bw5ZaRyJP"
}
```
Cache hits are free and millisecond-fast. None of the billed four were hits (`cached: false` on every success). Set the client timeout **≥60s** (this harvest used 90). Credits stayed **5** across the speed change.
## How do you use a Google Trends API from Python?
You send header `x-api-key` and one GET. No SDK, no OAuth.
1. Get a key. Sign up; new accounts get 100 free credits. Send it as header `x-api-key` only — no OAuth, no query-string key. Auth notes: [`/docs/authentication`](/docs/authentication). That is **one API key** for both GETs above.
2. Copy the first `requests` block. Print `credits_used` and the `averages` array. Set timeout to 90.
3. Named timeframes: `past_hour`, `past_4_hours`, `past_day`, `past_7_days`, `past_30_days`, `past_90_days`, `past_12_months` (default, what the harvest used), `past_5_years`. No arbitrary date range. `past_hour` / `past_4_hours` are minute-level; `past_5_years` is weekly.
4. Next: [Google Trends endpoint docs](/docs/google_trends) for the field map, and [try the same call in the explorer](/platforms/google_trends). Responses sit on **the unified schema** — a `dev.socialcrawl` envelope, not a one-off Trends dump.
That docs page is the Google Trends API documentation for these two paths. This post is the live harvest, not a second copy of it.
## Frequently asked questions
### How long does a Google Trends API take?
Typical billed call is **~4.6s** now (was **~9s**), measured on **22 billed calls** after 2026-09-07. A four-call production check on 2026-09-08 landed 6.8s–19.7s depending on the term — that table is "this run", not the typical.
### Why did the Google Trends API timeout?
**273 of 19,459** calls over 30 days died after **~48s**. Slow tail on the 22 billed calls after the change was **~12s** worst-case. Timeouts are rare, not gone. Empty-interest 404s can still sit near 50s at **0 credits** — that is not a billed timeout. Use a client timeout ≥60s.
### Is there an official Google Trends API?
Yes. Google announced a Trends API **alpha** on **24 Jul 2025**, limited testers, apply-form access, not a drop-in public REST key. SocialCrawl is a public `x-api-key` GET returning website-style 0–100 series. For which-API / pricing, see [best Google Trends APIs 2026](/blog/best-google-trends-apis-2026).
### How do you call a Google Trends related queries API?
`GET /v1/google_trends/rising?keyword=…` returns `rising` and `top` for one keyword. Resource is `rising`. 5 credits on a billed miss. `keyword` is singular.
### Did credits or the response shape change?
No. Same params, same shape, same **5 credits**, same free 400s and free 404s.
### Do you need pytrends to call a Google Trends API from Python?
No. One Google Trends API Python GET with `x-api-key`. pytrends is an unofficial library (pandas, last release Apr 2023); it is not a dependency, and this is not a wrapper around it.
### Where is the Google Trends API documentation?
[Google Trends endpoint docs](/docs/google_trends) for params and field maps. [Try the same call in the explorer](/platforms/google_trends) against production. The field map lives there — this post does not copy it.
Rerun any harvest row with your own key. A cache miss on `explore` or `rising` is 5 credits. A 400 or empty-interest 404 is 0. That is the whole Google Trends API Python path: two GETs, same 5 credits, same shape as this harvest.