Google Trends API & Scraper — pytrends Alternative avatar

Google Trends API & Scraper — pytrends Alternative

Pricing

from $0.01 / 1,000 dataset items

Go to Apify Store
Google Trends API & Scraper — pytrends Alternative

Google Trends API & Scraper — pytrends Alternative

Google Trends interest over time, interest by region, and related queries (top + rising) for any keyword, country, time range or explore URL. Direct API, automatic 429 retry, and you only pay for results that contain data.

Pricing

from $0.01 / 1,000 dataset items

Rating

0.0

(0)

Developer

Daniel Posztos

Daniel Posztos

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

13 days ago

Last modified

Share

Google Trends API & Scraper — a pytrends Alternative Without 429 Errors

SEO title: Google Trends API — pytrends alternative, no 429 errors SEO description: Google Trends API for Python, JavaScript or no code: interest over time, by region and related queries for any keyword. 429 rate limits handled for you; pay only for complete results.

A Google Trends API you can call from Python, JavaScript, any HTTP client or an AI agent, and a drop-in replacement for pytrends when it keeps failing with TooManyRequestsError (HTTP 429). Give it keywords (or Google Trends explore URLs) and get Google Trends data back as clean JSON, one row per query:

  • Interest over time: the full 0-100 time series plus a per-term summary (average, peak and when it happened, latest value)
  • Interest by region: countries, states/regions, cities (with coordinates) or US metro areas
  • Related queries: top and rising searches, including "Breakout" terms

Compare up to 5 terms on one shared scale, or look up hundreds of terms one by one. Works for web, image, news, YouTube and Google Shopping search.

Why this exists

Google Trends has no official API, and scraping it is unreliable: Google answers bursts of requests with HTTP 429 "Too Many Requests". In our tests, 28 of 30 back-to-back data requests from one IP were rejected. Browser-based Trends scrapers run into this constantly, and they are slow.

This actor works differently:

  • No browser. It calls the same JSON endpoints the Google Trends web page uses, and runs 3 queries in parallel.
  • Automatic 429 handling. Each request goes out directly first. When Google rejects it, the actor waits and retries on fresh datacenter proxy sessions (new IP, new cookies), and as a last resort on residential IPs. Anything that still fails gets one more try at the end of the run, after a cool-down.
  • You only pay for complete results. A term with no search volume, a query that still fails, or a row with a section missing still appears in the dataset (so you can see what happened), but it is not charged.

Cloud test, 40 US keywords: 39 complete results, 1 with no search volume (not charged), 0 failed, in 37 seconds. Why the retry ladder matters: in a test the same day, the shared datacenter proxy alone got throttled by Google (2 of 5 keywords failed after 42 retries), while direct requests from the same cloud kept working (5 of 5). So every request now starts direct, and proxies are only the fallback.

Input

FieldWhat it doesDefault
searchTermsKeywords, e.g. ["bitcoin", "ethereum"]. One row per term.—
compareTermsCompare terms in groups of up to 5 on one shared 0-100 scale (one row per group).false
startUrlsGoogle Trends explore URLs; each keeps its own settings.—
geo"" = worldwide, "US", "US-CA", "US-CA-807" (metro)""
timeRangenow 1-H, now 4-H, now 1-d, now 7-d, today 1-m, today 3-m, today 12-m, today 5-y, all, or "2024-01-01 2024-12-31"today 12-m
categoryGoogle Trends category ID (cat= in a Trends URL), 0 = all0
searchPropertyweb, images, news, youtube, shoppingweb
includeAny of interestOverTime, interestByRegion, relatedQueriesall three
regionResolutionCOUNTRY, REGION, CITY, DMA, or empty = Google's default""
languageLanguage of region names and queries, e.g. en-US, de, huen-US
timezoneOffsetMinutesGoogle's tz: minutes west of UTC (New York = 300)0
maxConcurrencyQueries running in parallel (1-5)3
proxyConfigurationProxy for retries: datacenter first, residential as last resort (custom groups replace both)Apify Proxy

You need at least one search term or one start URL.

Worked example — input

{
"searchTerms": ["bitcoin"],
"geo": "US",
"timeRange": "today 3-m"
}

Worked example — output (real data, shortened with "...")

