Proxies and rate limits
Google rate-limits Trends by exit IP. Rotate through a proxy pool, and understand why rotation happens per query rather than per request.
Using a proxy pool
Pass a list of proxy URLs and the client rotates through them automatically, moving to the next one whenever a query is refused:
import trendflow
from trendflow import Region
tf = trendflow.Client(
proxies=[
"http://user:pass@gate.decodo.com:7000",
"http://user:pass@gate.decodo.com:7000",
],
max_proxy_attempts=3, # defaults to the pool size, capped at 5
on_proxy_rotate=lambda attempt, error: print(f"rotated after {attempt}: {error!r}"),
)
trending = tf.trending_now(Region.US)
print(tf.current_proxy) # the proxy that answered
Entries are just URLs, so a pool can mix providers. Repeating one rotating gateway also works: each entry gets its own connection, so it lands on a fresh exit IP.
Rotation happens per query, not per request — this matters. Google binds the NID
cookie and the widget token to the IP that requested them, so a single query must complete
on one exit IP; sending the follow-up widgetdata call from a different IP earns an instant
429. The pool pins one proxy for the whole query and advances only on failure, re-seeding
the cookie jar each time. For the same reason, point the pool at sticky sessions rather
than per-request rotating endpoints if your provider offers the choice.
Rotation is skipped for errors a different IP cannot fix, such as a 404 or a renamed RPC.
Where to get proxies
Residential proxies are what actually clears Google's 429. Verified against this library:
| Provider | Notes | Endpoint format |
|---|---|---|
| Decodo (formerly Smartproxy) | Cheapest entry tier; pay-as-you-go available. Used to verify this library's live tests. | http://user:pass@gate.decodo.com:7000 |
Ask for sticky sessions when you sign up — per-request rotating endpoints break the
cookie/token binding described above. Note that a shared residential pool can be exhausted
for Google Trends specifically, in which case even a valid proxy returns 429; that is what
max_proxy_attempts is for.
