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 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; 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, 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 }
All input fields
| Field | Default | Notes |
|---|---|---|
searchTerms | ["coffee, tea"] | One comparison per line, up to 5 comma-separated terms per line. |
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. 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? Compare at most 5 keywords on the same scale. 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.