Google Trends Bulk Compare – Many Keywords, One Scale
Pricing
$3.00 / 1,000 keyword timeline with data
Google Trends Bulk Compare – Many Keywords, One Scale
Compare 5+ Google Trends keywords on one shared 0–100 scale (Google's UI caps at 5). Custom dates, countries & subregions, categories, optional rising queries. Flat CSV output. $0.003 per keyword with data; failed keywords are free, no start fee. No proxy or Google account needed.
Pricing
$3.00 / 1,000 keyword timeline with data
Rating
0.0
(0)
Developer
星賢 陳
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
8 hours ago
Last modified
Categories
Share
Google Trends Bulk Compare
Compare more than 5 Google Trends keywords on one scale. US$0.003 per keyword that returns data; failed or empty keywords are free, and there is no start fee.
Built after Google's Sept 2 redesign of Google Trends (this Actor was built in October 2026). In our own test on 2026-10-17 (Taipei time), 424 of 424 values were identical to Google Trends' own CSV export (265 values from a 5-term request plus 159 from a 3-term group, max difference 0), fetched from the same widgetdata endpoint the Trends UI's download button uses. You pay only for keywords that return data: failed or empty keywords are free, and there is no start fee.
What does Google Trends Bulk Compare do?
This Actor fetches Google Trends interest over time for a list of keywords and returns flat rows, one row per keyword per date, as a dataset and as OUTPUT.csv.
- Compare more than 5 keywords on one scale (
compareAcrossGroups). Google's own compare tool accepts only 5 terms. This Actor splits your list into groups of an anchor term plus up to 4 other keywords. Each group is then rescaled using the anchor (factor = sum(anchor in the reference group) / sum(anchor in this group)), and the overall maximum is set to 100. Rows are markedscale: "anchored-global"together with theirgroup. The factors, warnings and group membership are saved asRESCALE_INFO. - Or one scale per keyword (the default). Each keyword gets its own 0–100 scale, marked
scale: "per-keyword". - Custom date ranges (
customTimeRange), categories (category), and countries or subregions (geo, e.g.US,US-CA,TW-TPE; leave it empty for worldwide). - Related queries (optional): top and rising lists, with an
isBreakoutflag on each query. - Interest by region (optional).
- Change since last run (
trackChanges): when you run the same geo, time range, category and anchor again, thekeyword-summarydataset addspreviousLatestValue,deltaSinceLastRunandnewRisingSinceLastRun. - No browser, no proxy, no login. It uses plain HTTP JSON calls with a 30 s timeout. Only HTTP 408, 429, 5xx and network errors are retried, with exponential backoff plus jitter. The Actor honours
Retry-Afterand fetches a fresh cookie after the first 429. A 400 fails immediately. - Each keyword succeeds or fails on its own. Every row has a
status(ok,partial,errororskipped-charge-limit). The Actor never invents values. - Budget-aware. Once your run's maximum charge is reached, the remaining keywords are marked
skipped-charge-limit. They are not processed and not charged.
How to compare more than 5 keywords in Google Trends
- Put all your keywords in
keywords. - Set
compareAcrossGroups: trueand choose a steady, fairly popularanchorTerm(it is included in every group of 5). - Run the Actor. Every keyword comes back on one shared 0–100 scale (
scale: "anchored-global"), and the rescale factors and any low-anchor warning are saved inRESCALE_INFO.
Example input
{"keywords": ["chatgpt", "gemini", "claude ai"],"geo": "US","timeRange": "today 12-m"}
Add "compareAcrossGroups": true, "anchorTerm": "chatgpt" to put more than 5 keywords on one shared scale.
Google Trends data you can export
| Field | Description |
|---|---|
keyword | The search term |
date | Date of the data point (null for a failed keyword) |
value | Interest on the 0–100 scale (decimals after rescaling) |
isPartial | true if Google marks the period as incomplete |
scale | per-keyword or anchored-global |
group | Group index in compare mode |
geo, timeRange, category | The request settings |
status | ok, partial, error or skipped-charge-limit |
error | Error message for failed keywords |
How much does it cost to scrape Google Trends?
Pay per event: US$0.003 per keyword that returns data.
- Charged for keywords with
statusokorpartial.partialmeans the timeline came back but an optional section failed. - Keywords that end in
errororskipped-charge-limitare free. - There is no start fee.
- Platform usage is included in the price, so you don't pay a separate compute or proxy charge for this Actor.
This price is provisional until we measure the Actor's cost on the Apify platform, and it may change. Apify's rules on price-change notice apply.
Example: 30 keywords that all return data cost 30 × US$0.003 = US$0.09.
Use cases for SEO and content agencies
- Client keyword watchlists on one scale: compare 20–30 client keywords on one chart, instead of several separate 5-term charts that you can't compare.
- Weekly monitoring: schedule runs in Apify and turn on
trackChangesto see how much each keyword moved since the last run, plus any rising queries that are new. - Content ideas: pull rising and breakout related queries around your seed keywords.
- Local SEO: use subregions (e.g.
US-CA) and interest by region. - Seasonal planning: choose a custom date range and a category (e.g. 71 = Food & Drink).
- Reporting: the flat CSV (one row per keyword per date) goes straight into Sheets, Excel, Looker Studio or a BI tool.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
keywords | array of strings | (required) | No hard limit; tested up to 30 per run. Blank entries and duplicates are dropped. |
geo | string | "" (worldwide) | Country code (e.g. US) or subregion (e.g. US-CA, TW-TPE). |
timeRange | string | "today 12-m" | Google Trends time string, e.g. "now 7-d", "today 5-y". |
customTimeRange | string | — | "YYYY-MM-DD YYYY-MM-DD". Overrides timeRange when set. |
category | integer | 0 | Google Trends category ID (0 = all; e.g. 71 = Food & Drink). |
compareAcrossGroups | boolean | false | Puts all keywords on one shared 0–100 scale, using anchored groups. |
anchorTerm | string | first keyword | Included in every group. Pick a steady, fairly popular term: anchors that average below 5 amplify rounding error. |
includeRelatedQueries | boolean | false | Top + rising queries, with isBreakout. Adds 1 extra request per keyword. Results go to the related-queries dataset. |
includeInterestByRegion | boolean | false | Adds 1 extra request per keyword. Results go to the interest-by-region dataset. |
trackChanges | boolean | false | Reports change since the last run with the same geo, time range, category and anchor. |
stateStoreName | string | "trends-state" | Named key-value store used by trackChanges. |
delayBetweenKeywordsMs | integer | 8000 (min 2000) | Pause between keywords, or between groups in compare mode. |
delayBetweenRequestsMs | integer | 2500 (min 0) | Pause after every successful request. |
maxRetries | integer | 4 (0–8) | Applies only to 408/429/5xx/network errors. |
baseDelayMs | integer | 5000 | Base delay for backoff; it doubles on each retry, plus jitter. |
maxDelayMs | integer | 120000 | Upper limit on any backoff or Retry-After wait. |
hl | string | "en-US" | Language for Google Trends labels. |
tz | integer | -480 | Timezone offset in minutes (Google's convention: -480 = UTC+8). |
Example 1 – minimal (worldwide, past 12 months, one scale per keyword)
{ "keywords": ["content marketing", "seo audit", "link building"] }
Example 2 – US, 12 keywords compared on one scale, with weekly change tracking
{"keywords": ["seo", "content marketing", "link building", "keyword research", "seo audit","local seo", "technical seo", "backlinks", "google ads", "email marketing","social media marketing", "copywriting"],"geo": "US","compareAcrossGroups": true,"anchorTerm": "seo","includeRelatedQueries": true,"trackChanges": true}
Example 3 – subregion, category and custom date range (the input from our own test)
{"keywords": ["coffee"],"geo": "US-CA","category": 71,"customTimeRange": "2026-01-01 2026-06-30"}
Output
Default dataset / OUTPUT.csv. Flat rows, one per keyword per date. The rows below are real, taken from our 25-keyword local test (TW, past 12 months, anchor coffee, batch25-output.csv) and cut down to 3 rows:
keyword,date,value,isPartial,scale,group,geo,timeRange,category,status,errorcoffee,2025-10-12,4.5,false,anchored-global,0,TW,today 12-m,0,ok,ramen,2025-10-12,0.23,false,anchored-global,0,TW,today 12-m,0,ok,youtube,2025-10-12,81.25,false,anchored-global,4,TW,today 12-m,0,ok,
Real rows from the subregion/category test (sample-subregion-category.csv, cut down to 2 of 180 daily rows):
coffee,2026-01-01,86,false,per-keyword,,US-CA,2026-01-01 2026-06-30,71,ok,coffee,2026-01-02,77,false,per-keyword,,US-CA,2026-01-01 2026-06-30,71,ok,
If a keyword fails, it gets a single row with date: null, value: null, status: "error" and an error message.
keyword-summary dataset. One row per keyword. The row below comes from our local mock test (test-mock-suite.log, second of 2 runs). It does not contain Google data and is shown only to illustrate the structure:
{"keyword": "alpha", "status": "ok", "group": null, "scale": "per-keyword", "error": null,"latestValue": 100, "latestDate": "2025-10-23","rising": ["alpha rising 2", "alpha new"], "breakout": ["alpha new"],"previousRunAt": "2026-10-16T19:23:23.552Z", "previousLatestValue": 75,"deltaSinceLastRun": 25, "newRisingSinceLastRun": ["alpha rising 2"]}
related-queries dataset. One row per query. This is an example of the structure, not real output from the current version; the query values come from an earlier test run:
{"keyword": "bubble tea", "list": "rising", "query": "best bubble tea near me", "value": 109300,"formattedValue": "Breakout", "isBreakout": true, "geo": "TW", "timeRange": "today 12-m", "category": 0}
The key-value store also holds RUN_SUMMARY (counts, requests, 429s, charged events) and, in compare mode, RESCALE_INFO.
Accuracy and tested limits (measured in our own tests, 2026-10-17 Taipei time)
These numbers come from our own small tests. They are not a guarantee.
- Matches Google's own CSV export: we fetched the same request from the endpoint that Google Trends' download-CSV button uses. A 5-term request (TW, past 12 months) had 265/265 values identical (100%), max diff 0. A 3-term group had 159/159 identical, max diff 0. In total, 424/424 identical.
- One-scale accuracy: anchored rescaling (anchor = ramen, two groups) was compared with Google's direct 5-term request for coffee, bubble tea, hot pot, night market and ramen (TW, past 12 months). Over 265 points: MAE 0.110, max absolute error 0.65 on the 0–100 scale. The error comes from Google rounding values to integers. In this test the anchor's mean was only 4.04, so the low-anchor warning fired.
- Batches:
- Local: 25 keywords in anchored groups, 25/25 ok, 72.1 s, 13 requests, 0 non-200 responses.
- Apify platform (256 MB, no proxy): 8 keywords, per keyword, 8/8 ok, 106.7 s (platform 109.2 s), with 1 × 429, retried and recovered.
- Apify platform: 30 keywords in anchored groups, 30/30 ok, 105.7 s (platform 107.4 s), 17 requests, 0 non-200.
- Datacenter IPs on Apify were not blocked: there was 1 transient 429 in 36 platform requests.
- 429 handling (local mock, not Google): the Actor honoured
Retry-After, gave up cleanly after retries ran out, and did not retry a 400. - Not measured: more than 30 keywords per run, sustained or scheduled use, and Google's heavy throttling.
Google Trends API with Python, JavaScript and curl
Replace <YOUR_APIFY_TOKEN> with your token from Apify Console → Settings → API & Integrations.
curl (runs the Actor and returns the dataset items when it finishes):
curl -X POST "https://api.apify.com/v2/acts/raspberry_rondel~actor-google-trends/run-sync-get-dataset-items" \-H "Authorization: Bearer <YOUR_APIFY_TOKEN>" \-H "Content-Type: application/json" \-d '{"keywords": ["chatgpt", "gemini", "claude ai"], "geo": "US"}'
Python (pip install "apify-client>=3"):
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("raspberry_rondel/actor-google-trends").call(run_input={"keywords": ["chatgpt", "gemini", "claude ai"], "geo": "US"})for row in client.dataset(run.default_dataset_id).iterate_items():print(row["keyword"], row["date"], row["value"], row["status"])
JavaScript / Node.js (npm install apify-client):
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('raspberry_rondel/actor-google-trends').call({keywords: ['chatgpt', 'gemini', 'claude ai'],geo: 'US',});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
FAQ
Is there a Google Trends API? This Actor gives you API access to Google Trends interest-over-time data through the Apify API (see the examples above). It uses Google Trends' web endpoints, not an official Google API.
Why might values differ from what I see in the browser? Google Trends computes values from a sample of searches and rounds them to integers, and it refreshes recent data over time (the newest point is often marked partial). A request made at a different time can therefore return slightly different numbers, in the browser or here. In our test, values fetched at the same time matched Google's CSV export exactly (424/424).
How is Google's 5-term limit handled? Set compareAcrossGroups: true and choose a steady, popular anchorTerm. Keywords are split into groups of the anchor plus up to 4 others, and each group is rescaled through the anchor onto one 0–100 scale. In our test against Google's direct 5-term compare, the error was MAE 0.110 and max 0.65 over 265 points. If the anchor averages below 5, the run logs a low-anchor warning, because rounding error grows; factors and warnings are saved in RESCALE_INFO.
Does it match what I see on Google Trends? In our tests, values matched Google's CSV export exactly (424/424: 265/265 and 159/159). Values rescaled onto one scale differed from Google's direct 5-term compare by MAE 0.110 (max 0.65) over 265 points.
How many keywords per run? The code has no fixed cap. We have tested up to 30 per run.
Is it search volume? No. Google Trends gives relative interest on a 0–100 scale.
What if Google rate-limits me? The Actor retries 408/429/5xx errors with backoff and honours Retry-After. If a keyword still fails, it gets an error row, is not charged, and the run continues.
Can I cap my spend? Yes. Set a maximum total charge for the run; the remaining keywords are then skipped and not charged.
Do I need a proxy or a Google account? No.
Does it collect personal data? No. It only fetches aggregated Google Trends data.
Is it legal to scrape Google Trends? The Actor only fetches aggregated, public Google Trends data and no personal data. It is not legal advice: please check that your use fits the terms that apply to you.
Limitations
- Large lists: the code has no keyword limit, but our largest tested run was 30 keywords. Requests run one at a time with polite delays, so very large lists take longer and are more exposed to Google rate limits. For big lists, consider splitting them across runs.
- The one-scale values are estimates. Rescaling is accurate only to within rounding error (see the measured numbers above). The error grows when the anchor is not very popular (mean below 5) or when a group needs a large factor. If the anchor is all zeros in a group, that group's keywords get
errorand are not charged. If a group's dates don't line up with the reference group, that group also getserror. - Compare mode can fetch before skipping. A group is fetched before its members are charged, so when you hit your spending limit, part of a group can be fetched and then skipped. This uses requests but costs you nothing.
- Mock-tested only: change tracking has been tested only against a local mock. Related queries and interest by region have not yet been tested in real runs of the current version, including compare mode.
- Google Trends values are relative indexes (0–100), not search volumes. Google can return empty data for some terms.
- Related topics are not supported.
- The Actor depends on unofficial Google Trends web endpoints, which can change without notice.
Disclaimer
This Actor is an independent tool. It is not affiliated with, endorsed by, or sponsored by Google LLC. "Google" and "Google Trends" are trademarks of Google LLC. Please use the data in line with the applicable terms.