Metadata-Version: 2.5
Name: trendreq
Version: 0.1.0
Summary: Drop-in pytrends replacement: the same TrendReq API for Google Trends, without 429 errors. Runs on Apify.
Project-URL: Homepage, https://github.com/CleanScrape/trendreq
Project-URL: Documentation, https://github.com/CleanScrape/trendreq#readme
Project-URL: Issues, https://github.com/CleanScrape/trendreq/issues
Project-URL: Google Trends Actor, https://apify.com/cleanscrape/google-trends-scraper
Author-email: CleanScrape <contact.cleanscrape@gmail.com>
License: MIT
License-File: LICENSE
Keywords: 429,apify,google trends,google trends api,keyword research,pytrends,pytrends alternative,seo,trendreq
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Requires-Python: >=3.9
Requires-Dist: pandas>=1.3
Requires-Dist: requests>=2.25
Description-Content-Type: text/markdown

# trendreq: a drop-in pytrends replacement

pytrends was archived in April 2025, and it now fails with `429 Too Many Requests` errors for most people. `trendreq` keeps the same `TrendReq` interface, so your existing scripts keep working. The requests run on the [CleanScrape Google Trends Actor](https://apify.com/cleanscrape/google-trends-scraper) on Apify, with proxies and retries on the server side.

```python
# from pytrends.request import TrendReq   # before
from trendreq import TrendReq              # after

pytrends = TrendReq(hl="en-US", tz=360)
pytrends.build_payload(["iced coffee", "cold brew"], timeframe="today 12-m", geo="US")
df = pytrends.interest_over_time()
```

```
            iced coffee  cold brew  isPartial
date
2026-09-20           47         51      False
2026-09-27           42         49      False
2026-10-04           32         33       True
```

## Install

```bash
pip install trendreq
```

Then set your Apify API token. A free Apify account includes $5 of usage a month. Copy the token from [Apify Console > Settings > API & Integrations](https://console.apify.com/settings/integrations).

```bash
export APIFY_TOKEN=your_token          # macOS / Linux
setx APIFY_TOKEN your_token            # Windows (open a new terminal afterwards)
```

You can also pass it in code with `TrendReq(apify_token="...")`. Keep the token out of shared notebooks and repositories.

## Moving from pytrends

| pytrends method | trendreq | Notes |
|---|---|---|
| `build_payload(kw_list, cat, timeframe, geo, gprop)` | Same | Up to 5 keywords. `gprop` (YouTube, News, Images, Shopping) is not supported yet. |
| `interest_over_time()` | Same shape | Date index (UTC), one int column per keyword, `isPartial`. |
| `interest_by_region(resolution, inc_low_vol, inc_geo_code)` | Same shape | `COUNTRY`, `REGION`, `CITY` and `DMA` (US metro areas). City rows also get `latitude` and `longitude`, so towns with the same name stay apart. With a country chosen, `COUNTRY` gives its regions, as pytrends does. |
| `related_queries()` | Same shape | `{keyword: {"top": DataFrame, "rising": DataFrame}}` with `query` and `value`. |
| `related_topics()` | Same shape | Google currently returns no related topics for automated requests (pytrends gets the same), so this gives `None` with a warning. |
| `trending_searches(pn)` | Same shape | `pn` can be a pytrends country name (`"united_kingdom"`) or a code (`"GB"`). |
| `today_searches(pn)` | Same | A Series of today's trending searches. |
| `realtime_trending_searches(pn)` | Similar | Columns: `title`, `approxTraffic`, `pubDate`, `relatedNews`. |
| `suggestions()`, `categories()`, `top_charts()` | Not available | They raise `NotImplementedError` with an explanation. |

Exceptions keep pytrends' names: `ResponseError` and `TooManyRequestsError` (raised only if Google still limits the request after the server-side retries). `retries=` re-runs a rate-limited data type.

Time ranges work as in pytrends: `"today 5-y"`, `"today 12-m"`, `"today 3-m"`, `"now 7-d"`, `"now 1-d"`, `"all"`, or exact dates such as `"2024-01-01 2024-06-30"`. Regions take codes such as `"US"`, `"US-CA"` or `"DE"`.

Settings that only made sense for direct requests (`proxies`, `timeout`, `backoff_factor`, `requests_args`) are accepted and ignored, so you don't need to change your constructor call.

## Extras pytrends doesn't have

**One run for several data types.** Each method call starts one Apify run. To collect several data types for the same keywords, call `fetch()` first. It saves the per-run start fee:

```python
pytrends.build_payload(["bitcoin", "ethereum"], timeframe="today 5-y")
pytrends.fetch("interest_over_time", "related_queries", "interest_by_region")
over_time = pytrends.interest_over_time()     # no new run
related = pytrends.related_queries()          # no new run
```

**Trending searches with context.** `pytrends.trending_now("US")` returns rank, approximate traffic, publish time and related news headlines.

**Spending cap.** `TrendReq(max_charge_usd=0.50)` stops any single run at 50 cents.

## What it costs

You pay Apify for the Actor's results, at the [Actor's current price](https://apify.com/cleanscrape/google-trends-scraper/pricing). At the base price that is $0.05 per run plus $0.003 per row, with discounts on paid Apify plans. Some examples at base prices:

| Job | Rows | Cost |
|---|---:|---:|
| 2 keywords, 12 months, weekly (`interest_over_time`) | 106 | about $0.37 |
| 1 keyword, US states (`interest_by_region`) | 51 | about $0.20 |
| 2 keywords, time series + states + related queries in one `fetch()` | 102 | about $0.36 |
| Today's trending searches for one country | 10 | about $0.08 |

The free $5 monthly credit covers roughly 15 to 60 typical calls.

## Why pytrends fails with 429 errors

Google Trends has no official public API. pytrends sends requests from your own IP address, first to get a short-lived token and then to fetch each chart. Google limits how often one address can do that, so scripts that loop over keywords quickly hit `429 Too Many Requests`. Waiting, rotating proxies by hand and lowering the request rate only helps for a while. trendreq moves those requests to Apify, where the Actor rotates residential proxies and retries for you.

## Limits

- Values are relative interest from 0 to 100 within your comparison, the same as on the Google Trends website. They are not search counts.
- Results can differ slightly between runs, as they do on the website, because Google samples its data.
- Each method call is one Apify run and takes about 5 to 30 seconds. Use `fetch()` to collect several data types at once.
- Related topics are currently empty, because Google returns none for automated requests.

## Testing

```bash
python -m unittest discover -s tests
```

The tests run offline against real rows saved from the Actor, so they need no token.

## About

trendreq is maintained by [CleanScrape](https://apify.com/cleanscrape). It is not affiliated with Google or with the pytrends project. MIT licence.

Bugs and ideas: [open an issue](https://github.com/CleanScrape/trendreq/issues) or email contact.cleanscrape@gmail.com.
