Google Trends API Scraper - Trending Searches & Keyword Trends
Pricing
Pay per event + usage
Google Trends API Scraper - Trending Searches & Keyword Trends
Google Trends data as rows: interest over time, interest by region, and top & rising related queries. Compare up to 5 keywords per line across multiple countries, plus Trending Now with hundreds of trends per country (volume, start time, related searches). No browser, no login.
Get Google Trends data as clean rows:
- Interest over time: Google's 0–100 series for every keyword.
- Interest by region: 0–100 per state, region, metro area (US) or country.
- Related queries: the top and rising lists. Rising percentages other than "Breakout" do not match the ones on the trends.google.com website: use them only to order the rising list.
- Trending Now: up to 500 trends per country (the RSS feed has 10), with search volume, start time, related searches and categories.
Compare up to 5 keywords on one line, run many lines and many countries in one run, and pay per report. The Actor calls the undocumented JSON endpoints the Google Trends website itself uses, over HTTP, so it needs no browser and no login.
Not affiliated with or endorsed by Google.
Use cases
- SEO seasonality: see when a keyword peaks each year before you plan pages and campaigns.
- Content calendars: time posts to the weeks a topic rises, and find related queries that are gaining.
- Brand and market comparison: put up to 5 brands or products on one scale, country by country.
- News and trend monitoring: pull Trending Now on a schedule to see what is spiking in each country.
- Product research: compare product names and find the regions where interest is highest.
Quick start
Click Start with the prefilled input, or send this:
{"searchTerms": ["chatgpt, gemini", "nike"],"geos": ["US"],"timeRange": "today 12-m"}
This gives you 3 keyword reports (chatgpt and gemini compared, plus nike on its own) for the US over the past 12 months, at a cost of $0.009.
To get Trending Now as well:
{"searchTerms": ["nike"],"includeTrendingNow": true,"trendingGeos": ["US", "GB", "DE"],"maxTrendingPerGeo": 100}
Sample output
These rows come from live fetches on 2026-09-29. Every row also carries category, property and scrapedAt, which are shown on the first row only.
{"type":"interest_over_time","searchTerms":["chatgpt","gemini"],"geo":"US","timeRange":"today 12-m","category":0,"property":"","scrapedAt":"2026-09-29T07:07:58.077Z","term":"chatgpt","date":"2026-09-27T00:00:00.000Z","timestamp":1790467200,"value":65,"formattedValue":"65","isPartial":true}{"type":"interest_over_time","searchTerms":["chatgpt","gemini"],"geo":"US","timeRange":"today 12-m","term":"gemini","date":"2026-09-27T00:00:00.000Z","timestamp":1790467200,"value":31,"formattedValue":"31","isPartial":true}{"type":"interest_by_region","searchTerms":["chatgpt","gemini"],"geo":"US","timeRange":"today 12-m","term":"chatgpt","geoCode":"US-CA","geoName":"California","value":100}{"type":"related_query","searchTerms":["chatgpt","gemini"],"geo":"US","timeRange":"today 12-m","term":"chatgpt","rank":"top","position":1,"query":"what is chatgpt","value":100,"formattedValue":"100","link":"https://trends.google.com/trends/explore?q=what+is+chatgpt&date=today+12-m&geo=US"}{"type":"related_query","searchTerms":["bitcoin"],"geo":"US","timeRange":"today 12-m","term":"bitcoin","rank":"rising","position":1,"query":"how to buy bitcoin safely","value":11950,"formattedValue":"Breakout","link":"https://trends.google.com/trends/explore?q=how+to+buy+bitcoin+safely&date=today+12-m&geo=US"}{"type":"trending_now","searchTerms":null,"geo":"US","timeRange":"past 24 hours","position":2,"title":"jj mccarthy","traffic":200000,"increasePercent":1000,"startedAt":"2026-09-28T16:00:00.000Z","endedAt":null,"isActive":true,"relatedQueries":["jj mccarthy","jj mccarthy trade","nfc east","jj mccarthy stats","giants trade","vikings qb"],"categories":["Sports"],"articleIds":[4837249087,4853607005],"trendsUrl":"https://trends.google.com/trends/explore?q=jj+mccarthy&geo=US&date=now+1-d&hl=en-US"}{"type":"report_status","searchTerms":["zzqxv kkwpqj flurbo"],"geo":"US","timeRange":"today 12-m","term":"zzqxv kkwpqj flurbo","status":"no_data","message":"Google Trends does not have enough search data for this term, geo and time range."}
relatedQueries and articleIds are shortened in the sample above.
In the dataset tab, the Interest over time, Interest by region, Related queries, Trending Now and Report status views each show the columns for their row type. Views only choose columns; they do not filter rows, so every view lists every row. To work with one row type, filter on the type field.
Input
| Field | Default | What it does |
|---|---|---|
searchTerms | — | One comparison per line. Separate up to 5 terms on a line with commas ("chatgpt, gemini"). Up to 50 lines. Needed unless Trending Now is on. |
geos | ["US"] | Two-letter country codes. Use "worldwide" for worldwide. Each line runs once per country (up to 50). State and city codes such as "US-CA" are not accepted; for state-level data use the interest_by_region rows. |
timeRange | today 12-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. |
customTimeRange | — | "YYYY-MM-DD YYYY-MM-DD", from 2004-01-01 up to today. Overrides timeRange. |
category | 0 | Google Trends category id, 0–2000 (0 = all; 7 = Finance, 18 = Shopping, 71 = Food & Drink…). To find an id, pick a category on trends.google.com and read the cat= parameter of the explore URL. |
property | "" | "" web, images, news, froogle (Google Shopping), youtube. |
includeInterestOverTime | true | Include the 0–100 series. |
includeInterestByRegion | true | Include the per-region breakdown. |
regionResolution | by geo | REGION inside a country, COUNTRY for worldwide. Fallbacks, each logged as a warning: COUNTRY inside a country uses REGION; any other level on worldwide uses COUNTRY; DMA (metro areas) exists for the US only, so other countries use REGION. CITY is not offered for every country. |
includeLowSearchVolumeRegions | false | Same as the website's "include low search volume regions" checkbox. Off matches the website's default view. |
includeRelatedQueries | true | Include the top and rising related queries. |
includeTrendingNow | false | Add the Trending Now list for each of trendingGeos. |
trendingGeos | ["US"] | Two-letter country codes for Trending Now (up to 50). |
trendingHours | "24" | Window: "4", "24", "48" or "168" hours (the same choices as the Trending Now page). It is a string: API callers must send "48", not 48. |
maxTrendingPerGeo | 50 | Trends kept per country, in Google's order (1–500). 500 is a hard cap: Google lists more for long windows (US: about 657 for 48 hours and 1,891 for 7 days), and those lists are cut to the first 500. |
proxyConfiguration | Apify Proxy | The datacenter proxy is enough. |
One run has one time range. For another range, run again. Lines are not merged: the same term on two lines is fetched and charged once per line (repeats within one line are dropped).
Output fields
Every row has type, searchTerms (the comparison line, or null for Trending Now), geo ("" = worldwide), timeRange, category, property and scrapedAt.
interest_over_time
term, date (period start, ISO UTC), timestamp (Unix seconds), value (0–100), formattedValue (Google's own rendering, where "<1" marks a value that is small but not zero), isPartial (the period is still in progress).
In a comparison, all terms share one scale, just as they do on Google Trends. A term with no data in a comparison gets no interest-over-time rows, not a flat line of zeros.
interest_by_region
term, geoCode (for example US-CA, 759 for a DMA, or a country code), geoName, value (0–100, relative to that term's top region).
Regions with no data are left out; they are not reported as 0. By default, low-search-volume regions are excluded, as in the website's default view. Set includeLowSearchVolumeRegions to add them.
related_query
term, rank (top or rising), position, query, value, formattedValue, link (a full trends.google.com URL, or null when Google gives none).
For top, value is Google's 0–100 score. For rising, "Breakout" means growth above 5,000%. Other rising percentages ("+250%" and so on) do not match the numbers the trends.google.com website shows for the same query. They are reliable only for ordering the rising list.
trending_now
position, title, traffic (Google's approximate search count, for example 200000 for "200K+"; null when Google gives none), increasePercent (null when Google gives none), startedAt, endedAt (null while active), isActive, relatedQueries, categories (names such as "Sports", or a numeric id when the name is unknown), articleIds (Google's article ids), trendsUrl (an Explore link; for the 48-hour window it opens a 7-day Explore window, because Explore has no 48-hour range).
report_status (free)
term (null on Trending Now status rows), status, message. The status is one of these:
no_data: no requested part of this term × country × time range returned any data.error: the report failed or was not fetched, for example because a part failed after all retries on fresh connections, or the budget or timeout ran out. If some rows did arrive, they are delivered free and the report is not charged.partial: the report was delivered and charged, but a requested part is missing. This happens only when Google's explore answer offered no widget for that part, or Google refused that part's own request with HTTP 400/401 (for example, a region level it does not have for that country). The row names the part and the reason.
A part that Google answered with an empty list (for example, no rising queries) adds no rows and gets no partial row. The report is still charged if its other parts delivered rows.
A RUN_SUMMARY record in the key-value store lists per-request timings, request counts, and which terms were delivered, empty or failed.
Pricing
You pay per result that is actually delivered:
| Event | Price | When |
|---|---|---|
| Keyword report | $0.003 | Once per term × country × time range with at least one data row and no part that failed after retries. This covers all of that term's interest-over-time, region and related-query rows. A part Google's explore answer offered no widget for, or that Google refused with HTTP 400/401, does not block the charge (it is named in a free partial row). A part that answered empty adds no rows and does not block the charge either. |
| Trending Now result | $0.0005 | Per trending row delivered. |
report_status rows | free | Nothing is charged for a term that returned no data or failed. |
| Incomplete reports | free | If a requested part still fails after retries on fresh connections (a temporary block, a timeout), that report is not charged, and whatever did arrive is delivered free. |
Worked examples:
- 10 keywords × 1 country = 10 reports = $0.03
"chatgpt, gemini"× 3 countries = 6 reports = $0.018- The US Trending Now list over 24 hours (243 trends on 2026-09-29, with
maxTrendingPerGeo≥ 243) = $0.12 - The default 50 trends per country = $0.025 per country; the 500-trend cap = $0.25 per country
Platform usage (compute and proxy) is billed to you by Apify separately at its standard rates. That cost is small: the Actor's default memory is 256 MB, it uses no browser, and each report needs only a handful of small JSON requests.
The Actor respects your maximum cost per run. It charges each report before delivering it and stops cleanly when the budget runs out. If the limit cannot cover a single result, the run fails at once and fetches nothing.
Run size and timeout
The default run timeout is 3,600 s (1 hour). A unit is one line in one country. The Actor works on about 2 units at a time, at roughly 3–5 s each (more for a line that compares several terms), so plan for about units ÷ 2 × 4 s. For example, 50 lines × 10 countries = 500 units ≈ 1,000 s, but 50 lines × 50 countries = 2,500 units ≈ 5,000 s, which is past the default timeout.
A line that cannot start in a country before the timeout comes back as one free report_status row per term, with status: "error" and a "Not fetched" message; nothing is charged for them. Trending Now runs after all keyword units, so in a run that reaches its timeout, each remaining Trending Now country gets a free error row saying "Run deadline reached before this request could be made." For large runs, raise the timeout in the run options (or with the timeout API parameter, in seconds).
Use via API
The Actor id is jy-labs/google-trends-api-scraper. Run it and get the rows in one call:
curl -X POST "https://api.apify.com/v2/acts/jy-labs~google-trends-api-scraper/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \-H "Content-Type: application/json" \-d '{"searchTerms": ["chatgpt, gemini"], "geos": ["US"], "timeRange": "today 12-m"}'
The sync endpoint waits up to 300 s, so start large runs asynchronously with one of the clients:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });const run = await client.actor('jy-labs/google-trends-api-scraper').call({ searchTerms: ['chatgpt, gemini'], geos: ['US'] });const { items } = await client.dataset(run.defaultDatasetId).listItems();const relatedQueries = items.filter((row) => row.type === 'related_query');
from apify_client import ApifyClientclient = ApifyClient("YOUR_API_TOKEN")run = client.actor("jy-labs/google-trends-api-scraper").call(run_input={"searchTerms": ["chatgpt, gemini"], "geos": ["US"]})items = client.dataset(run["defaultDatasetId"]).list_items().items
To run it regularly, for example a daily Trending Now pull, create a schedule in Apify Console. Apify integrations and webhooks can send each run's dataset on to Google Sheets, Slack, Make, Zapier or your own endpoint.
FAQ
Why are the numbers 0–100 and not search counts? That is how Google Trends reports interest: it is relative to the peak of the chart (or of the top region), not an absolute count. Compare terms on one line to put them on one scale. Trending Now is different: it does give approximate search volumes.
How many keywords can I compare? Up to 5 per line, which is Google's limit. You can add up to 50 lines per run, and each line runs in each country you list.
What do I get for a keyword with too little search volume?
A free report_status row with status: "no_data". You are not charged, and if every term in the run was simply too small, the run still succeeds.
How fast is it? A single-keyword report typically takes a few seconds, and the Actor works on two comparison groups at a time. A Trending Now list is a single request per country. See Run size and timeout for large runs.
Do I need a residential proxy? No. Google Trends worked through the Apify datacenter proxy in our testing, which is the default.
Is it legal to scrape Google Trends? The Actor collects only public, aggregated data that anyone can see on the Google Trends website. It collects no data about individual Google users, because Trends data is aggregated and anonymized; trend titles and queries can name public figures. You are responsible for how you use the data, including following Google's terms and the laws that apply to you.
Limitations
- Related topics are not offered. Google blocks automated clients from them: they always come back empty, so the Actor does not sell them.
- Rising related-query percentages do not match the website. Apart from
"Breakout", the risingvalueandformattedValuediffer from what trends.google.com shows for the same query. Use them to order the rising list, not as growth figures. - Related-query lists, especially rising, can have fewer items than the website shows for the same query, because Google returns lists of different lengths per request.
- The region request is Google's default view: low-search-volume regions are excluded, as on the website. Small territories can still rank near the top in either view (St. Helena is #2 for worldwide "nike"). That is Google's own data.
includeLowSearchVolumeRegionsadds more of them (worldwide "nike": 59 → 230 regions). - Values can differ between fetches, and between this Actor and the website, because Google Trends samples its data per request and IP. Most points are within ±3, occasionally up to about 7. Small regions vary the most, and the past-hour and past-4-hour ranges change minute to minute.
regionResolutiononly takes levels Google offers for the geo.COUNTRYinside a country falls back toREGION, any other level on worldwide falls back toCOUNTRY, andDMAoutside the US falls back toREGION, each with a warning in the log. If Google refuses a level outright, the report is delivered without its region part, with apartialrow saying why.- Trending Now needs a country. Worldwide is not available, and some countries are not covered; those get an
errorstatus row. - Trending Now is capped at 500 trends per country. Longer windows list more (US: about 657 for 48 hours and 1,891 for 7 days), and only Google's first 500 are kept.
- News articles for Trending Now are returned as Google's article ids (
articleIds), not as headlines. - Google sometimes briefly refuses requests from an exit IP. The Actor retries on new connections, up to a fixed limit, before it gives up on a part. The status message counts incomplete reports, and
RUN_SUMMARYrecords retries, rotations and recovery cycles. - Google changes these endpoints from time to time. When something stops returning data, the
report_statusrows andRUN_SUMMARYsay which part failed.