Bulk Google Trends Scraper | Compare, Export & Resume
Pricing
$10.00 / 1,000 research request with usable data
Bulk Google Trends Scraper | Compare, Export & Resume
Bulk Google Trends research across keywords, countries and dates. Get timeline, regions, related queries and topics. Preserve comparison scope, inspect every request, resume incomplete batches, and download tidy CSV/JSON plus an n8n workflow.
Run a keyword × country × date research matrix in one Actor. Keep comparison groups together, account for every request, resume incomplete batches, and export tidy trend data.
Built for SEO research, content planning, ecommerce research, and recurring analyst workflows. Collect interest over time, regional interest, related queries, and related topics without constructing a separate run for every geography and time window.
$0.01 per usable research request — $10 per 1,000 request bundles. All selected surfaces and up to five keywords in one comparison group are included. No start fee or per-row fee.
Why use this Actor?
- One input for the whole research matrix. Supply keywords, countries, and time windows. Or use explicit request objects for a mixed research brief.
- Comparison groups keep their context. Request several keywords together when you need a relative comparison. Every export carries its request and comparison identity.
- Know what happened to every request. The manifest distinguishes usable data, valid no-data, incomplete extraction, and failed requests. A blocked response is not reported as zero interest.
- Resume the work that needs attention. Reuse completed requests and retry missing or failed surfaces from a prior run. Download an exact resume input instead of assembling retries by hand.
- Tidy exports are included. Separate CSV and JSON files for timeline, regions, related queries, and related topics preserve request context. The default dataset holds a complete bundle per request for API workflows.
- Predictable billing unit. One $0.01
research-requestevent covers a request with usable output across its selected surfaces. There is no charge for each daily point or related-query row. Confirmed no-data and wholly failed requests have no research-request charge.
These are concrete workflow features, not a claim that this Actor is faster or more accurate than every alternative. It is particularly useful when your task spans multiple countries or periods and you need to reconcile incomplete batches. It does not provide the Trending Now news feed.
Try a small research request
Paste this into the Actor input and run it:
{"keywords": ["running shoes"],"geos": ["US"],"timeRanges": ["today 3-m"],"surfaces": ["timeline", "regions", "relatedQueries", "relatedTopics"]}
Open the run's Output to see request bundles. Open its key-value store to download the manifest and separate research files. Begin with a small input so you can inspect the returned fields and availability for your use case.
Bulk research across countries and dates
{"keywords": ["running shoes", "trail running"],"geos": ["US", "GB", "DE"],"timeRanges": ["today 3-m", "today 12-m"],"surfaces": ["timeline", "relatedQueries"],"compareKeywords": false}
This expands to 12 research requests: 2 keywords × 3 countries × 2 windows. Each keyword is requested independently. Identical canonical requests are collapsed, so duplicate input rows do not create duplicate logical research work.
Use "" as a geography for worldwide interest. Country codes such as US, GB, and DE are passed as research geography, independently of the proxy's location. Time windows may be relative, such as today 3-m, or fixed, such as 2026-01-01 2026-06-30. Google controls data availability and granularity.
Compare brands or topics together
{"keywords": ["Nike", "Adidas", "New Balance"],"geos": ["US", "GB"],"timeRanges": ["today 12-m"],"surfaces": ["timeline", "regions"],"compareKeywords": true}
This creates two requests, one group in each country. The Actor preserves keyword order, per-keyword values, source parameters, and comparisonGroupId. Compare values within the same fetched response and surface; a matching comparisonGroupId identifies the query scope, not a guarantee of calibration across fetch times. The supported group size is capped by the input schema; it is not expanded into independently normalized groups behind your back.
Google Trends scores are relative interest, not absolute search volume. A value of 100 is a peak within the source's normalization context. A score of 50 in one independent request is not necessarily comparable to 50 in another country, date window, keyword group, or surface. Related “rising” percentages also have a different meaning from timeline interest scores. Keep the source context when analyzing the exports. Google's explanation
Rows include normalizationScope, which identifies the specific fetch and source widget, and normalizationMethod, which explains the metric. For a regional comparison, valueUnit: "percent_of_compared_terms" identifies each term's share among the compared terms within that region. It is different from a single-keyword map's relative-interest index.
Google sometimes omits related-query or topic widgets from a comparison page. The Actor can fetch those related surfaces through individual-keyword pages. Those rows retain their own sourceUrl and separate normalization scope; they are not added to the shared timeline scale.
The Actor does not calibrate arbitrary batches to a common scale. Google Trends uses sampled data, so repeated requests may differ. Topic IDs accepted by Google Trends can be supplied as keywords; a plain keyword string remains a search term and is not automatically resolved into a topic.
Explicit requests for a mixed research brief
Use requests instead of the matrix fields when individual rows need different settings:
{"requests": [{"label": "US footwear comparison, fixed period","keywords": ["Nike", "Adidas"],"geo": "US","time": "2026-01-01 2026-06-30","surfaces": ["timeline", "regions"]},{"label": "German running research","keywords": ["Laufschuhe"],"geo": "DE","time": "today 3-m","surfaces": ["timeline", "relatedQueries", "relatedTopics"]}]}
Multiple keywords inside one explicit request form one comparison group. Do not combine requests with top-level keywords or compareKeywords. A single global geography or time window may provide a default for explicit requests. If a global list has multiple entries, each request must specify that dimension itself. The explicit list never expands a matrix. Check the input schema for category, search property, execution limits, and proxy options.
What you get
| Output | Contents |
|---|---|
| Default dataset | One result bundle per canonical research request: input context, overall status, and surfaceResults containing tidy rows and individual outcomes |
MANIFEST.json | Every canonical request, including any work still pending, with status and provenance |
TIMELINE.csv / TIMELINE.json | Interest-over-time rows with keyword, source timestamp and partial-period information |
REGIONS.csv / REGIONS.json | Geographic interest with source region names/codes and keyword context |
RELATED-QUERIES.csv / RELATED-QUERIES.json | Top/rising related search rows with source values and display values |
RELATED-TOPICS.csv / RELATED-TOPICS.json | Top/rising topic rows with source topic identifiers and labels when available |
RESUME-INPUT.json | An input for resuming this research batch |
N8N-WORKFLOW.json / N8N-SETUP.md | Importable automation template and setup instructions |
OUTPUT | Run summary, research-file links, and the checkpoint storage ID used for resume |
Each request bundle contains requestId, comparisonGroupId, keywords, geo, time, category, property, status, and surfaceResults. Each surface result records surface, status, rows, sourceUrl, fetchedAt, and an error where applicable. Tidy rows keep request provenance so multiple runs can be joined without losing their origin.
The manifest and generated exports are the authoritative view of logical requests. For consumers reading raw dataset appends, use requestId as the stable key: an interrupted storage response can make an append's acknowledgment uncertain.
Example exported row
This excerpt from TIMELINE.json was collected on September 22, 2026 for coffee, US, today 3-m. It shows one observed row, with some fields omitted for readability. Future samples can differ.
{"requestId": "trends_48f1c8ccfc7f0730cf65134f","comparisonGroupId": "scope_6c45b22491ace6fc3ef8d8a8","geo": "US","timeRange": "today 3-m","requestStatus": "ok","surfaceStatus": "ok","fetchedAt": "2026-09-22T10:51:39.394Z","keyword": "coffee","interest": 68,"date": "2026-06-22T00:00:00.000Z","hasData": true,"isPartial": false,"normalizationScope": "113c0757-698a-47ee-aca5-12770ba3030c:scope_6c45b22491ace6fc3ef8d8a8:timeline:TIMESERIES","valueUnit": "relative_interest_index"}
The complete request returned 93 timeline rows, 51 regional rows, 50 related-query rows, and a valid no-data outcome for related topics. The request manifest makes that last outcome visible instead of silently omitting the requested surface.
Read the status before using the numbers
A request may return useful timeline data while a related-query request fails. That is partial extraction, and the successful data remains available. A valid empty source response is recorded as no-data. A source access failure, an unexpected response, or unavailable widget is reported separately; it is never replaced with invented zeros.
Zero-valued source observations can be valid data. They do not prove no searches occurred. A partial final time interval from Google is also different from a failed extraction surface; preserve both signals when analyzing a time series.
For sparse terms, Google may return regional zero placeholders explicitly marked hasData: false. The Actor retains those source rows for transparency, labels the outcome no_data, and does not charge for them alone. rowCount counts retained rows, so it is not a useful-data or billing count.
An Apify run status of SUCCEEDED means the program completed. Consult the manifest for research completeness, especially when a runtime or charge limit stopped new work. A forced kill can leave an in-progress run's final export files unfinished; completed durable request records are retained for resume.
Resume an interrupted or partial batch
Use the downloaded RESUME-INPUT.json, or start with:
{"resumeFromRunId": "YOUR_PREVIOUS_RUN_ID"}
The Actor imports the original plan, reuses finished request data, and retries missing or failed surfaces. Confirmed no-data and source-unsupported surfaces are treated as completed outcomes. Resume requires a checkpoint from this Actor under the same Apify account. Wait for a prior run to stop before resuming it.
Each run saves a dedicated checkpoint separately from the files in its default output store. OUTPUT.checkpointStoreId identifies it, and the downloaded RESUME-INPUT.json selects it through resumeKeyValueStoreId. Use that generated input rather than substituting the default output store ID. The input's storage selector grants access to the selected checkpoint while keeping the Actor's normal limited permissions.
The checkpoint must still exist when you resume. It follows Apify storage retention and can expire; resume is not a permanent archive. Save finished exports separately when you need to retain the research itself.
A request already billed in the inherited checkpoint is not charged again for resumed surface work. This depends on the same trusted checkpoint: launching a new independent input or changing the request context is fresh research. Resume is designed to finish an existing batch, not refresh its historical observations. To collect today's version of a relative window, start a new run from the original research input without a resume field.
Verified in cloud runs: a four-request batch stopped after one priced event under a $0.01 cap. Its resume kept the first request's 104 saved rows, completed the three deferred requests, and recorded only three new events. Resuming the finished 322-row batch again reused all four requests and recorded zero new events. This checks the resume and billing behavior; it is not a guarantee of future Google availability.
Pricing and cost control
The launch price is $0.01 per usable research request, or $10 per 1,000 request bundles. The unit is one canonical keyword/comparison-group + geography + time-window + category + property request with usable output, covering all its selected surfaces. A comparison group may contain up to five distinct keywords. Selecting more daily points does not multiply the event count. The Actor's Pricing tab is the source for the current rate.
- A complete request with usable rows: $0.01.
- A partial request with usable rows from at least one selected surface: $0.01.
- Confirmed no-data or no usable output: $0.
- Successfully inherited data on resume: no repeat request fee.
The Actor does not define a custom start event. The pay-per-event price includes Apify platform usage and the configured Apify proxy; a custom proxy provider remains subject to your arrangement with that provider. For a matrix of 12 requests, at most 12 request events are needed, regardless of how many timeline or related rows Google returns. maxRequests rejects an oversized input before research starts; its default is 100, with a maximum of 500. The run's maximum charge setting and maxRunSeconds bound execution. If an execution limit is reached, inspect the manifest and resume input for work that remains.
The 12-request matrix above costs at most $0.12 in Actor fees. The two-country comparison example costs at most $0.02, including all requested surfaces for each country. A request that returns only confirmed no-data reduces that total.
API and n8n automation
Run the Actor through the Apify API using its handle, cauldo/google-trends-bulk-research. Pass the same JSON body shown above. Send your Apify API token in the Authorization: Bearer … header. For longer batches, start a run, poll the run ID until it reaches a terminal status, then download its dataset and OUTPUT record. Apify run API
Download N8N-WORKFLOW.json and N8N-SETUP.md from your run's key-value store or the links in OUTPUT. The n8n template starts a bounded research run, waits for completion, validates the run's terminal status, and retrieves its summary and request bundles. Configure an HTTP authentication credential and edit the research input. No account token is embedded in the template.
For scheduled research, save an Apify task or connect a schedule trigger in n8n. Preserve the run and request IDs in your downstream table, and check partial or failed surface outcomes before updating a dashboard.
Scope and support
This is an independent Actor using Google Trends' public web data. It does not require a Google login or access to Google's limited-access official Trends API. Availability can change with Google's responses, filtering and rate limits. The official API is a separate product with different scaling capabilities. Google Trends API alpha
Related-topic availability: launch checks returned valid empty topic lists for tested popular terms and a valid topic ID. A bounded check of another Google Trends Actor returned empty topic lists too. The relatedTopics surface is collected when Google supplies it; no_data can reflect current source availability and does not prove that a term has no related topics. Start with a small test if this surface is essential to your workflow.
For an extraction issue, open the Actor's Issues tab with the run ID, affected request ID, expected surface, and a Google Trends source link. Do not include your API token. Reproducible small inputs make problems much easier to investigate.