Google Trends Scraper avatar

Google Trends Scraper

Pricing

Pay per usage

Go to Apify Store
Google Trends Scraper

Google Trends Scraper

Scrape Google Trends interest over time, interest by region, related queries and topics, and trending-now — without the 429 failures. Successes are billed, failures are not, and every run finishes inside a wall-clock budget instead of hanging.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Gorav Agarwal

Gorav Agarwal

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a month ago

Last modified

Categories

Security

Limited permissions

Share

Scrape Google Trends at scale — interest over time, interest by region, related queries, related topics and trending-now — and actually get data back.

$2.50 per 1,000 dataset rows. No start fee. Failed requests are never billed.


The problem this Actor exists to solve

Google Trends scrapers fail, loudly and often. The most-used Google Trends Actor on this platform ran 22,254 times in 30 days and 26.1% of those runs did not produce a result — 643 failed, 5,157 timed out, 2,301 were aborted. Its open issues are titled "It never worked…", "Runs with infinite loop and no result", "Too much time and no output", "keep failing", "No search volumes returned".

That is not Google being unscrapeable. It is one specific, fixable mistake.

What actually goes wrong

A request to Google's /trends/api/explore endpoint from a client that has no NID cookie returns HTTP 429 Too Many Requests — on the first request, from a clean IP, with no prior traffic. It looks exactly like a rate limit, so scrapers treat it as one: they back off, retry, spin, and eventually time out having never made a single successful call.

It is not a rate limit. It is a cookie gate. Measured on a clean IP:

ClientResult
No cookies (control)429
Referer header, still no cookies429
NID cookie, no Referer200
Cold client per request, 20 requests20/20 → 429 (100%)
One warmed session, reused0/30 → 429 (0%)

Google hands out an NID cookie to anyone who asks. One cheap GET before the first API call is the entire difference between a 100% failure rate and a 0% failure rate. This Actor does that, keeps the session warm, and rotates it through Apify Proxy when Google's separate per-IP quota does eventually bite.


How it stays under the rate limit

  • Session warm-up. Every proxy session is issued an NID cookie before its first API call, via a 1.6 KB endpoint rather than the 681 KB Trends home page — 425× less bandwidth per rotation.
  • Proxy rotation on 429. A 429 means the identity is spent, so the Actor takes a new proxy session and a new cookie rather than sleeping on a dead one. Concurrent 429s coalesce into a single rotation instead of stampeding.
  • Exponential backoff with full jitter. sleep = uniform(0, min(cap, base · 2^attempt)) — the jitter variant that actually de-synchronises concurrent retries, rather than the naive delay · random() that leaves them clustered.
  • Adaptive concurrency. Sustained throttling halves the in-flight limit and paces requests apart; sustained success walks it back up. A fixed concurrency turns a soft quota into a hard wall.
  • A hard wall-clock budget. When the budget expires the run stops scheduling, pushes everything it already has, and finishes successfully with a status message saying it was partial. There is no code path that hangs.
  • A fallback that cannot be throttled. Google's per-IP quota covers the whole /trends/api/* surface — but not the trending endpoints. Measured on a quota-exhausted IP in the same second: explore → 429, widgetdata → 429, trending API → 200 with 284 trends. So when the keyword path is walled off, the Actor falls back to trending and still returns data. In a live test against a fully throttled IP with no proxy available, the run finished successfully with 285 rows instead of failing.
  • Every run publishes its own rate-limit report — observed 429 rate, rotations, recoveries, total backoff — to the RUN_SUMMARY record. The claim is measured, not asserted.

Success-only billing

You are charged for rows in the default dataset. That is it.

Anything that fails — a throttled request, a malformed keyword, a region Google has no data for — is written to a separate failures dataset with its HTTP status code and reason, and is not charged. If a run returns nothing, it costs nothing. This directly answers the "charged but returned zero results" complaint that dogs the incumbent.

At $2.50 / 1,000 rows with no start fee, a 53-row single-keyword pull costs about $0.13. Competing Actors charge a $20 start fee that dominates any small run, or a flat $3.00/1k. Nested output mode collapses a whole series into one row if you want the bill smaller still.


What you get

