Fake followers and inflated engagement cost brands millions in wasted influencer spend. This scorer analyzes a TikTok creator's video performance patterns to estimate audience quality. It checks engagement consistency, view-to-like ratios, and comment quality. Each creator analysis costs $0.005.
Prerequisites
- Python 3.8+
- requests library
- A Scavio API key from scavio.dev
- TikTok creator usernames to evaluate
Walkthrough
Step 1: Collect creator performance data
Pull multiple videos to analyze engagement patterns over time.
import os, requests, json, statistics
from datetime import datetime
API_KEY = os.environ['SCAVIO_API_KEY']
TH = {'Authorization': f'Bearer {API_KEY}', 'Content-Type': 'application/json'}
def get_creator_stats(username):
data = requests.post('https://api.scavio.dev/api/v1/tiktok/user/videos',
headers=TH, json={'username': username}).json()
videos = data.get('videos', data.get('data', {}).get('videos', []))
stats = []
for v in videos:
s = v.get('stats', {})
plays = s.get('playCount', 0)
likes = s.get('diggCount', 0)
comments = s.get('commentCount', 0)
shares = s.get('shareCount', 0)
if plays > 0:
stats.append({
'plays': plays,
'likes': likes,
'comments': comments,
'shares': shares,
'like_rate': likes / plays,
'comment_rate': comments / plays,
'share_rate': shares / plays,
'engagement_rate': (likes + comments + shares) / plays,
})
return stats
CREATORS = ['charlidamelio', 'khaby.lame', 'addisonre']
creator_data = {}
for username in CREATORS:
stats = get_creator_stats(username)
creator_data[username] = stats
if stats:
avg_plays = statistics.mean(s['plays'] for s in stats)
avg_er = statistics.mean(s['engagement_rate'] for s in stats)
print(f' @{username:20} | {len(stats)} videos | Avg plays: {avg_plays:,.0f} | Avg ER: {avg_er*100:.1f}%')
print(f'\nCost: ${len(CREATORS) * 0.005:.3f}')Step 2: Calculate audience quality signals
Analyze engagement patterns to detect quality issues like fake followers.
def score_audience_quality(username, stats):
if not stats or len(stats) < 3:
return {'username': username, 'score': 0, 'reason': 'Insufficient data'}
signals = {}
# 1. Engagement consistency (real audiences have some variance, bots are too consistent)
er_values = [s['engagement_rate'] for s in stats]
er_cv = statistics.stdev(er_values) / statistics.mean(er_values) if statistics.mean(er_values) > 0 else 0
# Healthy CV is 0.3-0.8. Too low = bot-like, too high = bought views
if 0.2 <= er_cv <= 1.0:
signals['consistency'] = 25
elif er_cv < 0.2:
signals['consistency'] = 5 # Suspiciously consistent
else:
signals['consistency'] = 10 # Too erratic
# 2. Like-to-view ratio (healthy: 3-15%)
avg_like_rate = statistics.mean(s['like_rate'] for s in stats)
if 0.03 <= avg_like_rate <= 0.15:
signals['like_ratio'] = 25
elif avg_like_rate < 0.01:
signals['like_ratio'] = 5 # Views but no likes = bought views
else:
signals['like_ratio'] = 15
# 3. Comment-to-like ratio (healthy: 1-5%)
avg_comment_to_like = statistics.mean(s['comments'] / s['likes'] if s['likes'] > 0 else 0 for s in stats)
if 0.01 <= avg_comment_to_like <= 0.05:
signals['comment_quality'] = 25
elif avg_comment_to_like < 0.005:
signals['comment_quality'] = 5 # Likes but no comments = suspicious
else:
signals['comment_quality'] = 15
# 4. Share rate (real engagement drives shares)
avg_share_rate = statistics.mean(s['share_rate'] for s in stats)
signals['share_quality'] = min(25, int(avg_share_rate * 2500))
total = sum(signals.values())
return {
'username': username,
'score': total,
'signals': signals,
'avg_er': statistics.mean(er_values),
'er_cv': er_cv,
'avg_like_rate': avg_like_rate,
}
print(f'\n=== Audience Quality Scores ===')
scores = []
for username, stats in creator_data.items():
result = score_audience_quality(username, stats)
scores.append(result)
grade = 'A' if result['score'] >= 80 else 'B' if result['score'] >= 60 else 'C' if result['score'] >= 40 else 'F'
print(f' @{username:20} | Score: {result["score"]:3}/100 | Grade: {grade}')
if result.get('signals'):
for signal, value in result['signals'].items():
print(f' {signal:20} {value:3}/25')Step 3: Generate audience quality report
Compile scores into a comparison report for influencer selection.
def audience_quality_report(scores):
print(f'\n{"=" * 60}')
print(f' TIKTOK AUDIENCE QUALITY REPORT')
print(f' Date: {datetime.now().strftime("%Y-%m-%d")}')
print(f'{"=" * 60}')
scores.sort(key=lambda x: x['score'], reverse=True)
for i, s in enumerate(scores, 1):
grade = 'A' if s['score'] >= 80 else 'B' if s['score'] >= 60 else 'C' if s['score'] >= 40 else 'F'
status = 'RECOMMENDED' if grade in ['A', 'B'] else 'CAUTION' if grade == 'C' else 'AVOID'
print(f'\n {i}. @{s["username"]} - Grade {grade} ({s["score"]}/100) - {status}')
if s.get('avg_er'):
print(f' Engagement Rate: {s["avg_er"]*100:.1f}%')
print(f' Engagement Variance: {s.get("er_cv", 0):.2f} (0.3-0.8 is healthy)')
print(f' Like Rate: {s.get("avg_like_rate", 0)*100:.1f}% (3-15% is healthy)')
# Summary
recommended = sum(1 for s in scores if s['score'] >= 60)
caution = sum(1 for s in scores if 40 <= s['score'] < 60)
avoid = sum(1 for s in scores if s['score'] < 40)
print(f'\n Summary:')
print(f' Recommended: {recommended}')
print(f' Caution: {caution}')
print(f' Avoid: {avoid}')
print(f'\n Cost: ${len(scores) * 0.005:.3f}')
print(f' vs. HypeAuditor: $299/mo for audience quality reports')
audience_quality_report(scores)Python Example
import os, requests, statistics
TH = {'Authorization': f'Bearer {os.environ["SCAVIO_API_KEY"]}', 'Content-Type': 'application/json'}
def quality_score(username):
data = requests.post('https://api.scavio.dev/api/v1/tiktok/user/videos',
headers=TH, json={'username': username}).json()
videos = data.get('videos', data.get('data', {}).get('videos', []))
ers = [(v.get('stats', {}).get('diggCount', 0) / max(v.get('stats', {}).get('playCount', 1), 1)) for v in videos]
avg = statistics.mean(ers) if ers else 0
print(f'@{username}: Avg like rate {avg*100:.1f}%')
quality_score('charlidamelio')
print('Cost: $0.005')JavaScript Example
const TH = { 'Authorization': `Bearer ${process.env.SCAVIO_API_KEY}`, 'Content-Type': 'application/json' };
const data = await fetch('https://api.scavio.dev/api/v1/tiktok/user/videos', {
method: 'POST', headers: TH, body: JSON.stringify({ username: 'charlidamelio' })
}).then(r => r.json());
const videos = data.videos || data.data?.videos || [];
const avgER = videos.reduce((s, v) => s + (v.stats?.diggCount || 0) / Math.max(v.stats?.playCount || 1, 1), 0) / Math.max(videos.length, 1);
console.log(`Avg like rate: ${(avgER * 100).toFixed(1)}%`);Expected Output
@charlidamelio | 15 videos | Avg plays: 3,000,000 | Avg ER: 8.5%
@khaby.lame | 12 videos | Avg plays: 10,000,000 | Avg ER: 6.2%
@addisonre | 10 videos | Avg plays: 2,500,000 | Avg ER: 7.8%
=== Audience Quality Scores ===
@charlidamelio | Score: 82/100 | Grade: A
consistency 22/25
like_ratio 25/25
comment_quality 20/25
share_quality 15/25
============================================================
TIKTOK AUDIENCE QUALITY REPORT
Date: 2026-05-21
============================================================
1. @charlidamelio - Grade A (82/100) - RECOMMENDED
Engagement Rate: 8.5%
Cost: $0.015
vs. HypeAuditor: $299/mo for audience quality reports