On 2026-08-06, "nike" returned four different stories under one Trends API key. Google Search score 58.0 fell -35.56% over 3M with estimated volume 19,900,000. Amazon score 58.7 barely moved (-1.34% over 3M) with 19,433,404 recent volume. YouTube rose to 47.0 (+2.17% over 3M). TikTok sat at 28.4 with +82.05% over 7D and 12,038,473 recent volume, while 3M and 12M TikTok presets failed with date_out_of_range. This post wires those calls in Python against POST https://api.trendsapi.ai/api, including the double parse of the body string. For the evergreen SerpApi trends alternative framing, see SerpApi trends alternative.

Why one brand needs more than Google Search

A Google-only scrape can show search interest cooling while commerce stays flat and short-form video spikes. That split changes inventory and creative decisions. Trends API exposes the split as separate source values on the same auth path. Source docs for shopping and video live at Amazon Trends and YouTube Trends.

Pricing reminder for capacity planning: free tier 100 successful requests per month, Starter 5,000, Pro 25,000, Business 100,000. Only 200 responses count.

Step 1: shared client with double body parse

import json
import os
import urllib.request

API = "https://api.trendsapi.ai/api"
KEY = os.environ["TRENDSAPI_API_KEY"]

def trends_api(payload: dict) -> dict:
    req = urllib.request.Request(
        API,
        data=json.dumps(payload).encode(),
        headers={
            "Authorization": f"Bearer {KEY}",
            "Content-Type": "application/json",
        },
        method="POST",
    )
    envelope = json.loads(urllib.request.urlopen(req).read().decode())
    # body is a JSON string; parse it again
    return json.loads(envelope["body"])

Every successful envelope looks like {"statusCode": 200, "body": "..."}. Skipping the second parse is the usual failure mode in new clients.

Step 2: Google Search and Amazon growth side by side

google = trends_api({
    "mode": "get_growth",
    "source": "google search",
    "keyword": "nike",
    "percent_growth": ["3M", "12M"],
})
amazon = trends_api({
    "mode": "get_growth",
    "source": "amazon",
    "keyword": "nike",
    "percent_growth": ["3M", "12M"],
})
print(google["results"])
print(amazon["results"])

Live results from 2026-08-06:

Source Period Recent date Recent value Baseline value Growth Recent volume
google search 3M 2026-08-01 58.0 90.0 -35.56% 19,900,000
google search 12M 2026-08-01 58.0 68.0 -14.71% 19,900,000
amazon 3M 2026-07-31 58.7 59.5 -1.34% 19,433,404
amazon 12M 2026-07-31 58.7 59.0 -0.51% 19,433,404

Google Search volume on this source is estimated from the trend value. Amazon volume is independent: 3M volume growth was -1.27%, 12M volume growth was -0.42%. Search cooled harder than commerce.

Step 3: YouTube for creative demand

youtube = trends_api({
    "mode": "get_growth",
    "source": "youtube",
    "keyword": "nike",
    "percent_growth": ["3M", "12M"],
})
for row in youtube["results"]:
    print(row["period"], row["recent_value"], row["growth"])

YouTube returned score-only rows: 47.0 recent value, +2.17% over 3M (baseline 46.0 on 2026-05-02), and +4.44% over 12M (baseline 45.0 on 2025-08-02). Both calculations used 261 data points. Video interest edged up while Google Search fell, which is a useful alert for creative teams even without absolute volume.

Step 4: TikTok short windows and honest failures

tiktok_long = trends_api({
    "mode": "get_growth",
    "source": "tiktok",
    "keyword": "nike",
    "percent_growth": ["3M", "12M"],
})
tiktok_short = trends_api({
    "mode": "get_growth",
    "source": "tiktok",
    "keyword": "nike",
    "percent_growth": ["7D", "14D"],
})
print(tiktok_long["results"])
print(tiktok_short["results"])

Long presets failed. Each error row reported date_out_of_range with data_start 2026-07-06 and data_end 2026-08-04 across 30 points. Short presets succeeded:

Period Recent date Recent value Baseline date Baseline value Growth Recent volume Volume growth
7D 2026-08-04 28.4 2026-07-28 15.6 +82.05% 12,038,473 +10.6%
14D 2026-08-04 28.4 2026-07-21 13.2 +115.15% 12,038,473 +12.84%

Treat unavailable long history as a first-class result. Retry with 7D and 14D instead of inventing a 3M number.

Step 5: optional live boards for context

board = trends_api({
    "mode": "get_top_trends",
    "type": "Google Trends",
    "limit": 15,
})
for rank, label in board["data"]:
    print(rank, label)