Data typeRowsFields
interest_over_timeone per keyword per bucketdate, formattedTime, value (0–100), isPartial
interest_by_regionone per keyword per regionregionName, regionCode, value, hasData
related_queriestop + rising, rankedquery, listType, rank, formattedValue, link
related_topicstop + rising, rankedtopicTitle, topicType, topicMid, rank
trending_nowhundreds per geosearchVolume, growthPercent, startedAt, relatedTerms, news articles

Every row carries keyword, geo, timeframe and fetchedAt, so a multi-keyword multi-region run stays unambiguous in a single flat table.

Features

  • Timeframes from the past hour to 2004-to-present, plus custom YYYY-MM-DD YYYY-MM-DD ranges. Resolution follows automatically — 8-minute buckets for the past day, hourly for the past week, weekly for a year.
  • Geo targeting by country (US, GB, IN), sub-region (US-CA, GB-ENG), or worldwide. Run one keyword set across many regions in a single job.
  • Multi-keyword comparison respecting Google's hard 5-term limit (a 6th term returns HTTP 400). Longer lists are split automatically. Because Google normalises interest within a comparison group, individual mode — one request and one 0–100 scale per keyword — is the default for batch lists, and compare mode tags each row with its comparisonGroup so the scales stay interpretable.
  • Category filter (Finance, Health, Sports, Travel and ~1,400 more) and search type (web, images, news, YouTube, Shopping).
  • Trending now from Google's current realtime feed — hundreds of trends per region with search volume, growth percentage, related terms and linked news, not the 10-item RSS cap.
  • No browser. Plain HTTP against Google's own JSON endpoints, so runs are fast and compute is cheap.

Input example

{
"keyword": "bitcoin",
"keywords": ["ethereum", "solana"],
"geo": "US",
"additionalGeos": ["GB"],
"timeframe": "today 12-m",
"dataTypes": ["interest_over_time", "interest_by_region", "related_queries"],
"comparisonMode": "compare",
"maxRunTimeSecs": 240
}

Output example

{
"position": 1,
"keyword": "bitcoin",
"geo": "US",
"timeframe": "today 12-m",
"dataType": "interest_over_time",
"date": "2026-09-13T00:00:00Z",
"formattedTime": "Sep 13 – 19, 2026",
"value": 28,
"isPartial": false,
"category": 0,
"searchType": "web",
"language": "en-US",
"fetchedAt": "2026-09-21T18:04:11Z"
}

Proxy and cost

Google enforces two separate limits, and they need different answers:

  1. The cookie gate. No NID cookie → 429 on the first request. Beaten by warming the session. Free, instant, no proxy involved.
  2. A per-IP quota, which only appears under sustained load. Measured: 100 requests through a single IP at concurrency 4 produced 63% 429s and zero rows, and that IP then refused even a correctly warmed single request for over four minutes. Backing off does not clear this in any useful time — only changing IP does.

That is why a 429 here rotates the proxy session rather than sleeping on a dead one, and why concurrency is reduced under pressure instead of held constant.

Datacenter proxy is sufficient and is the default. Rotation, not residential bandwidth, is what defeats this limit — the constraint is IP diversity, not IP reputation, and the datacenter pool supplies plenty of both. Residential is therefore not required.

For completeness, if you did switch to residential it would not be the cost problem: these are JSON endpoints rather than rendered pages, so the payload is roughly 0.2–0.4 KB per dataset row, and at $8/GB that is about $0.002–0.003 per 1,000 rows on top of the per-result price. Negligible either way — which is precisely why it is not worth paying for. The Actor also warms each session through a 1.6 KB endpoint instead of the 681 KB Trends home page, so rotating often stays cheap: a measured run that rotated five times spent 8.3 KB in total on warm-ups.

Notes on Google's own behaviour

  • Google returns no related-topics widget at all for multi-keyword comparisons. That is upstream behaviour, not a bug in this Actor.
  • An empty rankedList is a valid answer from Google for a low-volume keyword, not an error. This Actor does not bill it and does not report it as a failure — a distinction the incumbent's "No search volumes returned" issue suggests is not always made.
  • Interest values are relative, not absolute: 100 is the peak within the requested query, not a search count.

Use cases

SEO keyword research and seasonality, demand forecasting, brand-versus-competitor share of search, product launch timing, content calendars, market entry sizing by region, trading and crypto sentiment signals, academic and journalistic trend analysis.