Deep-dive lookup
Video outlier check
Find out whether a video is a real outlier, meaning it beat its creator's usual views, or only looks big because the creator is big.
- What it does
- Tells you if one TikTok, YouTube or Instagram video is a real breakout for its creator.
- You send
- The video's link and its platform.
- You get back
- A job ID right away, then the video's stats, the creator's profile, an outlier score and a verdict such as
viral. - Cost
- $0.50 per check, charged at the start, even if the check fails. Status checks and saved results are free.
- How long
- Usually 15 to 60 seconds, a few minutes at busy times.
It's one of Virlo's deep-dive lookups, under /v1/satellite/.
Start a video outlier check
Returns a job_id in about a second. Virlo then compares the video with up to 100 of the creator's recent videos.
Each request is billed, even for a link you already checked. Creator, sound and hashtag lookups repeat free within 6 hours; this one doesn't.
Body parameters
Send only these two fields. Anything missing or extra returns a 400.
- Name
url- Type
- string
- Required
- *
- Description
The full link, including
https://. It must matchplatform: Virlo won't catch a mismatch, and still charges.
- Name
platform- Type
- string
- Required
- *
- Description
tiktok,youtubeorinstagram, lowercase.
Limits: 5 starts a minute, 100 an hour, 1,000 a day. Status checks don't count.
Details for developers
- Limits reset on the clock: each minute, each hour and at midnight UTC.
- Requests rejected with a
400still count. X-RateLimit-Limit,X-RateLimit-RemainingandX-RateLimit-Resetdescribe the window closest to running out. A429addsRetry-After(seconds). See Rate limits.
Request
curl -X POST https://api.virlo.ai/v1/satellite/video-outlier \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.instagram.com/reels/DVMBt9pE4ob/",
"platform": "instagram"
}'
Response
{
"data": {
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "processing"
}
}
Check the status
Free. Returns processing while the check runs, then completed with the result or failed with a reason in error. After 24 hours the job ID expires (404); the saved run keeps the result.
Path parameters
- Name
job_id- Type
- string
- Required
- *
- Description
The
job_idfrom the start call.
How to read the result
The result (data.result) has three parts: video, creator and analysis. In analysis, start with:
outlier_score: views divided by the creator's median views (half their recent videos got more, half fewer).6.56means about 6.6 times their usual.performance_label: the verdict.
performance_label | outlier_score |
|---|---|
mega_viral | 10 or more |
viral | 3 to under 10 |
above_average | 1.5 to under 3 |
average | Under 1.5, including flops |
percentile is a good second check: 89 means it beat 89% of the creator's recent videos. New videos score low at first; judge them after a few days.
Full field reference
data: result and run_id (equal to your job_id) only when completed; error only when failed.
result.video: url, title, views, likes, comments and publish_date (UTC, or null). Ignore publishDate, an old duplicate due for removal.
result.creator: username, platform and profile (null if it couldn't load). profile holds followers, following, avatar_url, url, description, is_verified, total_videos, total_likes, total_views, total_posts and category, plus:
bio_linkon TikTok and Instagram, orattributionon YouTube (the channel header's link text, such asX, not a URL).country, a two-letter code, on TikTok only.- On YouTube,
is_verifiedis alwaysnullandfollowingalways0. - Numbers a platform doesn't share come back
nullor0. Instagram often shows0fortotal_videosandtotal_posts.
result.analysis:
videos_analyzed: up to 100, fewer if the creator has fewer videos or the platform returns fewer. At0there's no baseline: ignore the scores and label.median_views,avg_views: the creator's median and mean views.weighted_score: ln(outlier_score) × ln(median_views),0if the video didn't beat the median. It rewards beating a bigger baseline, so use it to rank videos. Not the same as the Virality Scoreweighted_scoreelsewhere, which uses followers.percentile: 0 to 100, can have decimals.std_deviation: how much the creator's views swing around the mean.z_score: how unusual these views are, given that swing (0is the mean, negative is below). It stays low for creators with a few huge hits, even whenoutlier_scoreis high.
Request
curl https://api.virlo.ai/v1/satellite/video-outlier/status/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"status": "completed",
"result": {
"video": {
"url": "https://www.instagram.com/reels/DVMBt9pE4ob/",
"title": "Japan is turning footsteps into electricity! Using piezoelectric tiles, every step you take generates a small amount of energy...",
"views": 247862,
"likes": 27368,
"comments": 185,
"publish_date": "2026-02-25T16:40:48.000Z",
"publishDate": "2026-02-25T16:40:48.000Z"
},
"creator": {
"username": "notivion.ig",
"platform": "instagram",
"profile": {
"followers": 178543,
"following": 12,
"avatar_url": "https://instagram.fsac1-2.fna.fbcdn.net/v/t51.82787-19/770751058_n.jpg",
"url": "https://www.instagram.com/notivion.ig/",
"description": "Small artist and animator",
"is_verified": false,
"total_videos": 0,
"total_likes": null,
"total_views": null,
"total_posts": 0,
"category": null,
"bio_link": null
}
},
"analysis": {
"videos_analyzed": 100,
"median_views": 37779,
"avg_views": 131447,
"outlier_score": 6.56,
"weighted_score": 19.83,
"percentile": 89,
"std_deviation": 319747,
"z_score": 0.36,
"performance_label": "viral"
}
},
"run_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}
Wait for the result
Check the status every 10 to 15 seconds, as below. Still processing after 10 minutes (rare, such as after a server restart)? Start a new check, at another $0.50.
Or have Virlo notify your server when a check finishes or fails: use the satellite.lookup.completed webhook (data.type is video_outlier).
Start and wait
const API = 'https://api.virlo.ai/v1';
const headers = {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
};
async function analyzeVideo(url, platform) {
// 1. Start the check ($0.50)
const start = await fetch(`${API}/satellite/video-outlier`, {
method: 'POST',
headers,
body: JSON.stringify({ url, platform })
});
if (!start.ok) throw new Error(`Start failed: ${start.status}`);
const jobId = (await start.json()).data.job_id;
// 2. Check every 10 seconds until it finishes. Give up after 10 minutes.
const deadline = Date.now() + 10 * 60 * 1000;
while (Date.now() < deadline) {
await new Promise((resolve) => setTimeout(resolve, 10_000));
const res = await fetch(`${API}/satellite/video-outlier/status/${jobId}`, { headers });
if (!res.ok) throw new Error(`Status check failed: ${res.status}`);
const job = (await res.json()).data;
if (job.status === 'completed') return job.result;
if (job.status === 'failed') throw new Error(job.error ?? 'Check failed');
}
throw new Error(`Still processing after 10 minutes (job ${jobId})`);
}
Re-read past runs
Every check, failed ones too, is saved as a run that is free to read and never expires. Its ID is your job_id.
GET /v1/satellite/runs?type=video_outlier: your checks, newest first.GET /v1/satellite/runs/:run_id: one check, with the verdict atdata.result.analysis. Its top-levelanalysisis alwaysnullhere.
The creator's comparison videos aren't saved, so /runs/:run_id/videos returns an empty list. See all run fields.
Errors
Error responses aren't wrapped in data and are never charged. Check the top-level code, not the message. See Errors.
A failed check is different: it started, so it's charged. For example, the video is deleted or private, or its creator can't be found. Open the link in a logged-out browser first.
- Name
400 Bad Request- Description
Bad
urlorplatform, or an extra field.messageis usually a list, sometimes a string. If it isn't about your input (likeFailed to analyze video), the problem is on Virlo's side: retry shortly.
- Name
401 Unauthorized- Description
No API key (
missing_api_key), or a wrong or inactive one (invalid_api_key).
- Name
402 Payment Required- Description
Balance under $0.50 (50 credits, at $0.01 each). Add funds.
- Name
404 Not Found- Description
The job ID is unknown, another account's, or over 24 hours old. Read the saved run.
- Name
429 Too Many Requests- Description
Wait
retry_afterseconds, then retry.
