Creator engagement scoring
Compare one creator's engagement on TikTok, Instagram and YouTube in a single ranked table, calculated with one formula from each platform's recent posts. 60 to 190 credits per creator.
You will build a vetting table for influencer marketing: a single row per platform for one creator across TikTok, Instagram and YouTube, sorted by an engagement rate you compute the same way on each network.
Cost per run
60 to 190 credits per creator: three profile calls at 10 credits each, plus one page of recent posts per platform (TikTok 10, Instagram 10–130, YouTube 10–20). Vetting a shortlist of 100 creators costs at least 6,000 credits. Checking the same creator again is charged again, so keep the scores you calculated.
How do you compare engagement rates across platforms?
Fetch each platform's profile for the follower count, and one page of the creator's recent posts for the likes and comments. Then apply one formula everywhere: for each post, (likes + comments) / followers, and take the median over the page. The median keeps one viral post from carrying the whole score.
Raw numbers do not compare on their own. A TikTok like is not an Instagram like, follower counts inflate differently, and every analytics tool defines "engagement rate" its own way. A formula you own, applied to the same fields on every platform, is what makes the ranking fair. Recent posts also avoid a trap in lifetime totals: a TikTok profile's like count is every heart the account ever received, which says little about how its videos do now.
What you need
| Endpoint | Returns | Credits |
|---|---|---|
GET /v1/tiktok/profile | data.author.followers | 10 |
GET /v1/tiktok/profile/videos | Recent videos, post.engagement | 10 |
GET /v1/instagram/profile | data.author.followers | 10 |
GET /v1/instagram/profile/posts | Recent posts, post.engagement | 10–130 |
GET /v1/youtube/channel | data.author.followers (rounded above 1,000) | 10 |
GET /v1/youtube/channel/videos | Recent videos; includeExtras=true fills likes and comments | 10–20 |
The code
# creator_scoring.py
# Run with: INSIGHTSOCIAL_API_KEY=isk_live_... python creator_scoring.py
import os
from concurrent.futures import ThreadPoolExecutor
from statistics import median
import requests
KEY = os.environ["INSIGHTSOCIAL_API_KEY"]
BASE = "https://api.insightsocial.app/v1"
# Real creators rarely share one handle, so map them per platform.
CREATOR = {"tiktok": "mrbeast", "instagram": "mrbeast", "youtube": "MrBeast"}
PATHS = {
"tiktok": ("tiktok/profile", "tiktok/profile/videos", {}),
"instagram": ("instagram/profile", "instagram/profile/posts", {}),
"youtube": ("youtube/channel", "youtube/channel/videos", {"includeExtras": "true"}),
}
def get(path, **params):
res = requests.get(f"{BASE}/{path}", params=params,
headers={"x-api-key": KEY}, timeout=120)
return res.json()
def score(platform):
profile_path, posts_path, extra = PATHS[platform]
handle = CREATOR[platform]
profile = get(profile_path, handle=handle)
posts = get(posts_path, handle=handle, **extra)
row = {"platform": platform, "followers": None, "engagement_rate": None, "posts_scored": 0,
"credits": profile.get("credits_used", 0) + posts.get("credits_used", 0), "why": None}
if not profile["success"] or not posts["success"]:
row["why"] = (profile.get("error") or posts.get("error"))["type"]
return row
followers = profile["data"]["author"]["followers"]
row["followers"] = followers
if not followers:
row["why"] = "no follower count"
return row
rates = []
for item in posts["data"]["items"]:
post = item["post"]
likes, comments = post["engagement"]["likes"], post["engagement"]["comments"]
# Skip pinned posts (old, out of order) and posts with a hidden count.
if post["flags"]["pinned"] or likes is None or comments is None:
continue
rates.append((likes + comments) / followers)
row["posts_scored"] = len(rates)
if rates:
row["engagement_rate"] = round(median(rates), 4)
else:
row["why"] = "no post with both counts"
return row
with ThreadPoolExecutor(max_workers=3) as pool:
rows = list(pool.map(score, CREATOR))
# Rank the comparable rows; keep the others visible but unranked.
ranked = sorted((r for r in rows if r["engagement_rate"] is not None),
key=lambda r: r["engagement_rate"], reverse=True)
for r in ranked:
print(f'{r["platform"]:<10} {r["followers"]:>12,} {r["engagement_rate"]:.4f} ({r["posts_scored"]} posts)')
for r in rows:
if r["engagement_rate"] is None:
print(f'{r["platform"]:<10} cannot compare: {r["why"]}')
print("credits used:", sum(r["credits"] for r in rows))What you get back
youtube 298,000,000 0.0071 (30 posts)
tiktok 112,000,000 0.0109 (9 posts)
instagram 71,500,000 0.0052 (11 posts)
credits used: 60The figures are illustrative. A None rate is a signal, not a low score: the profile had no follower count, or no post on the page showed both likes and comments. Treat such rows as "cannot compare", never as "best" or "worst". YouTube subscriber counts are rounded above 1,000 (followers_approximate: true on the profile), which is close enough for a ranking but not for a precise rate.
What to change
- The formula. Add
sharesandsaveswhere a platform shows them, or divide byviewsfor a reach-based rate. A count the platform never shows isnullon every row, and a count hidden on one post isnullon that post only, so filter onNoneexactly as the code does. - A bigger sample. Send
pagination.next_cursorback ascursorwith the samehandleto read older posts, at the page price each. See Pagination. - Score a shortlist. Loop over a list of creator maps and sort the flattened rows. Budget at least 60 credits per creator.
- Weight the rank. Engagement rate alone favours small accounts. Blend it with
followersfor the trade-off your team actually makes.
Related
Competitor tracking
Snapshot a competitor's followers, engagement and latest posts on TikTok, Instagram, YouTube and X in one parallel sweep, then diff it against the last run. 80 to 210 credits per competitor.
TikTok analytics dashboard
Build the data layer of a TikTok dashboard for accounts you do not own, with account KPIs, a per-video table with engagement rates and a scored comment feed. 30 to 50 credits per refresh.