If you've used pytrends for anything bigger than a handful of keywords, you know how it goes. The first ten requests are fine, then TooManyRequestsError: The request failed: Google returned a response with code 429, then you add time.sleep(60), then you start looking at proxy providers.
And now there's a second problem. The pytrends repo on GitHub was archived in April 2025, and its last code push was in August 2024. It still installs, but nobody is fixing it when Google changes something.
So what are the options in 2026?
Option 1: keep pytrends and slow down
This still works for small jobs. Keep one keyword per request, sleep between calls, and back off hard when you see a 429. For 20 keywords a week it's fine. For 500 keywords, or anything on a schedule, you'll spend more time babysitting it than using the data. You're also sending every request from your own IP, which is why the 429s show up so fast.
Option 2: Google's official Trends API
Google announced an official Trends API in July 2025. At the time of writing it's an alpha for a limited group of testers, and there's no public sign-up. Worth applying if you have a real use case, but you can't build on it today.
Option 3: a hosted scraper you call like an API
This is what I ended up building, so take this section with that in mind: I made the Google Trends Scraper on Apify for exactly this problem. You send a list of keywords, it handles the proxies and retries on its side, and you get one row per keyword back. You never deal with a 429.
Here's the whole thing in Python. pip install apify-client, then grab an API token from the Apify Console (Settings > API & Integrations).
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("meridianlabs/google-trends-scraper").call(run_input={
"keywords": ["halloween costume", "pickleball", "air fryer", "standing desk"],
"geo": "US",
"timeRange": "past_5_years",
})
for row in client.dataset(run.default_dataset_id).iterate_items():
print(row["keyword"], "|", row["summary"]["text"])
That's apify-client 3.x. On 2.x use run["defaultDatasetId"].
I ran exactly that today (30 September 2026). It took about 20 seconds for all four:
halloween costume | Interest is rising (+391% vs the previous 13 weeks); up 3% year on year. Peak: October 2021. Seasonal: peaks every October. Fastest-rising related search: '2024 halloween costume ideas' (Breakout).
pickleball | Interest is falling (-29% vs the previous 13 weeks); down 2% year on year. Peak: April 2026. Fastest-rising related search: 'joola pickleball paddle' (Breakout).
air fryer | Interest is falling (-20% vs the previous 13 weeks); up 11% year on year. Peak: January 2022. Fastest-rising related search: 'shop air fryer deals' (Breakout).
standing desk | Interest is falling (-66% vs the previous 13 weeks); up 29% year on year. Peak: April 2026. Fastest-rising related search: 'vernal standing desk' (Breakout).
(Google Trends samples its data, so a second run a few minutes later gave standing desk -65% and +31%. Expect the odd point of drift between runs; the direction doesn't change.)
The raw data is still there. Each row has the full interestOverTime series, interestByRegion and relatedQueries (top and rising), same as pytrends. The summary line is the part I added, because with 500 keywords I don't want 500 charts. I want to know which ones are going up right now.
Moving pytrends code over
| pytrends | This |
|---|---|
interest_over_time() |
row["interestOverTime"] |
interest_by_region() |
row["interestByRegion"] |
related_queries() |
row["relatedQueries"] |
timeframe='today 5-y' |
"timeRange": "past_5_years" |
geo='US' |
"geo": "US" (same codes, including US-CA) |
build_payload(kw_list=[...5 terms]) to compare |
"compareKeywords": true, in groups of up to 5 (Google's limit), as many groups as you like |
Every data type comes back in one lookup, so there's no separate request per method like with pytrends.
Filtering 500 keywords down to the ones that matter
The summary is also split into plain fields, so you can filter without parsing text: momentum (rising, falling or stable), recentChangePct, yearOnYearChangePct, seasonal, seasonalPeakMonth, peakDate and topRisingQuery.
I put a small script on GitHub that reads keywords.txt, writes everything to a CSV and prints the rising and seasonal ones: pytrends-alternative. The core of it:
rows = [{"keyword": i["keyword"], **i["summary"]}
for i in client.dataset(run.default_dataset_id).iterate_items()]
rising = [r["keyword"] for r in rows if r["momentum"] == "rising"]
seasonal = [(r["keyword"], r["seasonalPeakMonth"]) for r in rows if r["seasonal"]]
On my four test keywords that prints Rising now: halloween costume and Seasonal: halloween costume (October), which is what you'd hope for at the end of September.
What it costs, and what it can't do
It's $0.005 per keyword lookup, so 1,000 keywords is $5, and failed lookups aren't charged. Apify's free plan includes $5 of usage a month, which covers about 1,000 lookups, so you can try it on a real list before paying anything.
Things it won't do:
- Related topics. Google doesn't return these to automated lookups, so only related searches (queries) come back.
- City-level regions. Countries, states and US metro areas work. Cities don't.
- Absolute search volume. Google Trends is a 0 to 100 index, not search counts. If you need monthly volumes, you need a Keyword Planner-type source instead.
-
Brand-new or tiny terms can come back as
no_data. That's Google having nothing, not an error.
If you're still on pytrends and it's working for your volume, there's no reason to switch. If you're fighting 429s or building something that runs on a schedule, this is the setup I'd use.
Top comments (0)