Winning TikTok products follow a predictable pattern: a hashtag spikes, creator adoption follows, and sales surge within 72 hours. This tutorial uses the Scavio TikTok API to detect that pattern programmatically -- scanning hashtags for engagement velocity, cross-referencing with video content, and scoring products by viral potential before the trend peaks.
Prerequisites
- Python 3.11+ or Node.js 20+
- A Scavio API key from https://scavio.dev
- Basic understanding of TikTok content trends
- Optional: a spreadsheet or database for tracking results
Walkthrough
Step 1: Search trending hashtags for product signals
Use the Scavio TikTok hashtag endpoint to find hashtags with high recent growth in product-related niches. Filter for hashtags that contain product-intent keywords.
import httpx
from datetime import datetime
SCAVIO_API_KEY = "your-api-key"
BASE_URL = "https://api.scavio.dev/api/v1/tiktok"
PRODUCT_NICHES = [
"kitchen gadget",
"beauty tool",
"home organization",
"fitness accessory",
"phone accessory",
"cleaning hack",
]
async def search_trending_hashtags(niche: str) -> list[dict]:
async with httpx.AsyncClient(timeout=15) as client:
resp = await client.post(
f"{BASE_URL}/hashtag/search",
headers={"Authorization": f"Bearer {SCAVIO_API_KEY}"},
json={"query": niche, "limit": 20}
)
resp.raise_for_status()
hashtags = resp.json().get("hashtags", [])
# Filter for hashtags showing growth
trending = [
h for h in hashtags
if h.get("view_count", 0) > 100000
]
return sorted(trending, key=lambda h: h.get("view_count", 0), reverse=True)Step 2: Fetch top videos for each trending hashtag
For each promising hashtag, pull the top-performing videos to analyze what products appear in the content and how creators present them.
async def fetch_hashtag_videos(hashtag_name: str, limit: int = 10) -> list[dict]:
async with httpx.AsyncClient(timeout=15) as client:
resp = await client.post(
f"{BASE_URL}/video/search",
headers={"Authorization": f"Bearer {SCAVIO_API_KEY}"},
json={"query": hashtag_name, "limit": limit}
)
resp.raise_for_status()
videos = resp.json().get("videos", [])
return [
{
"video_id": v.get("id"),
"description": v.get("description", ""),
"likes": v.get("likes", 0),
"shares": v.get("shares", 0),
"comments": v.get("comments", 0),
"views": v.get("views", 0),
"author": v.get("author", {}).get("username", ""),
"created": v.get("created_at", ""),
"engagement_rate": _calc_engagement(v)
}
for v in videos
]
def _calc_engagement(video: dict) -> float:
views = video.get("views", 1)
interactions = video.get("likes", 0) + video.get("shares", 0) + video.get("comments", 0)
return round(interactions / views * 100, 2) if views > 0 else 0.0Step 3: Score products by viral potential
Combine hashtag growth, video engagement rates, and creator diversity into a single viral score. Products with high scores across multiple creators are the strongest signals.
def score_product(hashtag: dict, videos: list[dict]) -> dict:
unique_creators = len(set(v["author"] for v in videos if v["author"]))
avg_engagement = sum(v["engagement_rate"] for v in videos) / max(len(videos), 1)
total_views = hashtag.get("view_count", 0)
total_shares = sum(v["shares"] for v in videos)
# Viral score: weighted combination
score = (
(min(unique_creators, 10) / 10) * 30 + # creator diversity (30%)
(min(avg_engagement, 15) / 15) * 30 + # engagement rate (30%)
(min(total_shares, 5000) / 5000) * 20 + # share velocity (20%)
(min(total_views, 10_000_000) / 10_000_000) * 20 # reach (20%)
)
return {
"hashtag": hashtag.get("name", ""),
"viral_score": round(score, 1),
"unique_creators": unique_creators,
"avg_engagement_rate": round(avg_engagement, 2),
"total_views": total_views,
"total_shares": total_shares,
"top_video_description": videos[0]["description"][:200] if videos else "",
"analyzed_at": datetime.now().isoformat()
}Step 4: Run the full pipeline and output ranked results
Scan all niches, score every product signal, and output a ranked list of winning products sorted by viral score.
import asyncio
import json
async def find_winning_products() -> list[dict]:
all_products = []
for niche in PRODUCT_NICHES:
hashtags = await search_trending_hashtags(niche)
for hashtag in hashtags[:5]: # Top 5 per niche
videos = await fetch_hashtag_videos(hashtag.get("name", ""))
if videos:
product = score_product(hashtag, videos)
product["niche"] = niche
all_products.append(product)
# Sort by viral score
all_products.sort(key=lambda p: p["viral_score"], reverse=True)
return all_products
async def main():
products = await find_winning_products()
print(f"Analyzed {len(products)} product signals")
print(f"Credits used: ~{len(products) * 2} ({len(products) * 2 * 0.005:.2f})")
print("\nTop 5 Winning Products:")
for i, p in enumerate(products[:5], 1):
print(f" {i}. [{p['niche']}] #{p['hashtag']} - Score: {p['viral_score']}")
print(f" Creators: {p['unique_creators']} | Engagement: {p['avg_engagement_rate']}%")
print(json.dumps(products[:10], indent=2))
asyncio.run(main())Python Example
import asyncio
import httpx
SCAVIO_API_KEY = "your-api-key"
BASE_URL = "https://api.scavio.dev/api/v1/tiktok"
async def main():
async with httpx.AsyncClient(timeout=15) as client:
# Search hashtags
resp = await client.post(
f"{BASE_URL}/hashtag/search",
headers={"Authorization": f"Bearer {SCAVIO_API_KEY}"},
json={"query": "kitchen gadget", "limit": 10}
)
hashtags = resp.json().get("hashtags", [])
# Get videos for top hashtag
if hashtags:
top = hashtags[0]
resp = await client.post(
f"{BASE_URL}/video/search",
headers={"Authorization": f"Bearer {SCAVIO_API_KEY}"},
json={"query": top["name"], "limit": 5}
)
videos = resp.json().get("videos", [])
creators = len(set(v.get("author", {}).get("username", "") for v in videos))
print(f"Hashtag: #{top['name']}")
print(f"Views: {top.get('view_count', 0):,}")
print(f"Top videos: {len(videos)}")
print(f"Unique creators: {creators}")
asyncio.run(main())JavaScript Example
const SCAVIO_API_KEY = "your-api-key";
const BASE_URL = "https://api.scavio.dev/api/v1/tiktok";
async function tiktokApi(endpoint, body) {
const resp = await fetch(BASE_URL + "/" + endpoint, {
method: "POST",
headers: { "Authorization": "Bearer " + SCAVIO_API_KEY, "Content-Type": "application/json" },
body: JSON.stringify(body)
});
return resp.json();
}
async function main() {
const hashtagData = await tiktokApi("hashtag/search", { query: "kitchen gadget", limit: 10 });
const hashtags = hashtagData.hashtags || [];
if (hashtags.length === 0) { console.log("No hashtags found"); return; }
const top = hashtags[0];
const videoData = await tiktokApi("video/search", { query: top.name, limit: 5 });
const videos = videoData.videos || [];
const creators = new Set(videos.map(v => v.author?.username).filter(Boolean)).size;
console.log("Hashtag: #" + top.name);
console.log("Views:", top.view_count?.toLocaleString());
console.log("Top videos:", videos.length);
console.log("Unique creators:", creators);
}
main();Expected Output
Analyzed 30 product signals
Credits used: ~60 ($0.30)
Top 5 Winning Products:
1. [kitchen gadget] #miniwaffle - Score: 72.5
Creators: 8 | Engagement: 11.2%