Google Trends Scraper: Interest, Regions, Related, Trending Now
Pricing
from $0.50 / 1,000 results
Google Trends Scraper: Interest, Regions, Related, Trending Now
Reliable Google Trends API alternative. Compare up to 5 keywords per comparison, or up to 50 on one scale with an anchor term, and many comparisons per run: interest over time, interest by country, region or city, related queries and Trending now by country. Built-in 429 handling.
A Google Trends API alternative with a pytrends-style Python client and built-in HTTP 429 retries. Use the MIT Python client for familiar interest-over-time DataFrames, or run this Actor for clean JSON and spreadsheet rows. Compare up to 5 keywords per comparison like on trends.google.com, or up to 50 keywords on one scale; Google rate limits still apply.
Give it keywords, get:
| Data | Output type | What it is |
|---|---|---|
| Interest over time | interest_over_time | 0-100 timeline per term, with isPartial for the unfinished last period |
| Interest by region | interest_by_region | 0-100 per country, region/state, city or US metro (DMA) |
| Related queries | related_queries | Top and rising queries per term ("Breakout" included) |
| Related topics (beta) | related_topics | Top and rising topics per term (topic name, type and Knowledge Graph ID). Often empty, see Limits |
| Trending now | trending_now | What is spiking in Google Search right now, per country: search volume, % increase, start time, category, related searches |
Built for reliability first:
- Rate limit (HTTP 429) handling: each request retries up to 10 times. Every retry gets a new session (new proxy IP and new Google cookies) and waits with exponential backoff plus jitter.
- Cookie bootstrap: every session first visits Google Trends like a browser to get the
NIDcookie before calling the API. - Partial results instead of failed runs: if one comparison fails, the others are still saved, and the run summary tells you exactly what failed.
- Many comparisons per run: compare up to 5 terms on the same scale (up to 50 with an anchor term), and add as many comparison lines as you need.
Input
Each line of Search terms is one Google Trends comparison. Put up to 5 terms on a line, separated by commas, to compare them on the same 0-100 scale (exactly like the Compare button on trends.google.com).
Example 1: compare three keywords in the US over 12 months (the default)
{"searchTerms": ["coffee, tea, matcha"],"geo": "US","timeframe": "today 12-m"}
Example 2: everything for several keywords, worldwide, by country
{"searchTerms": ["chatgpt", "gemini", "claude ai"],"geo": "","timeframe": "today 5-y","includeInterestByRegion": true,"regionResolution": "COUNTRY","includeRelatedQueries": true,"includeRelatedTopics": true}
Example 3: YouTube search interest in South Korea, past 7 days, one row per hour for Google Sheets
{"searchTerms": ["아이폰, 갤럭시"],"geo": "KR","timeframe": "now 7-d","gprop": "youtube","outputFormat": "row-per-point","language": "ko","timezoneOffset": -540}
Example 4: custom date range
{ "searchTerms": ["taylor swift"], "geo": "", "timeframe": "custom", "customTimeRange": "2024-01-01 2024-12-31" }
Example 5: Trending now in several countries (no keywords needed)
{ "searchTerms": [], "trendingNowCountries": ["US", "GB", "KR", "JP", "IN"], "trendingNowHours": "24", "maxTrendingPerCountry": 50 }
Compare more than 5 keywords on one scale
Google Trends compares at most 5 terms at once, and two separate comparisons are not on the same scale (each one has its own 100). This is where most pytrends scripts get stuck. Put 6 to 50 terms on one line and the Actor does the usual fix for you:
- It picks an anchor term (
anchorTerm, or the first term of the line) and splits the other terms into groups of 4. - Each group is one Google comparison with the anchor added, so every group contains the anchor.
- The anchor's values tell how each group's scale relates to the others. All groups are rescaled to the first group where the anchor has data, then everything is scaled again so the highest value of the whole line is 100.
{"searchTerms": ["python, javascript, java, typescript, golang, rust, kotlin, swift, php, ruby, scala, perl"],"anchorTerm": "java","geo": "US","timeframe": "today 12-m"}
You get one interest_over_time result per term, as for a normal line, with two extra fields: scaledWith (the anchor) and scaleGroup (which Google comparison the term came from). The anchor's timeline is saved once, not once per group. If the anchor is not one of the line's terms it is used for matching only and not returned. With outputFormat: "row-per-point" you get one row per date with every term of the line in values.
Tips and limits:
- Choose an anchor of medium, steady popularity. If the anchor is 0 for the whole time range in a group, that group cannot be matched: its terms keep Google's own values for that group and get a
scaleWarningfield, so you never get a silently wrong number. A very small anchor next to a huge term is matched on few distinct values, so precision drops. - Values are rounded to 2 decimals. Google's own values are whole numbers, so expect small differences (about 1 point) against a single comparison on trends.google.com.
- Only interest over time is put on one scale. Interest by region and related queries stay per term (each term on its own 0-100 scale), as for any other line.
- A line with more than 50 terms stops the run with an error; split it into several lines with the same
anchorTerm(each line is then on its own scale). - The input format of apify/google-trends-scraper (
isMultiple) keeps its limit of 5 terms per line.
All input fields
| Field | Default | Notes |
|---|---|---|
searchTerms | ["coffee, tea"] | One comparison per line, comma-separated terms. Up to 5 terms is a normal Google comparison; 6 to 50 terms are put on one scale through an anchor term. |
anchorTerm | first term of the line | Only for lines with more than 5 terms. See Compare more than 5 keywords on one scale. |
geo | US | Country (US, GB, KR, JP, DE ...) or subregion (US-CA, GB-ENG). Empty = worldwide. |
timeframe | 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 (2004 to now), custom. |
customTimeRange | With custom: YYYY-MM-DD YYYY-MM-DD or hourly YYYY-MM-DDTHH YYYY-MM-DDTHH. | |
categoryId (form) or category (API) | Google Trends category ID, empty or 0 = all. category accepts a number (7) or a string ("7"). | |
gprop | web | web, images, news, youtube, froogle (Google Shopping). |
includeInterestOverTime | true | |
includeInterestByRegion | false | |
regionResolution | auto | COUNTRY, REGION, CITY, DMA. Auto: worldwide gives countries, a country gives regions, a region gives cities. |
includeLowVolumeRegions | false | |
includeRelatedQueries / includeRelatedTopics | false | Top and rising lists per term. |
trendingNowCountries | [] | Country codes for Trending now. |
trendingNowHours | "24" | "4", "24", "48" or "168". |
maxTrendingPerCountry | 0 | 0 = all. |
outputFormat | item-per-term | item-per-term, row-per-point or official. See below. |
language | en-US | Language for dates, topic names and Trending now. |
timezoneOffset | 0 | Minutes behind UTC (Google's tz). 0 = UTC, 300 = New York, -540 = Seoul. |
maxRetries | 10 | Retries per request on 429 or network errors. |
proxyConfiguration | Apify Proxy (datacenter) | Residential proxy also works but is rarely needed. |
Output
Every item repeats the input it came from (comparison, terms, geo, timeframe, category, gprop), so you can mix many comparisons in one dataset and still filter easily.
outputFormat: "item-per-term" (default, compact)
One item per term and data type. Timelines and region lists are arrays.
{"type": "interest_over_time","term": "coffee","comparison": "coffee vs tea vs matcha","terms": ["coffee", "tea", "matcha"],"geo": "US","timeframe": "today 12-m","category": 0,"gprop": "web","resolvedTimeRange": "2025-10-02 2026-10-02","resolution": "WEEK","average": 76,"peakValue": 100,"latestValue": 70,"timeline": [{ "date": "2026-09-20", "timestamp": 1789862400, "formattedTime": "Sep 20 – 26, 2026", "value": 76, "isPartial": false },{ "date": "2026-09-27", "timestamp": 1790467200, "formattedTime": "Sep 27 – Oct 3, 2026", "value": 70, "isPartial": true }],"scrapedAt": "2026-10-02T11:58:23.507Z"}
{"type": "related_queries","term": "coffee","comparison": "coffee vs tea vs matcha","geo": "US","timeframe": "today 12-m","top": [ { "rank": 1, "query": "coffee near me", "value": 100, "formattedValue": "100", "link": "https://trends.google.com/trends/explore?q=coffee+near+me&date=today+12-m&geo=US" } ],"rising": [ { "rank": 1, "query": "sports scores today", "value": 5350, "formattedValue": "Breakout", "link": "..." } ]}
{"type": "interest_by_region","term": "coffee","geo": "US","resolution": "REGION","regions": [ { "geoCode": "US-WY", "geoName": "Wyoming", "value": 100, "hasData": true } ]}
{"type": "trending_now","geo": "KR","hours": 24,"rank": 1,"title": "한국 대 베네수엘라","searchVolume": 200000,"increasePercentage": 1000,"startedAt": "2026-10-02T10:00:00.000Z","endedAt": null,"active": true,"categories": ["Sports"],"relatedQueries": ["한국 대 베네수엘라", "베네수엘라 축구 국가대표팀", "..."],"exploreUrl": "https://trends.google.com/trends/explore?q=...&geo=KR&date=now%201-d","source": "trending-now"}
outputFormat: "row-per-point" (flat, for Google Sheets and Excel)
- Interest over time: one row per date per comparison, with one column per term in
values(values.coffee,values.teain CSV). - Interest by region: one row per region per comparison, with one column per term.
- Related queries and topics: one row per query or topic, with
list=toporrisingandrank.
{ "type": "interest_over_time", "comparison": "coffee vs tea", "geo": "US", "timeframe": "today 12-m", "date": "2026-09-20", "isPartial": false, "values": { "coffee": 73, "tea": 32 } }
Row-per-point produces many more results (for example 52 weekly rows instead of 2 items for a 2-term, 12-month comparison), so it costs more. Use it when you want the data straight in a spreadsheet.
A run summary (items, errors and HTTP statistics per comparison) is saved to the key-value store as RUN_SUMMARY.
Switching from apify/google-trends-scraper
Keep your input JSON and change only the Actor name. When the input has a field from the apify/google-trends-scraper input schema (isMultiple, timeRange, startUrls, spreadsheetId, maxItems, viewedFrom ...), this Actor translates it and returns that Actor's field names: one item per search term or URL with inputUrlOrTerm, searchTerm, interestOverTime_timelineData, interestOverTime_averages, interestBy (worldwide) or interestBySubregion and interestByCity (country) or interestByCity and interestByMetro (US state), relatedQueries_top, relatedQueries_rising, relatedTopics_top, relatedTopics_rising. The values are Google's own objects, passed through unchanged. With the native input, set outputFormat: "official" to get the same shape.
Before:
await client.actor('apify/google-trends-scraper').call({searchTerms: ['web scraping', 'bitcoin'], isMultiple: false, geo: 'US', timeRange: 'today 3-m', category: '',});
After (same input):
await client.actor('ctriolab/google-trends-scraper').call({searchTerms: ['web scraping', 'bitcoin'], isMultiple: false, geo: 'US', timeRange: 'today 3-m', category: '',});
| Field | Handling |
|---|---|
searchTerms, isMultiple | Supported. Without isMultiple, each line is one term, even with a comma. With it, a line is a comparison of up to 5 terms. |
timeRange, customTimeRange | Supported. customTimeRange wins, as in the original. |
geo, category | Supported. Empty geo = worldwide. |
startUrls | Google Trends explore URLs: q, geo, date, cat and gprop are read from the URL. Other URLs stop the run with an error. |
spreadsheetId | Supported: first column of a public Google Sheet, row 1 is the title. |
maxItems | Supported. |
maxRequestRetries | Used as maxRetries (up to 15). |
viewedFrom, skipDebugScreen, maxConcurrency, pageLoadTimeoutSecs, outputAsISODate, csvOutput, isPublic | Ignored with a log warning. This Actor uses no browser and saves no page snapshots. For a proxy country use proxyConfiguration. |
Differences to know: related queries and topics are filled only for single-term items (comparisons get empty lists), related topics are often empty (see Limits), and an item is saved only when Google returned some data. Each item is one result for pricing. In Apify's public run statistics for the 30 days to 2026-10-23, this Actor had 26 runs and 26 succeeded.
Pricing
Pay per result: you pay only for items saved to the dataset. No monthly fee, and Apify platform usage and proxy are included.
Typical costs with the default item-per-term format:
| Job | Results |
|---|---|
| 1 comparison of 2 terms, interest over time | 2 |
| Same + interest by region + related queries | 6 |
| Trending now, 1 country, all trends (24 h) | 50 to 500 |
Limits and notes
- Values are relative (0-100) within each comparison, exactly as on Google Trends. Terms on different lines are not on the same scale.
- Google Trends allows at most 5 terms per comparison. Longer lines (up to 50 terms) are matched through an anchor term, see above. All terms in a comparison use the same location and time range.
- Google rate-limits automated traffic. The actor handles this with session rotation and backoff, so runs with many comparisons take longer (about 1 to 3 seconds per request, plus waiting time when Google slows us down).
- Related topics (beta): Google currently hides related topics from most automated clients (the API answers with an empty list). The actor retries once with a fresh session; if Google still returns nothing, no item is saved, so you are not charged, and the run summary notes it. Related queries are not affected.
- Very small search volumes return all zeros (Google's own behaviour).
- Trending now uses the same data as trends.google.com/trending. If that endpoint is unavailable the actor falls back to the public Trending now RSS feed (fewer fields, about 10 to 25 trends).
- The data is aggregated and anonymous. No personal data is collected.
Use cases
- SEO and content planning: find rising queries and seasonal peaks before you write.
- Market and product research: compare brands, products or features over time and by country.
- E-commerce: spot seasonality and trending products (use
gprop: frooglefor Google Shopping). - AI agents and MCP clients: one call returns structured trend data with the input echoed in every item.
- Newsrooms and social media teams: schedule Trending now every hour for the countries you cover.
Python: pytrends-next
Coming from pytrends? pytrends-next is our free, MIT-licensed drop-in replacement for the archived pytrends. It talks to Google Trends directly from your machine and needs no Apify account.
$pip install pytrends-next
from pytrends_next.request import TrendReq # was: from pytrends.request import TrendReqpytrends = TrendReq(hl="en-US", tz=360)pytrends.build_payload(["coffee", "tea"], timeframe="today 3-m", geo="US")df = pytrends.interest_over_time()
It retries HTTP 429 with a new session and backoff. If Google keeps answering 429, TrendReq(fallback="apify", apify_token="...") sends those calls to this Actor and returns the same shape. The fallback is off by default and is billed to your Apify account at this Actor's pricing. Source: ctriolab/google-trends-python, which also keeps the older single-file client gtrends.py (interest_over_time_df).
FAQ
Can I replace pytrends in Python?
Yes. pytrends-next keeps the pytrends TrendReq API, so most code only needs the import changed. It is free and works without Apify; only the optional fallback="apify" mode runs this Actor, at the published pricing. top_charts() and multirange_interest_over_time() are not available. See the Python API guide for setup and migration examples.
Does this prevent every Google Trends 429 error?
No. The Actor retries HTTP 429 and network errors up to maxRetries (10 by default), with a new session and exponential backoff plus jitter. Google can still reject requests. Successful comparisons are saved and failures are recorded in RUN_SUMMARY. See the pytrends 429 guide for the limits of retry handling.
What data limits should I expect? Google compares at most 5 keywords at once; this Actor puts up to 50 on one scale through an anchor term (interest over time only). Values are relative from 0 to 100 within each comparison, not absolute search volume. Low-volume terms may return zeros, related topics (beta) may be empty, and the Trending now RSS fallback has fewer fields. The Limits and notes section above explains these cases.
Support
Missing a field or a Google Trends feature? Open an issue on the Issues tab.