Overview
Searches TikTok for creators in a target niche, fetches profile data and recent video engagement metrics, filters by follower count and engagement rate thresholds, and outputs a shortlist of qualified creators for campaign consideration.
Trigger
On-demand (manual run or triggered by campaign planning workflow)
Schedule
On-demand
Workflow Steps
Search TikTok users by niche keyword
POST to Scavio TikTok user search endpoint with the niche keyword. Retrieve list of creator profiles matching the search.
Fetch profile details for each creator
For each creator in search results, POST to TikTok user info endpoint with username to get follower_count, following_count, video_count, and sec_uid.
Filter by follower threshold
Remove creators below minimum follower count (configurable, e.g., 10,000 for micro, 100,000 for mid-tier).
Fetch recent videos for engagement calculation
For creators passing follower filter, POST to TikTok user videos endpoint with sec_uid to get last 10 videos with stats.
Calculate engagement rate
For each creator, compute average engagement rate across last 10 videos: mean((likes + comments + shares) / views).
Filter and rank by engagement rate
Remove creators below minimum engagement rate (e.g., 2%). Rank remaining creators by engagement rate descending. Output shortlist as CSV or JSON.
Python Implementation
import requests
import json
import time
from datetime import date
SCRAVIO_KEY = "YOUR_API_KEY"
API_BASE = "https://api.scavio.dev/api/v1/tiktok"
HEADERS = {"Authorization": f"Bearer {SCRAVIO_KEY}", "Content-Type": "application/json"}
NICHE = "fitness"
MIN_FOLLOWERS = 10000
MIN_ENGAGEMENT_RATE = 0.02
def search_creators(niche: str) -> list:
resp = requests.post(f"{API_BASE}/user/search", headers=HEADERS, json={"keyword": niche, "count": 30})
resp.raise_for_status()
return resp.json().get("data", {}).get("users", [])
def get_profile(username: str) -> dict | None:
resp = requests.post(f"{API_BASE}/user/info", headers=HEADERS, json={"username": username})
if resp.status_code != 200:
return None
return resp.json().get("data", {}).get("user", {})
def get_recent_videos(sec_uid: str) -> list:
resp = requests.post(f"{API_BASE}/user/videos", headers=HEADERS, json={"sec_uid": sec_uid, "count": 10})
if resp.status_code != 200:
return []
return resp.json().get("data", {}).get("videos", [])
def avg_engagement_rate(videos: list) -> float:
if not videos:
return 0.0
rates = []
for v in videos:
s = v.get("stats", {})
views = s.get("playCount", 0)
if not views:
continue
er = (s.get("diggCount", 0) + s.get("commentCount", 0) + s.get("shareCount", 0)) / views
rates.append(er)
return round(sum(rates) / len(rates), 4) if rates else 0.0
def run():
creators_raw = search_creators(NICHE)
shortlist = []
for c in creators_raw:
username = c.get("uniqueId") or c.get("username")
if not username:
continue
profile = get_profile(username)
if not profile:
time.sleep(0.3)
continue
followers = profile.get("stats", {}).get("followerCount", 0)
if followers < MIN_FOLLOWERS:
time.sleep(0.2)
continue
sec_uid = profile.get("secUid")
videos = get_recent_videos(sec_uid) if sec_uid else []
er = avg_engagement_rate(videos)
if er < MIN_ENGAGEMENT_RATE:
time.sleep(0.2)
continue
shortlist.append({
"username": username,
"followers": followers,
"avg_engagement_rate": er,
"video_count": profile.get("stats", {}).get("videoCount", 0),
"sec_uid": sec_uid,
"tiktok_url": f"https://tiktok.com/@{username}"
})
time.sleep(0.3)
shortlist.sort(key=lambda x: x["avg_engagement_rate"], reverse=True)
print(json.dumps(shortlist, indent=2))
return shortlist
if __name__ == "__main__":
run()
JavaScript Implementation
const fetch = require('node-fetch');
const SCRAVIO_KEY = 'YOUR_API_KEY';
const API_BASE = 'https://api.scavio.dev/api/v1/tiktok';
const HEADERS = { 'Authorization': `Bearer ${SCRAVIO_KEY}`, 'Content-Type': 'application/json' };
const NICHE = 'fitness';
const MIN_FOLLOWERS = 10000;
const MIN_ER = 0.02;
async function post(path, body) {
const res = await fetch(`${API_BASE}${path}`, { method: 'POST', headers: HEADERS, body: JSON.stringify(body) });
return res.ok ? (await res.json()) : null;
}
function avgER(videos) {
const rates = videos.map(v => { const s = v.stats||{}; const views = s.playCount||0; return views ? (s.diggCount+s.commentCount+s.shareCount)/views : null; }).filter(Boolean);
return rates.length ? rates.reduce((a,b)=>a+b,0)/rates.length : 0;
}
async function run() {
const search = await post('/user/search', { keyword: NICHE, count: 30 });
const users = search?.data?.users || [];
const shortlist = [];
for (const u of users) {
const username = u.uniqueId || u.username;
if (!username) continue;
const profileData = await post('/user/info', { username });
if (!profileData) { await new Promise(r=>setTimeout(r,300)); continue; }
const profile = profileData.data?.user || {};
const followers = profile.stats?.followerCount || 0;
if (followers < MIN_FOLLOWERS) { await new Promise(r=>setTimeout(r,200)); continue; }
const sec_uid = profile.secUid;
const videosData = sec_uid ? await post('/user/videos', { sec_uid, count: 10 }) : null;
const videos = videosData?.data?.videos || [];
const er = avgER(videos);
if (er < MIN_ER) { await new Promise(r=>setTimeout(r,200)); continue; }
shortlist.push({ username, followers, avg_engagement_rate: Math.round(er*10000)/10000, sec_uid, tiktok_url: `https://tiktok.com/@${username}` });
await new Promise(r=>setTimeout(r,300));
}
shortlist.sort((a,b) => b.avg_engagement_rate - a.avg_engagement_rate);
console.log(JSON.stringify(shortlist, null, 2));
}
run().catch(console.error);
Platforms Used
TikTok
Trending video, creator, and product discovery