{
"searchTerms": ["bitcoin"],
"geo": "US",
"timeRange": "today 3-m",
"category": 0,
"searchProperty": "web",
"trendsUrl": "https://trends.google.com/trends/explore?q=bitcoin&date=today%203-m&geo=US",
"summary": {
"bitcoin": {
"average": 53,
"peakValue": 100,
"peakDate": "2026-08-21T00:00:00Z",
"latestValue": 53,
"latestDate": "2026-10-12T00:00:00Z",
"latestIsPartial": true
}
},
"interestOverTime": [
{"date": "2026-07-12T00:00:00Z", "timestamp": 1783814400, "formattedTime": "Jul 12, 2026", "values": {"bitcoin": 66}, "isPartial": false},
{"date": "2026-07-13T00:00:00Z", "timestamp": 1783900800, "formattedTime": "Jul 13, 2026", "values": {"bitcoin": 77}, "isPartial": false},
"...",
{"date": "2026-10-12T00:00:00Z", "timestamp": 1791763200, "formattedTime": "Oct 12, 2026", "values": {"bitcoin": 53}, "isPartial": true}
],
"averages": {"bitcoin": 53},
"interestByRegion": [
{"geoCode": "US-KS", "geoName": "Kansas", "values": {"bitcoin": 100}},
{"geoCode": "US-NV", "geoName": "Nevada", "values": {"bitcoin": 77}},
{"geoCode": "US-CA", "geoName": "California", "values": {"bitcoin": 74}},
"..."
],
"relatedQueries": {
"bitcoin": {
"top": [
{"query": "bitcoin price", "value": 100, "link": "https://trends.google.com/trends/explore?q=bitcoin+price&date=today+3-m&geo=US"},
{"query": "bitcoin stock", "value": 20, "link": "https://trends.google.com/trends/explore?q=bitcoin+stock&date=today+3-m&geo=US"},
"..."
],
"rising": [
{"query": "british man recovers lost bitcoin", "value": 12250, "formattedValue": "Breakout", "link": "https://trends.google.com/trends/explore?q=british+man+recovers+lost+bitcoin&date=today+3-m&geo=US"},
{"query": "suriname", "value": 1450, "formattedValue": "+1,450%", "link": "https://trends.google.com/trends/explore?q=suriname&date=today+3-m&geo=US"},
"..."
]
}
},
"hasData": true,
"scrapedAt": "2026-10-12T13:56:02Z"
}

Output

One dataset row per query (one term, or one group of compared terms):

FieldMeaning
searchTerms, geo, timeRange, category, searchPropertyWhat was queried (geo is WORLDWIDE when empty)
trendsUrlThe same query on trends.google.com, for checking by eye
summaryPer term: average, peakValue, peakDate, latestValue, latestDate, latestIsPartial
interestOverTimePoints with date (UTC), timestamp, formattedTime, values per term, isPartial
averagesAverage interest per term over the period
interestByRegionRegions with data: geoCode, geoName, values; coordinates at city level
relatedQueriesPer term: top and rising lists (formattedValue like +250% or Breakout)
hasDatafalse means Google returned nothing (not charged)
missingSectionsSections that kept failing; the rest of the row is there (not charged)
errorOnly present when the query, or a section of it, failed after all retries

Rows come in input order, except queries that needed the end-of-run retry: those come last.

How to read the numbers: Google Trends values are relative, not search counts. 100 is the peak within the query, and everything else is scaled to it. Compared terms share one scale. Terms queried one by one each have their own scale, so compareTerms: true is what you want when the question is "which is searched more?". A latestIsPartial: true point covers a period that isn't over yet, so it usually reads low.

Use it from code or an AI agent

Run it synchronously and get the rows in one HTTP call:

curl -X POST "https://api.apify.com/v2/acts/westerly_breaker~google-trends-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"searchTerms": ["chatgpt", "claude", "gemini"], "compareTerms": true, "timeRange": "today 3-m"}'

From Python (pip install apify-client), the pytrends equivalents are interestOverTime (pytrends interest_over_time), interestByRegion (interest_by_region) and relatedQueries (related_queries):

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("westerly_breaker/google-trends-scraper").call(
run_input={"searchTerms": ["chatgpt", "claude"], "compareTerms": True, "timeRange": "today 3-m"}
)
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
print(row["searchTerms"], row["averages"])

The input fields are plain JSON with descriptive error messages. AI agents (Apify MCP server, LangChain, n8n, Make) can call the actor without a custom adapter, and if an input is wrong, the error message says what to fix.

Pricing (pay-per-event)

$0.002 per complete result. That's one row: one term, or one group of up to 5 compared terms, with every section you asked for. Platform usage is included; there is no separate compute charge.

  • 100 keywords, 97 complete, 2 with no search volume, 1 failed → 97 × $0.002 = $0.194
  • Rows without data, failed rows and partial rows are delivered but never charged.
  • If you set a maximum cost per run, the actor stops cleanly at that limit. Every row you paid for is delivered, and you are never billed for a row you didn't get.

Error messages

Bad input stops the run before any request, with a message that names the field and the fix, for example:

  • 'geo' 'USA' is not a valid Google Trends location code. Use '' (worldwide), an ISO 3166 country code like 'US' or 'HU', a region like 'US-CA', or a US metro (DMA) like 'US-CA-807'.
  • Search term 'a,b' contains a comma. Put each term in its own list entry instead, and set 'compareTerms' to true if you want them compared.

Known limitations

  • Related topics are not available. Google returns an empty topic list to clients that aren't a full browser, so this actor doesn't offer the section rather than return empty data. Related queries work normally.
  • Values are relative (0-100), not absolute search volumes. This is how Google Trends works, not a limitation of the actor.
  • Low-volume terms can come back empty. Google hides data below its privacy threshold. These rows have hasData: false and are free.
  • Per-term regional maps of compared terms are not fetched. The compared map (all terms on one scale) is. Query the terms one by one if you need each term's own regional ranking.

Data source

Public Google Trends data from trends.google.com, the same JSON the website loads. No login, no API key, no personal data.