TikTok Shop Hot Products ranked a 140 microneedle derma roller SKU at #1 as of 2026-08-10T00:01:32Z. That board has no keyword time series, so the next step is to score derma roller on Amazon, Google Shopping, Google Search, and YouTube from Python. On the 2026-08-10 pull, Amazon sat at score 58.3 with volume 328,707 on 2026-07-31 (+5.81% over 30D, -15.51% over 3M, -19.59% over 12M). Google Shopping sat at 19.0 on 2026-08-08 (+35.71% over 7D, -62.0% over 3M). Google Search sat at 48.0 on 2026-08-08 (-4.0% over 7D, -36.84% over 12M). YouTube sat at 40.0 on 2026-08-08 (-2.44% over 30D, -36.51% over 12M). TikTok keyword series returned no_data. One Bearer POST, four sources, double-parsed JSON.
Shared Python client
Reuse the same helper as the Python Trends API integration and the ecommerce product research pipeline page. requests, Bearer auth, second json.loads on body.
import json
import os
import requests
API_URL = "https://api.trendsapi.ai/api"
API_KEY = os.environ["TRENDSAPI_API_KEY"]
def trends_api(payload):
res = requests.post(
API_URL,
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json=payload,
timeout=60,
)
res.raise_for_status()
envelope = res.json()
# body is a JSON string; parse it a second time
return json.loads(envelope["body"])
Free tier is 100 successful requests per month. Starter 5,000. Pro 25,000. Business 100,000. Only HTTP 200 counts.
Step 1: read the live board
get_top_trends needs a type and no keyword. Limit 15 returned the derma roller listing at rank 1, a basic casual round neck short-sleeve sports top at rank 2, and GeeYea women's nude ankle strap block heel sandals at rank 3.
board = trends_api({
"mode": "get_top_trends",
"type": "TikTok Shop Hot Products",
"limit": 15,
})
print(board["as_of_ts"], board["data"][0])
Normalize the long SKU title to derma roller. Keep rank 1 and the as_of_ts in the output row for audit.
Step 2: Amazon growth and volume
Amazon is the absolute-volume anchor. Prefer monthly presets. On this pull, 7D and 14D returned collapsed_range.
amazon = trends_api({
"mode": "get_growth",
"source": "amazon",
"keyword": "derma roller",
"percent_growth": ["7D", "14D", "30D", "3M", "6M", "12M"],
})
| Period | Status | Recent date | Score | Volume | Growth |
|---|---|---|---|---|---|
| 7D | collapsed_range | n/a | n/a | n/a | n/a |
| 14D | collapsed_range | n/a | n/a | n/a | n/a |
| 30D | success | 2026-07-31 | 58.3 | 328,707 | +5.81% |
| 3M | success | 2026-07-31 | 58.3 | 328,707 | -15.51% |
| 6M | success | 2026-07-31 | 58.3 | 328,707 | -36.14% |
| 12M | success | 2026-07-31 | 58.3 | 328,707 | -19.59% |
Baseline volumes tell the same story: 310,621 on 2026-06-30, 389,465 on 2026-04-30, 515,213 on 2026-01-31, and 409,222 on 2025-07-31. Volume growth matched score growth within 0.2 points on each successful period.
Step 3: Shopping, Search, and YouTube
Call each source separately. Shopping and Search tip on 2026-08-08 for this pull.
for source, periods in [
("google shopping", ["7D", "14D", "30D", "3M", "6M", "12M"]),
("google search", ["7D", "14D", "30D", "3M", "6M", "12M"]),
("youtube", ["7D", "14D", "30D", "3M", "6M", "12M"]),
]:
body = trends_api({
"mode": "get_growth",
"source": source,
"keyword": "derma roller",
"percent_growth": periods,
})
print(source, body["results"])
| Source | Recent score | 7D | 14D | 30D | 3M | 12M |
|---|---|---|---|---|---|---|
| google shopping | 19.0 | +35.71% | +46.15% | -9.52% | -62.0% | -72.06% |
| google search | 48.0 | -4.0% | -5.88% | -7.69% | -32.39% | -36.84% |
| youtube | 40.0 | -2.44% | +2.56% | -2.44% | -4.76% | -36.51% |
Shopping baselines: 14.0 on 2026-08-01, 13.0 on 2026-07-25, 21.0 on 2026-07-11, 50.0 on 2026-05-09, 68.0 on 2025-08-09. Search baselines: 50.0, 51.0, 52.0, 71.0, 76.0 on the same window ends. YouTube 12M baseline was 63.0 on 2025-08-09. Short-window Shopping strength does not cancel the 12M drawdown.
Step 4: TikTok keyword miss is still a finding
tiktok = trends_api({
"mode": "get_growth",
"source": "tiktok",
"keyword": "derma roller",
"percent_growth": ["7D", "14D", "30D"],
})
The call returned HTTP-layer success with body error no_data: no time series for this keyword and source. The shop board still ranked a derma roller SKU #1. Store both facts. Do not invent a TikTok score. For source field details, see the TikTok trends docs and the Amazon trends docs.
Step 5: optional Amazon series for the chart
series = trends_api({
"mode": "get_time_series",
"source": "amazon",
"keyword": "derma roller",
})
print(len(series), series[-1], max(series, key=lambda r: r["value"]))
The series had 49 monthly points. Earliest point: 2022-07-31, score 38.8, volume 218,659. Peak: 2025-02-28, score 100.0, volume 564,148. Latest: 2026-07-31, score 58.3, volume 328,707. January 2026 was still elevated at 91.3 / 515,213 before the spring slide through 55.1 / 310,621 in June.
Step 6: write a flat scorecard
Collapse growth rows into one CSV-ready list. Keep error statuses. Do not drop Amazon just because 7D collapsed.
import csv
def flatten_growth(source, body):
out = []
for row in body.get("results", []):
out.append({
"keyword": "derma roller",
"source": source,
"period": row.get("period"),
"status": row.get("status"),
"recent_date": row.get("recent_date"),
"recent_value": row.get("recent_value"),
"recent_volume": row.get("recent_volume"),
"growth": row.get("growth"),
"error": row.get("error"),
})
return out
rows = []
rows.append({
"keyword": "derma roller",
"source": "tiktok_shop_board",
"period": "live",
"status": "success",
"recent_date": "2026-08-10",
"recent_value": 1,
"recent_volume": None,
"growth": None,
"error": None,
})
# append flatten_growth(...) outputs for amazon, shopping, search, youtube
A minimal print for the 2026-08-10 pull looks like this:
| Field | Value |
|---|---|
| board rank | 1 |
| board as_of_ts | 2026-08-10T00:01:32Z |
| amazon score / volume | 58.3 / 328,707 |
| amazon 30D / 6M / 12M | +5.81% / -36.14% / -19.59% |
| shopping score / 7D / 12M | 19.0 / +35.71% / -72.06% |
| search score / 7D / 12M | 48.0 / -4.0% / -36.84% |
| youtube score / 14D / 12M | 40.0 / +2.56% / -36.51% |
| tiktok keyword | no_data |
How to read the scorecard
Amazon shows a modest 30D rebound (+5.81% score, +5.82% volume) inside a 12M decline (-19.59% score, -19.68% volume). Google Shopping is the noisy short-term signal: +35.71% over 7D while still -72.06% over 12M. Google Search and YouTube track a softer demand path, both near -37% over 12M. For inventory or ad tests, treat TikTok Shop rank as discovery, Amazon volume as size, and Shopping 7D as a volatility flag, not a green light.
Sibling terms from the same board day help sanity-check. Acne patches Amazon score 47.9 / volume 190,441 on 2026-07-31 (+5.97% 30D, -1.03% 3M, -10.13% 12M). Thermal brush Amazon score 38.6 / volume 380,899 (-1.78% 30D, -27.72% 3M, -10.23% 12M). Thermal brush Google Search sat at 33.0 on 2026-08-08 (+6.45% 7D, -49.23% 3M, +6.45% 12M). Microneedling Google Search sat at 41.0 on 2026-08-08 (-18.0% 7D, -37.88% 30D, -54.44% 3M, -6.82% 12M). Derma roller is not alone in a cooling beauty-device window, and absolute Amazon volume still separates the pack: thermal brush 380,899, derma roller 328,707, acne patches 190,441.
Decision rules for this SKU day
- Do not buy on TikTok Shop rank alone. Rank 1 coexisted with TikTok keyword
no_dataand a 12M Amazon decline. - Prefer Amazon 30D+ presets. Persist
collapsed_rangefor 7D and 14D instead of retry spam. - Treat Shopping 7D and 14D (+35.71%, +46.15%) as short-window noise until Search and YouTube confirm.
- Compare sibling volumes before sizing a buy. Thermal brush out-volumes derma roller on Amazon even when derma roller owns the shop board slot.
- Store
data_dateas 2026-08-10 for every row written from this session.
Wire this script into the broader ecommerce product research pipeline pattern: board pull, keyword map, per-source growth, persist errors, cron the CSV. That is the whole job for one SKU day.