Influencer marketing teams spend 15 to 30 minutes manually vetting each TikTok creator by scrolling profiles, eyeballing engagement, and guessing at follower authenticity. This does not scale when evaluating 200 creators for a campaign. The Scavio TikTok API lets you automate the entire vetting process: pull profile data (follower count, verification status), fetch recent posts (engagement rates, posting frequency), and flag red flags like suspicious follower-to-engagement ratios. Vetting one creator requires about 4 API calls (profile + 3 pages of posts), costing $0.02 total. A 200-creator campaign vetting run costs $4.
Prerequisites
- Python 3.8+ or Node.js 18+
- A Scavio API key from scavio.dev
- requests library installed (Python)
- A list of TikTok usernames to vet
Walkthrough
Step 1: Fetch profile data for the creator
Pull the creator's profile including follower count, video count, total likes, and verification status. The profile endpoint also returns the sec_uid needed for fetching posts.
import requests, os
API_KEY = os.environ['SCAVIO_API_KEY']
HEADERS = {'Authorization': f'Bearer {API_KEY}', 'Content-Type': 'application/json'}
def get_profile(username):
resp = requests.post('https://api.scavio.dev/api/v1/tiktok/profile',
headers=HEADERS, json={'username': username})
user = resp.json()['data']['user']
return {
'username': user['unique_id'],
'followers': user['follower_count'],
'following': user['following_count'],
'videos': user['aweme_count'],
'likes': user['total_favorited'],
'verified': user.get('verified', False),
'sec_uid': user['sec_uid'],
}Step 2: Fetch recent posts and calculate engagement rate
Pull the last 60 posts and compute average engagement rate (likes + comments + shares divided by play count). A healthy engagement rate on TikTok is typically 3-8%.
def get_engagement_stats(sec_uid, pages=3):
videos = []
params = {'sec_user_id': sec_uid, 'count': 20}
for _ in range(pages):
resp = requests.post('https://api.scavio.dev/api/v1/tiktok/user/posts',
headers=HEADERS, json=params).json()['data']
videos.extend(resp.get('videos', []))
if not resp.get('has_more'): break
params['max_cursor'] = resp['max_cursor']
if not videos:
return {'avg_engagement': 0, 'post_count': 0, 'avg_plays': 0}
rates = []
for v in videos:
s = v['stats']
plays = s.get('playCount', 0)
if plays > 0:
eng = (s.get('diggCount', 0) + s.get('commentCount', 0) + s.get('shareCount', 0)) / plays
rates.append(eng)
return {
'avg_engagement': sum(rates) / len(rates) if rates else 0,
'post_count': len(videos),
'avg_plays': sum(v['stats'].get('playCount', 0) for v in videos) / len(videos),
}Step 3: Score and flag red flags
Combine profile and engagement data into a vet score. Flag red flags: very low engagement with high followers (likely bought), no posts in 30 days, follower-to-following ratio anomalies.
def vet_creator(username):
profile = get_profile(username)
engagement = get_engagement_stats(profile['sec_uid'])
flags = []
if profile['followers'] > 50000 and engagement['avg_engagement'] < 0.01:
flags.append('LOW_ENGAGEMENT: possible bought followers')
if profile['followers'] > 0 and profile['following'] / profile['followers'] > 2:
flags.append('HIGH_FOLLOW_RATIO: follows many more than followers')
if engagement['post_count'] == 0:
flags.append('INACTIVE: no recent posts found')
score = 'PASS' if not flags else 'REVIEW'
return {
'username': profile['username'],
'followers': profile['followers'],
'verified': profile['verified'],
'avg_engagement': f"{engagement['avg_engagement']:.2%}",
'avg_plays': int(engagement['avg_plays']),
'recent_posts': engagement['post_count'],
'flags': flags,
'verdict': score,
}Step 4: Batch vet a list of creators
Run the vetting pipeline across all candidate creators and output a summary report.
def batch_vet(usernames):
results = []
for username in usernames:
result = vet_creator(username)
results.append(result)
status = result['verdict']
print(f"[{status}] @{result['username']}: {result['followers']:,} followers, "
f"{result['avg_engagement']} engagement")
for flag in result['flags']:
print(f" WARNING: {flag}")
passed = [r for r in results if r['verdict'] == 'PASS']
print(f"\n{len(passed)}/{len(results)} creators passed vetting")
return results
batch_vet(['creator1', 'creator2', 'creator3'])Python Example
import requests, os, json
API_KEY = os.environ['SCAVIO_API_KEY']
HEADERS = {'Authorization': f'Bearer {API_KEY}', 'Content-Type': 'application/json'}
def get_profile(username):
u = requests.post('https://api.scavio.dev/api/v1/tiktok/profile',
headers=HEADERS, json={'username': username}).json()['data']['user']
return {'username': u['unique_id'], 'followers': u['follower_count'],
'following': u['following_count'], 'likes': u['total_favorited'],
'verified': u.get('verified', False), 'sec_uid': u['sec_uid']}
def get_engagement(sec_uid):
videos, params = [], {'sec_user_id': sec_uid, 'count': 20}
for _ in range(3):
r = requests.post('https://api.scavio.dev/api/v1/tiktok/user/posts',
headers=HEADERS, json=params).json()['data']
videos.extend(r.get('videos', []))
if not r.get('has_more'): break
params['max_cursor'] = r['max_cursor']
rates = []
for v in videos:
s = v['stats']
if s.get('playCount', 0) > 0:
rates.append((s['diggCount'] + s['commentCount'] + s['shareCount']) / s['playCount'])
return sum(rates) / len(rates) if rates else 0, len(videos)
def vet(username):
p = get_profile(username)
eng, posts = get_engagement(p['sec_uid'])
flags = []
if p['followers'] > 50000 and eng < 0.01: flags.append('LOW_ENGAGEMENT')
if posts == 0: flags.append('INACTIVE')
print(f"@{p['username']}: {p['followers']:,} followers, {eng:.2%} engagement, {len(flags)} flags")
return {'profile': p, 'engagement': eng, 'posts': posts, 'flags': flags}
for u in ['creator1', 'creator2']:
vet(u)JavaScript Example
const API_KEY = process.env.SCAVIO_API_KEY;
const H = { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' };
async function getProfile(username) {
const r = await fetch('https://api.scavio.dev/api/v1/tiktok/profile', {
method: 'POST', headers: H, body: JSON.stringify({ username })
}).then(r => r.json());
const u = r.data.user;
return { username: u.unique_id, followers: u.follower_count,
following: u.following_count, sec_uid: u.sec_uid };
}
async function getEngagement(secUid) {
const videos = [];
let params = { sec_user_id: secUid, count: 20 };
for (let i = 0; i < 3; i++) {
const r = await fetch('https://api.scavio.dev/api/v1/tiktok/user/posts', {
method: 'POST', headers: H, body: JSON.stringify(params)
}).then(r => r.json());
videos.push(...(r.data.videos || []));
if (!r.data.has_more) break;
params.max_cursor = r.data.max_cursor;
}
const rates = videos.map(v => {
const s = v.stats;
return s.playCount > 0 ? (s.diggCount + s.commentCount + s.shareCount) / s.playCount : 0;
}).filter(r => r > 0);
return rates.length ? rates.reduce((a, b) => a + b, 0) / rates.length : 0;
}
async function vet(username) {
const p = await getProfile(username);
const eng = await getEngagement(p.sec_uid);
const flags = [];
if (p.followers > 50000 && eng < 0.01) flags.push('LOW_ENGAGEMENT');
console.log(`@${p.username}: ${p.followers} followers, ${(eng * 100).toFixed(2)}% engagement`);
return { profile: p, engagement: eng, flags };
}
(async () => { for (const u of ['creator1', 'creator2']) await vet(u); })();Expected Output
[PASS] @fitnessguru: 85,000 followers, 5.40% engagement
[REVIEW] @megafollower: 500,000 followers, 0.80% engagement
WARNING: LOW_ENGAGEMENT: possible bought followers
[PASS] @cookingwithanna: 42,000 followers, 7.20% engagement
2/3 creators passed vetting