DEV Community

anassBld
anassBld

Posted on

pytrends is archived: fixing Google Trends 429 errors in 2026

If you have a script that starts with from pytrends.request import TrendReq, you have probably seen this lately:

pytrends.exceptions.TooManyRequestsError: The request failed: Google returned a response with code 429
Enter fullscreen mode Exit fullscreen mode

pytrends was archived on April 17, 2025. Its last release (4.9.2) is from April 2023. It still gets about 900,000 downloads a month on PyPI, so a lot of notebooks, dashboards and cron jobs are quietly failing.

Here is what actually breaks, what you can fix yourself, and the replacement I ended up building.

Why pytrends gets 429s

Google Trends has no public API. pytrends calls the same internal endpoints the website uses (/trends/api/explore, then widgetdata/multiline, comparedgeo, relatedsearches). Each build_payload costs one explore call plus one call per widget you read, so a single keyword with timeline, regions and related queries is 4 requests.

Google rate-limits those endpoints per IP and per cookie. From a laptop you get maybe a few dozen requests before the 429s start. From a cloud VM or Colab, often zero, because those IP ranges are already burned.

Fixes that work if you want to stay DIY

  1. New session on every 429. The block is partly tied to the NID cookie. Retrying with the same requests.Session keeps failing; a fresh session (fresh cookie) plus backoff often works.
  2. Rotate IPs, not just time. Sleeping 60 seconds on the same datacenter IP rarely helps. Residential IPs work much better than datacenter ones.
  3. Ask for less. If you only need the timeline, skip interest_by_region() and related_queries(): that is 2 requests instead of 4.
  4. Cache by day. Google serves the same sample for the same query within a day, so re-requesting it gives you nothing new.

The 5-keyword limit, and how to get around it

Trends compares at most 5 terms, and everything is scaled 0-100 relative to the biggest one. The usual trick for more keywords is an anchor: put the same keyword in every batch of 4, then rescale each batch by the anchor's ratio.

# batch A: anchor + a1..a4, batch B: anchor + b1..b4
scale = mean(anchor_in_A) / mean(anchor_in_B)
b_rescaled = [v * scale for v in b_values]
Enter fullscreen mode Exit fullscreen mode

The catch: Google rounds to whole numbers. Next to iphone, a niche keyword shows 0 or 1, and its rescaled value is mostly rounding noise. The fix is to sort keywords by rough size and compare each one with neighbours of similar size, then chain those ratios. In my tests, chained ratios matched direct head-to-head measurements within about 1% for most pairs, and within about 7% for a keyword 400 times smaller than its neighbour.

What I built: pytrends-ng

I got tired of maintaining retry and proxy code, so I put all of the above into a hosted Google Trends actor on Apify and wrote a small client with the same API as pytrends:

# pip install pytrends-ng
from pytrends_ng import TrendReq   # was: from pytrends.request import TrendReq

pytrends = TrendReq(hl="en-US", tz=360)   # reads APIFY_TOKEN from the environment
pytrends.build_payload(["chatgpt", "claude", "gemini"], timeframe="today 3-m", geo="US")

print(pytrends.interest_over_time().tail(3))
print(pytrends.related_queries()["claude"]["rising"].head(3))
Enter fullscreen mode Exit fullscreen mode

Real output from today:

            chatgpt  claude  gemini  isPartial
date
2026-10-09       66      20      30      False
2026-10-10       49      15      21      False
2026-10-11       52      16      23      False

                                          query   value formattedValue
0  codex vs claude code abraham quiros villalba     NaN       Breakout
1                                           jev  3400.0        +3,400%
2                              claude haiku 5.5  1150.0        +1,150%
Enter fullscreen mode Exit fullscreen mode

Differences from the original:

  • No 5-keyword limit. Pass 50 keywords to build_payload and they all come back on one shared scale, using the neighbour-chaining above.
  • One request per payload. interest_over_time, interest_by_region and related_queries all read from the same run.
  • formattedValue keeps Google's text such as Breakout, so value stays numeric.
  • related_topics() and suggestions() are not supported yet.

It is not free: it costs $2 per 1,000 results, where one result is one keyword in one country with its timeline, regions and related queries. A free Apify account includes $5 of credit a month, which covers about 2,500 keywords. It is not instant either: each new payload takes around 30 seconds, mostly container startup, and the other methods on that payload then reuse the result. Fine for notebooks and daily jobs, not for a live UI.

The client is MIT-licensed and small enough to read in five minutes: github.com/anassk01/pytrends-ng. If your pytrends code uses a call it does not support yet, open an issue and I will add it.

Top comments (0)