As of 2026-08-06T10:01:38+00:00 the board count was 15. Top labels included "perez hilton" at rank 1, "abdul el-sayed" at 2, "spokane fires" at 3, and "spirit halloween" at 9. Nike was not on that 15-row board, which is expected for a steady brand; growth calls still matter when the live list is news-heavy.

Amazon Best Sellers Top Rated (as_of 2026-08-03T04:01:36+00:00) opened with Amazon Basics AA batteries at rank 1, AAA batteries at 2, and Crocs Classic Clog at 3. That board is a category scan, not a Nike brand series, but it shows how get_top_trends feeds discovery while get_growth measures a known SKU or brand.

Step 6: compare a product keyword the same way

Brand labels and product labels do not always move together. AirPods on the same pull date shows a sharper Amazon decline than Nike.

air_amz = trends_api({
    "mode": "get_growth",
    "source": "amazon",
    "keyword": "airpods",
    "percent_growth": ["30D", "3M", "6M", "12M"],
})
air_web = trends_api({
    "mode": "get_growth",
    "source": "google search",
    "keyword": "airpods",
    "percent_growth": ["3M", "12M"],
})

Amazon AirPods score was 29.7 on 2026-07-31 with 6,377,787 recent volume. Windows: 30D -15.86% (baseline 35.3, volume 7,580,965), 3M -5.11% (baseline 31.3), 6M -17.04% (baseline 35.8), 12M -47.71% (baseline 56.8, volume 12,188,687). Google Search AirPods sat at 54.0 (-18.18% over 3M from baseline 66.0, +3.85% over 12M from baseline 52.0) with estimated volume 8,510,000. Nike commerce was nearly flat; AirPods commerce fell almost half over 12M. Keep product and brand keywords in separate cron rows.

Step 7: flatten results for a daily job

def flatten(keyword: str, payload: dict, pull_date: str) -> list[dict]:
    rows = []
    for row in payload.get("results", []):
        rows.append({
            "keyword": keyword,
            "source": payload.get("data_source") or row.get("data_source"),
            "period": row.get("period"),
            "status": row.get("status"),
            "recent_date": row.get("recent_date"),
            "recent_value": row.get("recent_value"),
            "baseline_value": row.get("baseline_value"),
            "growth": row.get("growth"),
            "recent_volume": row.get("recent_volume"),
            "volume_growth": row.get("volume_growth"),
            "error": row.get("error"),
            "pull_date": pull_date,
        })
    return rows

pull_date = "2026-08-06"
out = []
for source, periods in [
    ("google search", ["3M", "12M"]),
    ("amazon", ["3M", "12M"]),
    ("youtube", ["3M", "12M"]),
    ("tiktok", ["7D", "14D"]),
]:
    body = trends_api({
        "mode": "get_growth",
        "source": source,
        "keyword": "nike",
        "percent_growth": periods,
    })
    # get_growth single-source responses include data_source at the top level
    if isinstance(body, dict) and "data_source" not in body:
        body = {"data_source": source, "results": body.get("results", body)}
    out.extend(flatten("nike", body, pull_date))

print(len(out), "rows")
for r in out:
    print(r["source"], r["period"], r["status"], r["growth"], r["recent_volume"])

Expect eight Nike rows when every short and long window succeeds on Google Search, Amazon, and YouTube, plus TikTok 7D and 14D. If TikTok long windows are still in the request list, add two error rows with status error and keep them. Downstream SQL can filter status = 'success' for charts and keep failures for coverage monitoring.

What to store and which alerts to fire

Persist one row per source and period: keyword, source, period, recent_date, recent_value, growth, recent_volume, pull_date. For this session the pull_date is 2026-08-06. Useful alert rules from the Nike snapshot:

  1. Google Search 3M growth below -30% while Amazon 3M growth stays inside ±5%. That is the search-cooled, commerce-stable pattern (-35.56% vs -1.34%).
  2. TikTok 7D growth above +50% with recent volume above 10,000,000. Nike cleared that bar at +82.05% and 12,038,473 volume.
  3. Any TikTok row with error = date_out_of_range. Log the data_start and data_end fields (here 2026-07-06 to 2026-08-04) and automatically retry with 7D and 14D.
  4. YouTube 12M growth positive while Google Search 12M growth negative (+4.44% vs -14.71%). Creative demand can rise while web search cools.

Quota math for this job: four successful get_growth calls for Nike, optional two for AirPods, optional one get_top_trends board. That is 5 to 7 successful requests per run. Daily cron stays under the free tier 100 requests per month if the keyword list stays short. Starter 5,000 covers larger brand lists.

Related reading

If the goal is swapping a SerpApi Google Trends scraper for this multi-source client, start from the mode map on SerpApi trends alternative. For a seasonal retail example that begins on the Google Trends board, see Spirit Halloween demand sensing in Python. For Google-only framing without SerpApi, see Google Trends API alternative.