Google Trends Bulk Extractor
Pricing
Pay per usage
Google Trends Bulk Extractor
Bulk-extract Google Trends data for one or many keywords. Returns interest over time, interest by region, related queries, and related topics in a single run. No rate-limit games required.
Apify Actor that bulk-extracts Google Trends data for one or many keywords in a single run. Returns interest over time, interest by region, related queries, and (optionally) related topics, structured per keyword batch.
Why this actor
Google Trends has no public API. The unofficial google-trends-api npm
package wraps Trends' internal AJAX endpoints and is the same approach most
free tools use. Running it through Apify means you don't have to manage the
proxy rotation, the manual URL-tweaking, or the slow per-keyword web UI —
give it a keyword list, get back structured data.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
keywords | string[] | required | 1-5 keywords per request (Trends limit). |
geo | string | "" | Two-letter country code, empty = worldwide. |
timeRange | string | "today 12-m" | Trends timeframe string (e.g. today 5-y, now 7-d) or custom range. |
category | integer | 0 | Trends category ID; 0 = all. |
includeInterestOverTime | boolean | true | |
includeInterestByRegion | boolean | true | |
includeRelatedQueries | boolean | true | |
includeRelatedTopics | boolean | false | |
maxRelatedItems | integer | 25 | Cap returned related queries/topics per rank. |
If you give more than 5 keywords, the Actor automatically batches them into groups of 5 (each batch = one result item).
Output
Each dataset item represents one batch:
{"keywords": ["electric scooter", "e-bike"],"geo": "US","timeframe": "today 3-m","category": 0,"fetchedAt": "2026-07-04T20:30:00.000Z","interestOverTime": { "default": { "timelineData": [...] } },"interestByRegion": { "default": { "geoMapData": [...] } },"relatedQueries": {"top": [ { "query": "...", "value": 100, "link": "..." }, ... ],"rising": [ { "query": "...", "value": 5000, "link": "..." }, ... ],"sourceShape": "rankedList","default": { ...raw upstream payload... }}}
relatedQueries and relatedTopics use a normalised { top, rising, sourceShape, default }
shape. The sourceShape field tells you which upstream shape the response was
detected as — "rankedList" is the current google-trends-api shape (which
itself is normalised through JSON round-tripping); the fallback "perKeyword"
shape (older library versions / blog examples) is also handled.
If a section fails (e.g. Trends rate-limits the request or the response isn't
JSON), the section is replaced by an error key like
interestOverTimeError: "..." so a partial result is still useful.
Local test
npm installnpm test # structural only - no network calls, verifies shape handlingnpm run test:live # also hits live Google Trends; rate-limits are tolerated
The structural test asserts that trimRelated correctly handles both known
response shapes the google-trends-api library has shipped, that
batchKeywords enforces the 5-keyword-per-batch limit, and that run()
wires input/output together. The live test additionally exercises the full
upstream round-trip — if Google is currently rate-limiting this IP, every
section will come back with *Error keys but the test still passes (the
graceful-degradation path is what we want to verify).
Deploy
This is a build-only repo. Deploy and publish to the Apify Store is done by Sky manually.
Pricing model
PAY_PER_EVENT ~$0.002/keyword-batch returned.