Google Trends data in Python is a requests POST, not a scrape client. Send mode get_growth or get_time_series with source google search and a keyword. The envelope is {"statusCode": int, "body": string}. body is a JSON string and must be parsed a second time. pytrends is archived and talks to the website. This call talks to https://api.trendsapi.ai/api with a Bearer key. Field names live on the API reference. Plan limits live on pricing. Source notes for Google live on the Google Trends guide.

Install requests, skip pytrends

pip install requests

That is the dependency for this tutorial. Do not add pytrends, a browser driver, or a cookie helper to make Google Trends load. Official pip install trendsapi is on the SDK hub and is not a TrendReq clone. The product MCP server at https://api.trendsapi.ai/mcp exposes the same modes if the runtime is an agent instead of a script.

One POST for source google search

import json
import os
import requests

resp = requests.post(
    "https://api.trendsapi.ai/api",
    headers={
        "Authorization": f"Bearer {os.environ['TRENDSAPI_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={
        "mode": "get_growth",
        "source": "google search",
        "keyword": "air fryer",
        "percent_growth": ["3M", "12M"],
    },
    timeout=60,
)
resp.raise_for_status()
outer = resp.json()
inner = json.loads(outer["body"])

A live pull on 2026-08-27 for air fryer on google search returned a 3M point-to-point change of -18.84 percent (56.0 vs 69.0) and a 12M change of +16.67 percent (56.0 vs 48.0). volume came back estimated. volume_growth was omitted because volume is derived from the trend value on this source.

Parse statusCode then parse body

outer["statusCode"] is the HTTP-like code for the inner job. outer["body"] is still a string after resp.json(). json.loads on that string is the second parse. Only then do results or a time series exist as objects. A 401 or 429 on the outer response is a key or burst problem, not a Trends website cookie miss.

What a DataFrame still has to do

get_time_series is the mode that returns dated points for a chart. get_growth is the mode that returns named windows. pytrends interest_over_time() mixed those jobs into one DataFrame. After the second parse, pick the columns the chart actually needs. Do not expect isPartial or a gprop column. YouTube or Images are other source strings on a new POST, not a gprop flag on this one.