How to Scrape Google Trends (Python Guide)
- There is no official Google Trends API. The public explore page (
trends.google.com/trends/explore) blocked a plain cookieless request with HTTP 429 on my June 12, 2026 run. - The daily trending RSS feed (
trends.google.com/trending/rss) is the easy DIY win: I hit it and got HTTP 200 and 10 trending searches with traffic estimates and linked news, no key. - Interest-over-time numbers come from an undocumented widget API. With a session cookie it returned 200 and 53 weekly datapoints (0-100 scale), but it is unofficial and rate-limited.
- Trends values are a relative 0-100 index, not raw search counts, and the data is sampled, so two pulls of the same query can differ slightly.
- For absolute search volume, related-query tables at scale, or no rate-limit babysitting, use a scraper API like ChocoData or a keyword tool with its own volume data.
Google Trends is the fastest free read on what the world is searching for, which makes it a staple for SEO research, content planning, market timing, and trend-spotting. This guide builds a real Python scraper, tests it against the live service, and is honest about which doors are open. I ran every request below on June 12, 2026 and pasted the real output. The short version: the explore page slams plain requests with a 429, but Google’s own trending RSS feed and its undocumented widget API both handed me data. For the fundamentals, see my web scraping guide and the Python walkthrough.
Can you scrape Google Trends, and is it legal?
You can pull public Google Trends data with a script, and the legal risk depends on the method and what you store. The technical reality first: the visible explore page at trends.google.com/trends/explore rate-limits no-cookie clients, so a naive request gets a 429. Two other paths work, both tested below. The legal side has two layers worth separating.
On US computer-access law, reading pages anyone can load without logging in sits on the safer side. In hiQ Labs v. LinkedIn, the Ninth Circuit held that scraping public data does not violate the Computer Fraud and Abuse Act, and the Supreme Court’s Van Buren decision narrowed the CFAA toward traditional hacking. Requesting a public RSS feed is not, by itself, a federal computer crime.
Two further constraints apply. Contract law is the live risk: Google’s Terms of Service restrict automated access, and hiQ won the CFAA question yet still paid a $500,000 judgment for breaching a user agreement. Database and copyright protection is the second: the trend index values are factual measurements with thin protection, but the surrounding page content and the news articles linked from the feed are owned by others. Stay on public endpoints, never script a logged-in Google account, throttle your requests, and keep what you collect to the trend figures and metadata. I am a tester, not a lawyer, so get advice before a commercial scrape. My is web scraping legal pillar covers the full picture.
What data can you extract from Google Trends?
Google Trends exposes four distinct datasets, and they live behind different endpoints with different reliability. Knowing which source holds what tells you when DIY is enough and when you need an API.
| Dataset | Source endpoint | What you get | Reliability |
|---|---|---|---|
| Daily trending searches | trending/rss (RSS/XML) | Hot queries, traffic estimate, linked news | High, returned 200 for me |
| Interest over time | api/widgetdata/multiline (JSON) | 0-100 index per time bucket | Medium, undocumented + rate-limited |
| Interest by region | api/widgetdata/comparedgeo (JSON) | 0-100 index per state/country | Medium, undocumented |
| Related topics / queries | api/widgetdata/relatedsearches (JSON) | Rising and top related terms | Medium, undocumented |
The takeaway: if you want today’s hot searches, the RSS feed is enough and it is stable. If you want the interest-over-time curve or related queries, you go through the widget API, which works but is unofficial and throttled. None of these returns absolute search volume; every index value is relative.
How does Google Trends block scrapers?
Google Trends stops naive scrapers with aggressive IP rate limiting and a token-gated API, not a login wall. When I requested the explore page with a normal browser User-Agent but no session cookie, the response was an immediate HTTP 429. Here is the proof from my run on June 12, 2026:
import requests
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
"(KHTML, like Gecko) Chrome/126.0 Safari/537.36"
r = requests.get(
"https://trends.google.com/trends/explore?q=python&geo=US",
headers={"User-Agent": UA}, timeout=25,
)
print("HTTP", r.status_code)
print("is 429 error page:", "Error 429" in r.text)
print("body length:", len(r.text))
HTTP 429
is 429 error page: True
body length: 1697
The 1697-byte body is Google’s “Too Many Requests” page, not trend data. Two walls cause this. First, the explore endpoint throttles clients that arrive without a valid session cookie, so the first request from a script often fails. Second, even past that, the actual numbers never sit in the page HTML: they load through the api/widgetdata/* endpoints, and each of those requires a one-time token minted by a prior api/explore call. Miss the token step and you get nothing. The good news is that priming a session with one homepage GET clears the cookie wall, which is exactly what Method 2 below does.
Method 1: Scrape the Google Trends RSS feed with Python (DIY)
The simplest DIY method that works is the daily trending RSS feed, parsed with requests and BeautifulSoup’s XML mode. It skips the cookie wall, needs no token, and returns structured XML, so it is the right starting point for a free scraper. The endpoint takes a geo country code:
| Goal | URL pattern |
|---|---|
| US trending searches | https://trends.google.com/trending/rss?geo=US |
| UK trending searches | https://trends.google.com/trending/rss?geo=GB |
| Any country | https://trends.google.com/trending/rss?geo=COUNTRY_CODE |
Each <item> carries the query, an approx_traffic estimate, a pubDate, a picture, and up to three linked news stories under Google’s ht: namespace. Here is the scraper:
import requests
from bs4 import BeautifulSoup
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
"(KHTML, like Gecko) Chrome/126.0 Safari/537.36"
URL = "https://trends.google.com/trending/rss?geo=US"
resp = requests.get(URL, headers={"User-Agent": UA}, timeout=25)
print("HTTP", resp.status_code, resp.headers["content-type"])
# Parse as XML so the ht: namespaced tags survive
soup = BeautifulSoup(resp.content, "xml")
items = soup.find_all("item")
print(f"Parsed {len(items)} trending searches\n")
for it in items[:8]:
title = it.title.get_text()
traffic = it.find("ht:approx_traffic")
traffic = traffic.get_text() if traffic else "n/a"
news = it.find_all("ht:news_item")
src = ""
if news:
s = news[0].find("ht:news_item_source")
src = s.get_text() if s else ""
print(f"{title} (traffic {traffic}, {len(news)} stories) - {src}")
I ran this on June 12, 2026. Real output:
HTTP 200 text/xml; charset=utf-8
Parsed 10 trending searches
novorossiya (traffic 1000+, 3 stories) - Institute for the Study of War
john davis (traffic 1000+, 3 stories) - People.com
thayne jasperson (traffic 500+, 3 stories) - People.com
antonio gracias (traffic 1000+, 3 stories) - The New York Times
amanda anisimova (traffic 1000+, 3 stories) - BBC
dark souls (traffic 1000+, 3 stories) - OpenCritic
draftkings (traffic 2000+, 3 stories) - Yahoo Sports
grow a garden 2 (traffic 1000+, 3 stories) - games.gg
That is a working free scraper: one GET, 10 real trending searches, each with a traffic band and its top news source. Two limits to plan around. First, the feed only covers today’s trending searches for one country; it carries no historical interest-over-time and no arbitrary keyword lookup. Second, approx_traffic is a coarse band (“1000+”, “2000+”), not a precise number. Install the dependencies with pip install requests beautifulsoup4 lxml (the xml parser needs lxml). For more on this stack, see my BeautifulSoup guide and the requests walkthrough.
Method 2: Scrape interest-over-time from the widget API (DIY)
To get the interest-over-time curve for a specific keyword, you call Google’s undocumented widget API in two steps: mint a token, then fetch the datapoints. This is the same flow the pytrends library wraps. It works, but it is unofficial and throttled, so handle it with care. The two steps:
GET api/explorewith your query JSON, which returns four widgets each carrying atokenand arequestpayload.GET api/widgetdata/multilinewith theTIMESERIESwidget’s token and request, which returns the 0-100 index per time bucket.
Both responses start with the XSSI guard )]}', so strip the first five characters before parsing JSON. Priming the session with one homepage request supplies the cookie that gets you past the 429.
import requests, urllib.parse, json
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
"(KHTML, like Gecko) Chrome/126.0 Safari/537.36"
s = requests.Session()
s.headers.update({"User-Agent": UA})
s.get("https://trends.google.com/trends/", timeout=25) # prime the cookie
# Step 1: explore -> tokens
req = ('{"comparisonItem":[{"keyword":"python","geo":"US",'
'"time":"today 12-m"}],"category":0,"property":""}')
url = "https://trends.google.com/trends/api/explore?hl=en-US&tz=0&req=" + urllib.parse.quote(req)
r1 = s.get(url, timeout=25)
print("explore:", r1.status_code)
widgets = {w["id"]: w for w in json.loads(r1.text[5:])["widgets"]}
ts = widgets["TIMESERIES"]
# Step 2: multiline -> interest over time
url2 = ("https://trends.google.com/trends/api/widgetdata/multiline?hl=en-US&tz=0&req="
+ urllib.parse.quote(json.dumps(ts["request"])) + "&token=" + ts["token"])
r2 = s.get(url2, timeout=25)
print("multiline:", r2.status_code)
points = json.loads(r2.text[5:])["default"]["timelineData"]
print("datapoints:", len(points))
for p in points[:3] + points[-3:]:
print(" ", p["formattedAxisTime"], "->", p["value"][0])
I ran this on June 12, 2026. Real output (first and last three weeks of the year):
explore: 200
multiline: 200
datapoints: 53
Jun 8, 2025 -> 69
Jun 15, 2025 -> 67
Jun 22, 2025 -> 69
May 24, 2026 -> 85
May 31, 2026 -> 55
Jun 7, 2026 -> 60
53 weekly datapoints on the 0-100 scale, exactly what the explore page would chart. The explore call also returns GEO_MAP, RELATED_TOPICS, and RELATED_QUERIES widgets, so the same token pattern pulls interest-by-region and related queries by swapping the second endpoint to comparedgeo or relatedsearches.
Now the honesty part. This API is undocumented and rate-limited. A cookieless burst earned the 429 you saw above. With a fresh session cookie I ran eight keyword lookups back to back and all eight returned 200, so a polite one-session-per-query pattern survives short runs. Push harder and Google throttles the IP. Plan for retries with backoff, rotate IPs for volume, and expect the token flow to change without notice. For the wider anti-block toolkit, see scraping without getting blocked, and for a structured crawler, Scrapy.
Method 3: Scrape Google Trends with a scraper API
A scraper API is the right tool when you need volume past one IP, or want to skip the token dance and rate-limit babysitting entirely. It carries the session cookie, rotates IPs, and returns the rendered result, so you avoid the 429 and the moving token flow. ChocoData exposes a universal endpoint plus dedicated endpoints, and you point it at the Trends URL:
import requests
resp = requests.get(
"https://api.chocodata.com/v1",
params={
"api_key": "YOUR_API_KEY",
"url": "https://trends.google.com/trends/explore?q=python&geo=US",
"render": "true", # execute the page JavaScript
"country": "us", # exit from a US IP
},
timeout=90,
)
print(resp.status_code)
data = resp.json() # rendered interest-over-time, related queries, geo map
I did not run this call (it needs a paid key), so I am not pasting fake output. What an API buys you over the DIY routes, by trade-off:
| Factor | RSS feed | Widget API (DIY) | Scraper API |
|---|---|---|---|
| Cost | Free | Free | Per-request, paid |
| Data | Today’s trends only | Any keyword, 0-100 index | Any keyword, rendered |
| Rate limits | Generous | Your IP gets throttled | Rotated pool |
| Token flow | None | You maintain it | Handled for you |
| Stability | High | Breaks on Google changes | Vendor maintains it |
| Best for | Daily hot-search monitoring | Light keyword research | Volume, hands-off pipelines |
Decision rule: if you only need daily trending searches, the free RSS scraper is enough and I would ship it. For occasional keyword curves, the widget API works as long as you stay polite. For steady volume, a team that cannot afford the token flow breaking, or related-query tables across many keywords, the API earns its cost by absorbing the rate limits and maintenance. Trends still gives you no absolute volume, so for that, pair it with a keyword tool.
What are the limits of scraping Google Trends?
The honest limits: no official API, a relative 0-100 index instead of real volume, sampled data, and an explore page that 429s plain requests. The trending RSS feed is stable but covers only today’s hot searches for one country. The widget API reaches any keyword’s interest-over-time and related queries, but it is undocumented, throttled, and free to change whenever Google ships a release. None of the endpoints returns absolute search counts: every value is normalized to the peak in your chosen range and region, and because it is drawn from a sample, two pulls of the same query can differ a few points. Build on RSS for free trend monitoring, layer the widget API for light keyword research with retries and backoff, reach for a scraper API when you need volume or a hands-off pipeline, and anchor the index against a known keyword volume when you need real numbers.
FAQ
Partly. pytrends wraps the same undocumented widget API I test below, so when Google does not rate-limit you it returns interest-over-time and related-query data. It breaks whenever Google changes the token flow or throttles your IP, and it has no official support. Treat it as a convenience wrapper over an endpoint that can change without notice, not a stable API.
No. Each series is normalized to a 0-100 index where 100 is the peak interest in the selected range and region, then divided by total searches to remove popularity bias. A value of 50 means half the peak, not a search count. To turn the index into estimated absolute volume you anchor it against a keyword whose real volume you know from a keyword tool.
Google Trends is built from a sample of searches, and the sample is drawn fresh per request, so the curve wobbles a few points between pulls. For stable figures, average several pulls or use a longer time range, and treat single-digit differences as noise rather than signal.