Google Trends Scraper & Keyword Monitor
Pricing
from $9.00 / 1,000 keywords
Google Trends Scraper & Keyword Monitor
Enter keywords, get Google Trends interest over time, related queries and interest by region as flat rows, plus one summary row per keyword: latest value, change vs previous period, change since your last run, spike flag. No browser. Pay per keyword that returns data; no start fee.
Pricing
from $9.00 / 1,000 keywords
Rating
0.0
(0)
Developer
SUNGHWAN CHO
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
15 days ago
Last modified
Categories
Share
Enter a list of keywords and get Google Trends data as flat rows: interest over time, top and rising related queries, and interest by region, plus one summary row per keyword with the latest value, the change versus the previous period, the peak, and the change and spike flag since your last run.
This Google Trends scraper is built for people who look up the same keywords again and again: SEO and content teams, e-commerce sourcing, market research, trend reports in n8n or Make, and AI agents. It works with plain HTTP requests, so there is no browser to wait for, and you pay per keyword instead of per row.
What you get
For every keyword and country (geo):
- A summary row (
keywordSummary, free): latest value, average of the last 7 and 30 days, change versus the previous period in percent, peak value and time, change since your last run, aspikeflag, the top rising related query, and a clearstatus. - Interest over time (
timelinePoint): one row per point in time, from per-minute data for the past hour to monthly data back to 2004. - Related queries (
relatedQuery): up to 25 top and 25 rising searches, with growth in percent, aisBreakoutflag and a flag for queries that are new since your last run. - Interest by region (
regionInterest): one row per country, state / province or metro area. - A run summary (
RUN_SUMMARY, free): status, stop reason and charge flag of every keyword.
All rows are flat, with English field names. Numbers are numbers, missing values are null, times are ISO 8601 in UTC.
Why this Google Trends scraper
- No browser. The Actor calls the same JSON endpoints the Google Trends website uses and runs in 256 MB of memory. In our tests a run with one keyword took 16 to 24 seconds and a run with 60 keywords took about 3 minutes 20 seconds.
- Per-keyword pricing, no start fee. One event per keyword, whatever you include. A time series with 270 points costs the same as one with 30. A run with a single keyword costs one keyword.
- Failed keywords are free. You pay only for a keyword that completed and has data. Failed, partial, skipped and no-data keywords are stored with their status but not charged.
- Change since your last run. The Actor remembers the last value of every keyword and reports what changed, on the same scale, with a spike flag. You do not have to store and compare the results yourself.
- Handles HTTP 429 for you. Every keyword runs on a fresh proxy session. A rate-limited request is retried alone, and a keyword that still fails is tried once more at the end of the run.
- Honest status. Every keyword gets a
statusand astopReason. If Google changes its response format, the Actor reportsunexpectedResponseinstead of storing broken data.
Use cases
- SEO and content planning - track your target keywords every day or week, and collect rising related queries as topic ideas before they peak.
- E-commerce and product sourcing - watch demand for product keywords by country and catch spikes early (
spike: true). - Brand and competitor monitoring - compare up to 5 brands on one scale and follow how the gap moves.
- Market research by country - run the same keywords in
US,GB,DE,KR,JPand see where interest is highest, down to state or province. - Trend reports and alerts - schedule a run, then send the summary rows to Google Sheets, Slack or email with n8n, Make or Zapier.
- AI agents - an agent that needs "is this keyword rising?" gets one small summary row per keyword instead of hundreds of data points.
- A pytrends replacement - keep your keyword lists and time range strings and move the rate-limit handling out of your code.
Quick start
- Open the Actor, enter one or more keywords, and pick a country and a time range.
- Click Start. Results appear in the Output tab while the run is still going.
- Export the dataset as JSON, CSV or Excel, or read it through the Apify API. Add a schedule to repeat the run every day or week.
Input
Only keywords is required.
| Field | Default | What it does |
|---|---|---|
keywords | required | Search terms in any language, one per item, up to 100 characters each. Duplicates are removed. |
geo | worldwide | worldwide or a two-letter country code (US, GB, DE, KR, JP, TW, ...). Several countries: "US,KR,JP" - every keyword is looked up in every country. A region code such as US-CA also works. |
timeRange | today 3-m | now 1-H, now 4-H, now 1-d, now 7-d, today 1-m, today 3-m, today 12-m, today 5-y, all. |
include | ["interestOverTime"] | Which detail rows to output: interestOverTime, relatedQueries, interestByRegion. The summary row is always output. [] = summary rows only. |
compareMode | false | false: each keyword has its own 0-100 scale. true: keywords are sent in groups of up to 5 (in list order) and share one scale. See Scales. |
customTimeRange | - | "YYYY-MM-DD YYYY-MM-DD" (start end). Overrides timeRange. |
category | "0" | Google Trends top-level category ID, for example "7" Finance, "18" Shopping, "71" Food & Drink. The full list is in the input form. |
historyStoreName | google-trends-monitor-history | Named key-value store that remembers the last value of each keyword. Set to "" to turn off "change since last run". |
spikeThresholdPct | 50 | spike becomes true when the latest value is this many percent (and at least 10 points) above the baseline. |
proxyMode | auto | auto (datacenter first, residential for retries and when datacenter IPs are rate-limited), datacenter, residential. |
maxRequests | automatic | Upper limit of HTTP requests in the run, retries included. |
The resolution follows the time range:
timeRange | Meaning | One point per | Points per keyword |
|---|---|---|---|
now 1-H | Past hour | minute | about 60 |
now 4-H | Past 4 hours | minute | about 240 |
now 1-d | Past day | 8 minutes | about 180 |
now 7-d | Past 7 days | hour | about 169 |
today 1-m | Past 30 days | day | about 31 |
today 3-m | Past 90 days | day | about 93 |
today 12-m | Past 12 months | week | about 53 |
today 5-y | Past 5 years | week | about 262 |
all | 2004 to now | month | about 274 |
Example 1: daily keyword monitoring
Schedule this once a day. From the second run on, every summary row shows the change since the last run.
{"keywords": ["bitcoin", "nvidia", "다이소"],"geo": "US","timeRange": "today 3-m"}
Keywords can be in any language. 다이소 is Daiso, a Korean retail chain.
Example 2: rising related queries for content ideas
{"keywords": ["protein powder", "creatine"],"geo": "US","timeRange": "today 1-m","include": ["relatedQueries"]}
Example 3: compare brands on one scale
Up to 5 keywords per group share one 0-100 scale. include: [] returns only the summary rows.
{"keywords": ["chatgpt", "gemini", "claude"],"geo": "US","timeRange": "today 12-m","compareMode": true,"include": []}
Example 4: several countries with regional breakdown
Every keyword is looked up (and billed) once per country: 2 keywords x 3 countries = 6 lookups.
{"keywords": ["k-beauty", "올리브영"],"geo": "US,JP,KR","timeRange": "today 12-m","category": "44","include": ["interestOverTime", "interestByRegion"]}
올리브영 is Olive Young, a Korean beauty retailer. Category "44" is Beauty & Fitness.
Output
One dataset, flat rows. The type field tells the rows apart. Every row has keyword, geo, timeRange, category, url (the same query on the Google Trends website), scrapedAt, source: "google_trends" and schemaVersion.
All examples below are copied from real runs on the Apify platform (2026-10-01 UTC).
keywordSummary - one per keyword and geo (free)
This row is from the second of two real runs, six minutes apart, with the input {"keywords": ["bitcoin", "nvidia"], "geo": "US", "timeRange": "now 1-d", "include": ["relatedQueries"]}. Because it is a second run, the "since last run" fields are filled.
{"type": "keywordSummary","keyword": "bitcoin","geo": "US","timeRange": "now 1-d","category": 0,"scale": "single","comparedWith": null,"status": "completed","stopReason": "completed","errorMessage": null,"charged": true,"hasData": true,"pointCount": 181,"resolution": "minute","latestValue": 39,"latestTime": "2026-10-01T18:32:00.000Z","partialValue": 41,"partialTime": "2026-10-01T18:40:00.000Z","avg7Days": null,"avg30Days": null,"comparePeriod": "4h","changeVsPreviousPeriodPct": -16.45,"peakValue": 100,"peakTime": "2026-10-01T09:44:00.000Z","previousRunAt": "2026-10-01T18:37:23.827Z","previousLatestValue": 42,"valueAtPreviousRun": 40,"changeSinceLastRun": -1,"changeSinceLastRunPct": -2.5,"spike": false,"spikeBasis": "previousRun","relatedTopCount": 25,"relatedRisingCount": 9,"breakoutQueryCount": 2,"topRisingQuery": "michael saylor bitcoin market growth","topRisingQueryValue": 14250,"newRisingQueryCount": 2,"regionCount": null,"topRegionName": null,"interestOverTimeStatus": "ok","relatedQueriesStatus": "ok","interestByRegionStatus": "notRequested","requests": 6,"retries": 1,"url": "https://trends.google.com/trends/explore?date=now%201-d&geo=US&q=bitcoin&hl=en-US","scrapedAt": "2026-10-01T18:43:55.143Z","source": "google_trends","schemaVersion": 1}
latestValueis the latest complete point. Google's unfinished last point (isPartial) is reported separately aspartialValueand is never used for averages, changes or the peak.changeVsPreviousPeriodPctcompares the mean of the last period with the period before it.comparePeriodsays how long that period is:15mfor the past hour,1hfor 4 hours,4hfor the past day,1dfor 7 days,7dfor 1 to 3 months,28dfor 12 months,91dfor 5 years,365dforall.avg7Daysandavg30Daysarenullwhen the series is shorter than 7 or 30 days.status:completed(everything you asked for was saved),partial(the time series was saved, another part failed),failed,budgetLimited(your maximum charge,maxRequestsor the run timeout was reached),notStarted.stopReason:completed,noData,rateLimited,invalidRequest,unexpectedResponse,httpError,networkError,chargeLimitReached,requestBudget,timeLimit,blocked,datasetWriteFailed.chargedistrueonly whenstatusiscompletedandhasDataistrue.
In compare mode the summary row also says what the keyword was compared with. From a real run of Example 3 (fields shortened):
[{"type": "keywordSummary", "keyword": "chatgpt", "geo": "US", "timeRange": "today 12-m", "scale": "compared", "comparedWith": "gemini | claude", "status": "completed", "charged": true, "latestValue": 73, "changeVsPreviousPeriodPct": 9.12, "peakValue": 100, "peakTime": "2025-11-02T00:00:00.000Z"},{"type": "keywordSummary", "keyword": "gemini", "geo": "US", "timeRange": "today 12-m", "scale": "compared", "comparedWith": "chatgpt | claude", "status": "completed", "charged": true, "latestValue": 32, "changeVsPreviousPeriodPct": 20.56, "peakValue": 35, "peakTime": "2026-04-12T00:00:00.000Z"},{"type": "keywordSummary", "keyword": "claude", "geo": "US", "timeRange": "today 12-m", "scale": "compared", "comparedWith": "chatgpt | gemini", "status": "completed", "charged": true, "latestValue": 21, "changeVsPreviousPeriodPct": 0, "peakValue": 32, "peakTime": "2026-03-01T00:00:00.000Z"}]
A keyword without enough search volume completes with stopReason: "noData" and is not charged. From a real run with a random string as the keyword (fields shortened):
{"type": "keywordSummary","keyword": "zqxjvkwpl mnbtrcyh 83615 qqfdz","geo": "TW","timeRange": "today 1-m","status": "completed","stopReason": "noData","errorMessage": null,"charged": false,"hasData": false,"pointCount": 0,"latestValue": null,"interestOverTimeStatus": "ok","requests": 5,"retries": 1}
timelinePoint - one per point in time (include: interestOverTime)
[{"type": "timelinePoint", "keyword": "다이소", "geo": "KR", "timeRange": "today 3-m", "category": 0, "scale": "single", "comparedWith": null, "time": "2026-09-30T00:00:00.000Z", "value": 21, "hasData": true, "isPartial": false, "url": "https://trends.google.com/trends/explore?date=today%203-m&geo=KR&q=%EB%8B%A4%EC%9D%B4%EC%86%8C&hl=en-US", "scrapedAt": "2026-10-01T18:38:29.972Z", "source": "google_trends", "schemaVersion": 1},{"type": "timelinePoint", "keyword": "다이소", "geo": "KR", "timeRange": "today 3-m", "category": 0, "scale": "single", "comparedWith": null, "time": "2026-10-01T00:00:00.000Z", "value": 21, "hasData": true, "isPartial": true, "url": "https://trends.google.com/trends/explore?date=today%203-m&geo=KR&q=%EB%8B%A4%EC%9D%B4%EC%86%8C&hl=en-US", "scrapedAt": "2026-10-01T18:38:29.972Z", "source": "google_trends", "schemaVersion": 1}]
Times are UTC. The last point of a series is usually unfinished (isPartial: true). hasData: false marks points where Google has not enough data; their value is 0, exactly as on Google's chart.
relatedQuery - top and rising related searches (include: relatedQueries)
[{"type": "relatedQuery", "keyword": "bitcoin", "geo": "US", "timeRange": "now 1-d", "category": 0, "kind": "top", "rank": 1, "query": "bitcoin price", "value": 100, "formattedValue": "100", "isBreakout": false, "isNewSinceLastRun": null, "queryUrl": "https://trends.google.com/trends/explore?q=bitcoin+price&date=now+1-d&geo=US", "url": "https://trends.google.com/trends/explore?date=now%201-d&geo=US&q=bitcoin&hl=en-US", "scrapedAt": "2026-10-01T18:43:55.143Z", "source": "google_trends", "schemaVersion": 1},{"type": "relatedQuery", "keyword": "bitcoin", "geo": "US", "timeRange": "now 1-d", "category": 0, "kind": "rising", "rank": 1, "query": "michael saylor bitcoin market growth", "value": 14250, "formattedValue": "Breakout", "isBreakout": true, "isNewSinceLastRun": false, "queryUrl": "https://trends.google.com/trends/explore?q=michael+saylor+bitcoin+market+growth&date=now+1-d&geo=US", "url": "https://trends.google.com/trends/explore?date=now%201-d&geo=US&q=bitcoin&hl=en-US", "scrapedAt": "2026-10-01T18:43:55.143Z", "source": "google_trends", "schemaVersion": 1},{"type": "relatedQuery", "keyword": "bitcoin", "geo": "US", "timeRange": "now 1-d", "category": 0, "kind": "rising", "rank": 5, "query": "goog stock", "value": 100, "formattedValue": "+100%", "isBreakout": false, "isNewSinceLastRun": true, "queryUrl": "https://trends.google.com/trends/explore?q=goog+stock&date=now+1-d&geo=US", "url": "https://trends.google.com/trends/explore?date=now%201-d&geo=US&q=bitcoin&hl=en-US", "scrapedAt": "2026-10-01T18:43:55.143Z", "source": "google_trends", "schemaVersion": 1}]
Up to 25 top and 25 rising queries per keyword. For top, value is 0-100 relative to the most searched related query. For rising, value is the growth in percent; when Google shows "Breakout" instead of a percentage, isBreakout is true. isNewSinceLastRun is null on the first run and for top queries.
regionInterest - one per country / region with data (include: interestByRegion)
{"type": "regionInterest","keyword": "다이소","geo": "KR","timeRange": "today 3-m","category": 0,"rank": 1,"regionCode": "KR-27","regionName": "Daegu","value": 100,"url": "https://trends.google.com/trends/explore?date=today%203-m&geo=KR&q=%EB%8B%A4%EC%9D%B4%EC%86%8C&hl=en-US","scrapedAt": "2026-10-01T18:38:29.972Z","source": "google_trends","schemaVersion": 1}
Countries for worldwide, states / provinces for a country, metro areas for a region code. Regions without enough data are left out. Region names are in English.
Run summary (free)
The key-value store record RUN_SUMMARY lists every keyword with status, stopReason, charged, requests and retries, plus totals, rows stored per type, proxy fallbacks and whether your charge limit was reached. From a real run with two keywords, one of them without data (shortened):
{"source": "google_trends","schemaVersion": 1,"runStatus": "succeeded","stopReason": "completed","totals": {"keywords": 2, "completed": 2, "partial": 0, "failed": 0, "budgetLimited": 0, "notStarted": 0, "noData": 1, "charged": 1},"rowsStored": {"timelinePoint": 31, "relatedQuery": 0, "regionInterest": 0, "keywordSummary": 2},"charging": {"eventName": "keyword", "chargedEvents": 1, "limitReached": false, "isPayPerEvent": false, "maxTotalChargeUsd": null},"proxy": {"mode": "auto", "residentialFallbacks": 0},"keywords": [{"keyword": "zqxjvkwpl mnbtrcyh 83615 qqfdz", "geo": "TW", "status": "completed", "stopReason": "noData", "charged": false, "requests": 5, "retries": 1, "baseline": "promoted", "errorMessage": null},{"keyword": "nvidia", "geo": "TW", "status": "completed", "stopReason": "completed", "charged": true, "requests": 5, "retries": 1, "baseline": "promoted", "errorMessage": null}]}
The run fails only when no keyword could be saved. If some keywords fail, the others are kept; read RUN_SUMMARY and re-run only the failed ones.
Dataset views
The Output tab has five table views: All rows, Keyword summaries, Interest over time, Related queries and Interest by region. Views choose columns, not rows - to get only one row type from the API, filter on type in your own code, or request only what you need with include.
Change since your last run
With historyStoreName set (the default), the Actor remembers the latest complete point of every keyword + geo + time range + category. On the next run the summary row shows:
previousRunAt,previousLatestValue- what the last run saw.valueAtPreviousRun- the value in today's series at the time of the last run's latest point. Because Google rescales every response, this is the number to compare with;changeSinceLastRunandchangeSinceLastRunPctuse it whenever that point is still inside the series.spike-truewhen the latest value is at leastspikeThresholdPctpercent and 10 points above that baseline. On a first run the baseline is the previous period (spikeBasis: "previousPeriod").newRisingQueryCount, andisNewSinceLastRunon risingrelatedQueryrows.
The baseline only moves after the rows of a keyword were stored, so a failed run never hides a change. Use different store names to keep separate schedules apart.
In the summary example above, the previous run stored 42 as its latest value (previousLatestValue). Six minutes later Google reports that same point as 40 in the new series (valueAtPreviousRun), and the new latest value is 39. The change is therefore -1 (-2.5%), not -3. Two rising queries were not in the previous list (newRisingQueryCount: 2).
Scales: read this before comparing numbers
Google Trends does not return search volumes. Every value is relative, 0-100:
- Default (
compareMode: false): 100 is the keyword's own peak within the chosen geo and time range. A 60 for "bitcoin" and a 60 for "nvidia" say nothing about which one is searched more. compareMode: true: keywords are sent in groups of up to 5, in list order. Inside a group, 100 is the peak of the most searched keyword, so values of the group are comparable (scale: "compared",comparedWithlists the others). Values from different groups are not comparable. Google allows at most 5 keywords per comparison. If the last group has a single keyword, it is a normal single lookup.- The scale changes whenever the time range, the geo or the group changes - and also between runs, when a new peak appears. That is why
valueAtPreviousRunexists. - Related queries and interest by region are always per keyword, also in compare mode.
Pricing
Pay per event: $0.01 for each keyword x geo that completed with data (event name keyword). There is no start fee and no charge per dataset row. Proxy traffic, retries, summary rows and the run summary are included.
| What you run | Billed keywords | Cost |
|---|---|---|
| 1 keyword, once | 1 | $0.01 |
| 1 keyword, every day for 30 days | 30 | $0.30 |
| 5 keywords, every day for 30 days | 150 | $1.50 |
| 20 keywords, once a week for 4 weeks | 80 | $0.80 |
| 100 keywords, once | 100 | $1.00 |
| 5 keywords in 3 countries, every day for 30 days | 450 | $4.50 |
The price is the same for every time range and for any combination of include.
Not charged:
- Keywords with status
failed,partial,budgetLimitedornotStarted. - Keywords that complete without data (
hasData: false,stopReason: "noData"). - Dataset rows, summary rows and the run summary.
Good to know:
- In compare mode every keyword of a completed group that has data is one event.
- A keyword looked up in 3 countries is 3 events.
- If you set a maximum cost per run, the Actor only fetches keywords that still fit the budget and marks the rest
budgetLimited. It never fetches a keyword it cannot bill and never bills a keyword it did not store. RUN_SUMMARY.totals.chargedalways equals the number of summary rows withcharged: true.
Reliability: what we measured
How the Actor deals with Google's rate limits:
- Every keyword starts on a fresh proxy session with its own cookie and fixed browser headers.
- A request that Google refuses (HTTP 429) is retried alone: first with the same token on a new session, then after a pause with new tokens.
- A keyword that still fails is tried once more at the end of the run, without fetching again what was already saved.
- In
automode datacenter proxies are used first; retries and rate-limited stretches go through residential proxies. - After 30 refused requests in a row the run stops instead of hammering Google.
What we measured, on one day (2026-10-02):
- One run of 120 keywords (90 English, 30 Korean / Japanese / Chinese, over 9 geos and 7 time ranges): 120 of 120 lookups completed. 19 of them needed at least one retry. The run took 7 minutes 18 seconds.
- Seven later runs with 118 lookups in total: 118 of 118 completed.
This is a one-day sample, taken while our datacenter IPs were rate-limited, so almost all requests went through residential proxies. It is a measurement, not a promised success rate. Google can tighten its limits at any time. Check status in your own runs - and remember that a keyword that fails costs you nothing.
Limits and honest notes
- Relative values only. 0-100, rescaled on every request (see Scales). No absolute search volume.
- Numbers move between requests. Google Trends works on a sample of searches and rescales each response, so the same day can show a slightly different value tomorrow.
- Compare mode: 5 keywords per group - Google's limit.
- Related topics are not offered. In our tests Google returned an empty list for them on this path.
- "Trending now" is not included. This Actor is for keywords you choose.
- Web search only. Image, News, Shopping and YouTube search are not offered.
- Top-level categories only (the 25 in the input form).
- Rate limits are Google's and can change. Google rate-limits these endpoints (HTTP 429) and blocked our small datacenter proxy pool after about a hundred keywords. The retries and the residential fallback are there for that; if Google still refuses, the keyword is
failedwithstopReason: "rateLimited"and is not charged. - This is not an official API. Google can change the response format at any time. The Actor checks the format of every response and reports
unexpectedResponserather than storing unchecked data. - Low-volume keywords and short time ranges often have no data (
hasData: false). Google sometimes returns a series with a single non-zero point for a very rare term; that counts as data. - Largest run we tested: 120 keywords. For longer lists, split the keywords over several runs.
- Verified in tests: geo
worldwide,US,GB,DE,CA,AU,KR,JP,TW,US-CA; all time ranges in the table; custom date ranges; all 25 top-level categories; Korean, Japanese and Chinese keywords.
Use from the API, schedules and automation tools
Run and get the rows in one call:
curl -X POST "https://api.apify.com/v2/acts/magenta_courser~google-trends-monitor/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"keywords": ["bitcoin", "nvidia"], "geo": "US", "timeRange": "now 7-d", "include": []}'
Python (pip install apify-client):
from apify_client import ApifyClientclient = ApifyClient("YOUR_TOKEN")run = client.actor("magenta_courser/google-trends-monitor").call(run_input={"keywords": ["bitcoin", "nvidia"],"geo": "US","timeRange": "today 3-m","include": ["interestOverTime", "relatedQueries"],})rows = client.dataset(run["defaultDatasetId"]).list_items().itemssummaries = [r for r in rows if r["type"] == "keywordSummary"]timeline = [r for r in rows if r["type"] == "timelinePoint"]
- Schedules - create a schedule in Apify Console (for example every day at 06:00) with a fixed input. Keep the same
historyStoreNameso each run is compared with the one before. - n8n, Make, Zapier - use the Apify integration: run the Actor, read the dataset items, keep the rows with
type = keywordSummary, and branch onspike = trueto send an alert. - Google Sheets / BI tools - export the dataset as CSV or Excel, or load the JSON from the dataset API URL.
Use with AI agents (MCP)
The Actor works as a tool for AI agents through the Apify MCP server. Add it to an MCP client such as Claude Desktop, Cursor or VS Code:
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=magenta_courser/google-trends-monitor","headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }}}}
Then ask, for example: "Check Google Trends for 'air fryer' and 'rice cooker' in the US over the last 90 days. Which one is rising?"
Tips for agents:
- Pass
"include": []to get only one summary row per keyword. That is the smallest answer. - Read
statusandhasDatafirst, thenlatestValue,changeVsPreviousPeriodPct,changeSinceLastRunPct,spikeandtopRisingQuery(needs"include": ["relatedQueries"]). - Values are relative (0-100). To say which of several keywords is searched more, set
"compareMode": truewith up to 5 keywords. geotakes ISO country codes ("US","KR"), not country names.
Moving from pytrends
pytrends was archived in April 2025 and is no longer maintained. If your scripts stopped working or keep running into HTTP 429, the same requests map to this Actor like this:
| pytrends | This Actor |
|---|---|
build_payload(kw_list, timeframe, geo, cat) | keywords, timeRange (same strings: today 3-m, now 7-d, today 5-y, all), geo, category |
timeframe="2026-01-01 2026-06-30" | customTimeRange: "2026-01-01 2026-06-30" |
interest_over_time() | include: ["interestOverTime"] - timelinePoint rows |
related_queries() | include: ["relatedQueries"] - relatedQuery rows with kind top / rising |
interest_by_region() | include: ["interestByRegion"] - regionInterest rows |
5 keywords in one kw_list (shared scale) | compareMode: true |
one keyword per kw_list (own scale) | default (compareMode: false) |
related_topics(), trending_searches(), suggestions() | not offered |
Differences to know: rows are long format (one row per keyword and point) instead of a wide DataFrame - in pandas, pd.DataFrame(timeline).pivot(index="time", columns="keyword", values="value") gives the wide table. Proxies, cookies and retries are handled by the Actor.
FAQ
Is this the official Google Trends API? No. Google's own Trends API is in a limited alpha that you have to apply for. This Actor reads the public data behind the Google Trends website. It is not affiliated with Google.
Do I need a Google account, an API key or my own proxies? No. You only need an Apify account. Proxies are included in the price.
Are the values search volumes? No. Google Trends only publishes relative interest from 0 to 100. See Scales.
Why is latestValue different from what I saw yesterday for the same day?
Google rescales the series on every request and works on a sample of searches. Compare with valueAtPreviousRun, which is read from today's series.
Why did a keyword fail?
Read stopReason and errorMessage in its summary row. rateLimited: run it again in a few minutes. invalidRequest: Google rejected the geo, time range or category. unexpectedResponse: Google changed something - please open an issue. Failed keywords are not charged.
What does partial mean?
The time series was saved, but related queries or regions kept failing. You keep the rows and the keyword is not charged. Run it again to get the missing part.
Am I charged for a keyword that has no data?
No. It is stored with hasData: false and stopReason: "noData", and charged is false.
Can I monitor hourly?
Yes. Use now 1-d or now 7-d and an hourly schedule. Keep the same historyStoreName.
Can I compare more than 5 keywords? Google compares at most 5 at a time. With more keywords, the Actor makes groups of 5 in list order, and values of different groups are not comparable. To put more keywords on one scale, use one run per group, put the same anchor keyword first in every group, and rescale the groups by the anchor's values.
How do I get only the rising queries?
Use "include": ["relatedQueries"] and keep the rows with type = "relatedQuery" and kind = "rising".
Which time zone are the times in? UTC. Daily points are UTC days.
How many keywords can I put in one run? There is no fixed limit. The largest run we tested had 120 keywords and took about 7 minutes. For long lists, split them into several runs.
Something is wrong or missing. Where do I report it? Open an issue on the Actor's Issues tab. Include the run ID.
Notes
This Actor collects only public, aggregated search interest data from Google Trends. It does not log in to any account and does not collect personal data. It does not solve captchas. Google Trends is a trademark of Google LLC; this Actor is an independent tool and is not affiliated with or endorsed by Google.