pytrends-next
A maintained drop-in replacement for pytrends, which was archived
(read-only) in April 2025. Same TrendReq API, same DataFrames, talks to Google Trends directly.
- Standard library only. pandas is optional: with pandas you get the same DataFrames as pytrends, without it you get lists of dicts.
- Python 3.9+.
- Built-in handling of HTTP 429: new cookie session and exponential backoff with jitter.
- Optional, paid, off by default: route a call through a hosted scraper when Google keeps answering 429.
pip install "pytrends-next[pandas]" # or: pip install pytrends-next (no pandas)
from pytrends_next.request import TrendReq # was: from pytrends.request import TrendReq
pytrends = TrendReq(hl="en-US", tz=360)
pytrends.build_payload(["coffee", "tea"], timeframe="today 3-m", geo="US")
print(pytrends.interest_over_time().head(3))
# coffee tea isPartial
# date
# 2026-07-23 75 35 False
# 2026-07-24 81 38 False
# 2026-07-25 94 40 False
For most code the migration is one search and replace: pytrends. to pytrends_next. in imports.
pytrends_next.exceptions has the same ResponseError and TooManyRequestsError.
Moving from pytrends
| pytrends 4.9.2 | pytrends-next | Notes |
|---|---|---|
TrendReq(hl, tz, geo, timeout, proxies, retries, backoff_factor, requests_args) |
same | timeout tuple: the larger value is used (urllib has one timeout). requests_args: headers, proxies and verify are used, other keys are ignored with a warning. retries defaults to 3 (pytrends: 0). |
build_payload(kw_list, cat, timeframe, geo, gprop) |
same | Lists of geos and timeframes work as in pytrends. |
interest_over_time() |
same | Index date, one int column per keyword, isPartial. MultiIndex columns for several geos. |
interest_by_region(resolution, inc_low_vol, inc_geo_code) |
same | pytrends' check meant to apply resolution worldwide and for sub-levels never matched; here it does. |
related_queries() |
same | {kw: {"top": DataFrame[query, value] or None, "rising": ...}} |
related_topics() |
same | Google now returns topics only for single-term requests, so each term is asked alone. Often empty, see Limits. |
trending_searches(pn="united_states") |
same | The old endpoint is gone. Now served from Google's "Trending now" list. pn takes the pytrends country name or an ISO code ("US"). |
today_searches(pn="US") |
same | Series of titles, past 24 hours. |
realtime_trending_searches(pn, cat, count) |
same | Trends started in the past 4 hours, columns entityNames, title. cat is ignored. |
suggestions(keyword) |
same | |
categories() |
same | |
top_charts() |
raises NotImplementedError |
Google removed the endpoint. |
multirange_interest_over_time() |
raises NotImplementedError |
Not ported yet. |
| (none) | trending_now(geo="US", hours=24) |
New. Rows with title, volume, increase_percentage, started, ended, active, categories, related_queries. hours: 4, 24, 48 or 168. Falls back to the Trending RSS feed if the main endpoint changes. |
HTTP 429 (TooManyRequestsError)
Google Trends has no public API. It rate-limits by IP and by session, and a laptop or a single
server often gets HTTP 429 after a few dozen requests. pytrends raised TooManyRequestsError at once.
pytrends-next does what our hosted scraper does on every request:
- Visits trends.google.com first to get the
NIDcookie a browser visitor has (cookieless clients are limited sooner). - On 429, 403 or 5xx: drops the session, takes the next proxy from
proxies=[...]if you gave any, waits about 0.75 s, 1.5 s, 3 s ... (capped at 30 s, with jitter) and tries again,retriestimes. - 400 and 404 are not retried (bad geo, category or timeframe).
If you still get TooManyRequestsError: send fewer requests (batch up to 5 terms per build_payload),
wait a few minutes, use your own proxies, or use the hosted fallback below.
Hosted fallback (optional, paid)
pytrends = TrendReq(fallback="apify", apify_token="apify_api_...") # or set APIFY_TOKEN
When Google still answers 429 after the local retries, the same call is sent to the Google Trends Scraper Actor on Apify, which rotates IPs on Apify's proxy network. The result comes back in the same shape.
- It costs money. The Actor is billed per result to your own Apify account (about $1.50 per 1,000 results; one result is one term's timeline, one term's region list, one term's related list or one trending topic). Apify's free plan includes a small monthly credit.
- It is never on by default. Setting
APIFY_TOKENalone does nothing; you must passfallback="apify". - A warning is logged (logger
pytrends_next) every time a call goes to the Actor. - If
build_payloaditself gets 429, every method on that payload goes to the Actor. - Supported:
interest_over_time,interest_by_region,related_queries,related_topics,trending_nowand the pytrends trending methods. Not supported: several geos or timeframes in one payload, commas inside a keyword,suggestions,categories. - Difference: in hosted mode each term's region map is scaled on its own (locally, the terms share one scale).
- Timeframes: the named ranges (
now 1-Htotoday 5-y,all) andYYYY-MM-DD YYYY-MM-DD. Others are rejected before a run starts.
Disclosure: Ctrio Lab maintains this library and also builds and sells that Actor. The library is MIT licensed and fully works without it.
Limits
- Values are relative (0 to 100) within one payload, as on trends.google.com. Separate calls are not on the same scale.
- Related topics are usually empty: Google hides them from clients it classifies as automated. Empty lists come back as
None, like pytrends. - Very small search volumes come back as all zeros (Google's own behaviour).
- This is an unofficial client for undocumented endpoints. Google can change them at any time.
Legacy single-file client
gtrends.py (the earlier version of this repo) is still here and unchanged. It calls the hosted Actor for
every request. New code should use pytrends_next.request.TrendReq: gtrends.interest_over_time_df(terms, ...)
becomes build_payload(terms, ...) plus interest_over_time().
Development
python -m unittest discover -s tests # no network, recorded responses in tests/fixtures
python tests/live_smoke.py # about 12 live requests to Google
License
MIT. See LICENSE.
Metadata
Release files for pytrends-next 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| pytrends_next-0.1.0.tar.gz | 18.0 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pytrends_next-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 34.1 kB
Release files / pytrends_next-0.1.0.tar.gz
| Download URL | pytrends_next-0.1.0.tar.gz |
|---|---|
| Size | 18.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f79f9fda723367395a91de4b4d68f6d170166e73ffebe38444374d4efeb28aee
|
|
BLAKE2b-256 checksum How to use checksums |
aec169080d25cc131ba0b74c93a90680e5d0804baa065f7a46f784c0b4097a9a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.12
|
Release files / pytrends_next-0.1.0-py3-none-any.whl
| Download URL | pytrends_next-0.1.0-py3-none-any.whl |
|---|---|
| Size | 16.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f8d5c9816854e1ee99d41166d1ec57d185d8ad12dab1215cbe4d97dd53b89cc1
|
|
BLAKE2b-256 checksum How to use checksums |
25805b372a389b5c4442c69788c0c38dcf090a3ea4138251fdbdaac5c391a7e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.12
|
Security for pytrends-next 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.