Track creators and videos
Watch competitors, vet a creator before a paid deal, or see how a sponsored post performs. Virlo re-checks a TikTok, YouTube, or Instagram creator or video on your schedule.
- What it does
- Watches a creator or one video, and writes a fresh AI report on each check.
- You send
- A creator's handle or profile link, or a video link, plus how often to check.
- You get back
- An ID right away. Then numbers, history, AI reports, and alerts such as breakout videos.
- Cost
- $0.25 to start, then $0.25 per check until you pause or stop. Reading is free.
- How long
- The first report takes 1 to 2 minutes for a creator, and under a minute for a video.
How tracking works
- Start with Track a creator or Track a video. You get an
idand pay $0.25, which covers the first check. - Wait for the first check. Ask for the item again every 15 seconds, or whatever
retry_after_secondssays (free; this is called polling), untilenrichment_statusisreadyorfailed. Or use thetracking.cycle.completedwebhook. - Read the results, free: snapshots (history), the AI report, signals (alerts), and posts.
- It repeats at $0.25 per check until you pause or stop.
| Field | Values |
|---|---|
enrichment_status | Report progress: pending, processing, ready, or failed. failed: 3 attempts in a row failed (for example, a wrong handle). A new item shows this within about a minute. Tracking pauses, and a failed first check is refunded. |
status | active, paused (no checks or charges: you paused it, or Virlo did after 3 failures or a low balance), or deleted (stopped, but still readable by id). |
A check (the API also says cycle or scrape) fetches the latest numbers, saves them as a snapshot, and writes an AI report. An audience snapshot is different: a $0.50 profile of a creator's commenters.
Details for developers
Base URL: https://api.virlo.ai/v1/tracking. Results come in data, and lists add pagination. Times are ISO 8601 in UTC. Unknown parameters return 400. Rates are fractions (0.05 = 5%) unless noted. Tracked creators also have pending_jobs and finalized, as in How results load. Tracked videos don't.
Images. For tracked creators, avatar_url, a post's thumbnail_url, and a sound's cover_url are file names. Put https://auth.virlo.ai/storage/v1/object/public/ plus avatars/, thumbnails/, or sound-covers/ in front. A value that starts with https:// is already a link. Tracked videos return platform links, and TikTok's expire.
What it costs
- Start: $0.25, covering the first check. Refunded if Virlo can't find the creator or video.
- Each later check: $0.25, charged only when it succeeds.
- Extras: older posts $0.50 to $2.00, and an audience snapshot $0.50.
- Everything else is free.
Later checks are billed silently (only the start charge appears in the X-Cost header), so watch your balance and Usage page. If your balance can't cover a check, tracking pauses and won't restart when you add funds: resume it yourself.
Track a creator
Starts tracking a creator and runs the first check right away.
Cost: $0.25. Refunded within about a minute if Virlo can't find the creator.
How long: 1 to 2 minutes for the first report. Poll Get tracked creator.
Each creator can be tracked once per account, across the web app and the API. If it's already tracked, you get a 409 and no charge. The message says where. If it's in this key's workspace, you also get its creator_id. A creator you stopped through the API is restored instead.
Request body
- Name
platform- Type
- string
- Required
- *
- Description
tiktok,youtube, orinstagram, in lowercase.
- Name
handle- Type
- string
- Description
Such as
khaby.lame. Sendhandleorurl. If both,handlewins.
- Name
url- Type
- string
- Description
The profile link, with
https://:https://www.tiktok.com/@username,https://www.instagram.com/username, orhttps://www.youtube.com/@handle(/channel/,/c/, and/user/links work too).
- Name
scrape_cadence- Type
- string
- Description
six_hours,twelve_hours,daily(default),every_other_day,weekly,bi_weekly, ormonthly.
- Name
collection_depth- Type
- string
- Description
Also collect older posts once:
standard(50 videos, +$0.50),deep(200, +$1.00) orfull(500, +$2.00). Refunded if it finds no posts or fails.
Request
curl -X POST https://api.virlo.ai/v1/tracking/creators \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platform": "tiktok",
"handle": "khaby.lame",
"scrape_cadence": "daily"
}'
Response
{
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "active",
"message": "Creator tracking started. Initial metrics and AI report are being generated.",
"pending_jobs": [
{
"type": "tracking_report",
"status": "pending",
"poll_url": "/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"result_path": "data",
"webhook_event": "tracking.cycle.completed",
"retry_after_seconds": 15
}
],
"finalized": false
}
}
A 402 has two shapes. Both have code and required_credits.
List tracked creators
Creators your team tracks through the API, newest first, including paused ones. Stopped creators and creators tracked in the web app aren't listed. Each item is a full creator.
Cost: Free.
Query parameters
- Name
search- Type
- string
- Description
Part of a handle or display name.
- Name
platform- Type
- string
- Description
tiktok,youtube, orinstagram.
- Name
page- Type
- integer
- Description
Default
1.
- Name
limit- Type
- integer
- Description
Default
20. Over 100 counts as 100.
Request
curl -G https://api.virlo.ai/v1/tracking/creators \
-H "Authorization: Bearer YOUR_API_KEY" \
-d search=khaby
Response
{
"data": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"platform": "tiktok",
"platform_handle": "khaby.lame",
"status": "active",
"scrape_cadence": "daily",
"enrichment_status": "ready",
"latest_followers": 162973075,
"growth_rate": 0.00031009,
"next_scrape_at": "2026-09-25T14:00:05.120+00:00"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"total_pages": 1,
"has_next_page": false,
"has_prev_page": false
}
}
Get tracked creator
One tracked creator: latest numbers, settings, and check progress.
Cost: Free.
Full field reference
Every field is in the example. Notes:
growth_rate: change since the last check, in total views on YouTube and followers elsewhere. It reads1after the first check.followers_gained: equals all followers after the first check.latest_total_likes:0on YouTube and Instagram.latest_total_views: the channel total on YouTube. Elsewhere, the sum over stored posts.profile_metadata: differs by platform.external_linksis an object.next_scrape_at: the check starts within about 5 minutes of this time.
Request
curl https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"platform": "tiktok",
"platform_handle": "khaby.lame",
"profile_url": "https://www.tiktok.com/@khaby.lame",
"display_name": "Khabane lame",
"avatar_url": "7c2e9f4b1a8d3c6e5f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d8e.jpg",
"bio": "If u wanna laugh u r in the right place",
"is_verified": true,
"status": "active",
"scrape_cadence": "daily",
"enrichment_status": "ready",
"latest_followers": 162973075,
"latest_following": 81,
"latest_total_likes": 2681204805,
"latest_total_views": 463241900,
"latest_total_videos": 1355,
"last_scraped_at": "2026-09-24T14:00:05.120+00:00",
"growth_rate": 0.00031009,
"followers_gained": 50521,
"next_scrape_at": "2026-09-25T14:00:05.120+00:00",
"category": "comedy",
"content_tags": ["silent-comedy", "life-hacks", "reactions"],
"profile_metadata": {
"country": null,
"website": null,
"language": "en",
"external_links": {}
},
"created_at": "2026-09-20T10:30:00.000+00:00",
"updated_at": "2026-09-24T14:00:31.402+00:00",
"pending_jobs": [],
"finalized": true
}
}
Get creator report
The latest AI report on the creator, rewritten each check: what works, breakout videos (viral_content), and how commenters react. report is null until the first check is done.
Cost: Free.
collection_data lists the videos the report used. popular_videos is TikTok only, and YouTube uses shorts.
Request
curl https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/report \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"account": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"platform": "tiktok",
"platform_handle": "khaby.lame",
"latest_followers": 162973075
},
"report": {
"id": "c7d8e9f0-a1b2-4c3d-9e4f-5a6b7c8d9e0f",
"tracking_account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"analysis": {
"overview": {
"headline": "163M-follower comedy creator known for silent reactions...",
"recent_focus": "Everyday mishaps and travel gags...",
"content_focus": "Language-free comedy that works in any country...",
"popular_focus": "Silent reactions to overcomplicated life hacks...",
"growth_insight": "Follower growth is steady but slowing..."
},
"key_insight": "Wordless storytelling travels across languages...",
"what_works": [
{
"insight": "Silent, non-verbal storytelling",
"evidence": "His top videos contain no spoken words...",
"evidence_video_ids": ["7678009073421405471"]
}
],
"discoveries": [
{ "text": "Posts at almost the same time of day...", "metric": "3 posts/week", "evidence_video_ids": [] }
],
"viral_content": [
{
"title": "They were there yesterday, I promise #learnfromkhaby #comedy",
"views": 101400000,
"outlier_ratio": 8.52,
"why_it_worked": "A relatable mix-up with a silent payoff...",
"platform_video_id": "7678009073421405471"
}
],
"content_themes": [
{
"name": "Life hack reactions",
"avg_views": 89400000,
"description": "Watches an overcomplicated solution, then shows the simple one...",
"video_count": 8,
"evidence_video_ids": ["7678009073421405471"]
}
],
"posting_patterns": {
"frequency": "2 to 3 videos per week...",
"best_formats": ["Silent reaction to a life hack"],
"optimal_duration": "13 to 18 seconds"
},
"subjects_covered": ["Life hack reactions", "Travel mishaps"],
"audience_sentiment": {
"overall_summary": "Overwhelmingly positive and global...",
"sentiment_labels": ["highly_positive", "appreciative"],
"notable_comments": [
{ "likes": 190974, "content": "Learn from Khaby", "insight": "Fans treat him as a teacher of common sense", "video_id": "7678009073421405471" }
],
"key_findings": [
{ "finding": "Comments come in many languages...", "takeaway": "Keep videos wordless to reach every market..." }
]
}
},
"collection_data": {
"latest_videos": [
{
"url": "https://www.tiktok.com/@khaby.lame/video/7688400123809893662",
"title": "Yeah, I'm never taking these glasses off again. #learnfromkhaby",
"views": 1100000,
"likes": 64000,
"comments": 820,
"shares": 1900,
"bookmarks": 3100,
"duration": null,
"published_at": "2026-09-22T16:39:49.000Z",
"thumbnail_url": "0174d2837f7635b2bed46a3bff5e03ec16fe26465600f3839f56b68e69911c2a.webp",
"platform_video_id": "7688400123809893662"
}
],
"popular_videos": [
{
"url": "https://www.tiktok.com/@khaby.lame/video/7678009073421405471",
"title": "They were there yesterday, I promise #learnfromkhaby #comedy",
"views": 101400000,
"likes": 6200000,
"comments": 31000,
"shares": 450000,
"bookmarks": 120000,
"duration": null,
"published_at": "2026-08-25T16:36:58.000Z",
"thumbnail_url": "6893372b005aa6d33df99bfd7c8093090c52ead2dc2a83c346972e8a749f47c1.webp",
"platform_video_id": "7678009073421405471"
}
],
"shorts": [],
"shorts_count": 0,
"comments_collected": 40,
"transcripts_collected": 0,
"top_video_transcripts": {}
},
"created_at": "2026-09-24T14:00:31.402+00:00"
}
}
}
Get creator signals
Alerts from the creator's checks, newest first.
Cost: Free.
type | Raised when |
|---|---|
outlier_video | A video got over 3 times the median views. Once per video. |
follower_spike, follower_decline | Followers moved at least 3% and 250 followers since the last check (critical at 10% or more). payload.pct is a percent. |
new_subject | The new report covers new topics. |
creator_unreachable | 3 failed attempts paused tracking. |
weighted_score ranks breakouts: it rises with both outlier_ratio and median views. It's not the agent pages' Virality Score.
read is always false. To spot new alerts, keep the newest created_at you've seen.
Query parameters
- Name
limit- Type
- integer
- Description
Default
50, at most 100. There's no paging or date filter.
Request
curl "https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/signals?limit=20" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": [
{
"id": "7d8e9f0a-1b2c-4d3e-8f4a-5b6c7d8e9f0a",
"type": "outlier_video",
"severity": "notable",
"title": "Outlier video: They were there yesterday, I promise #learnfromkhaby #comedy",
"payload": {
"url": "https://www.tiktok.com/@khaby.lame/video/7678009073421405471",
"title": "They were there yesterday, I promise #learnfromkhaby #comedy",
"views": 101400000,
"platform": "tiktok",
"median_views": 11900000,
"outlier_ratio": 8.52,
"weighted_score": 34.91,
"platform_handle": "khaby.lame",
"platform_video_id": "7678009073421405471"
},
"created_at": "2026-08-26T14:01:12.431+00:00",
"read": false
}
]
}
Get creator snapshots
The creator's numbers at each check, one row per check.
Cost: Free.
You get the most recent limit checks in your date range, listed oldest first. There's no paging.
delta_*compares with the check before it. The first row's arenullonly when there's no earlier check.engagement_rateisn't the usual metric: it'stotal_likes÷total_views(nullif views are 0). On TikTok that's profile likes over about 20 stored posts' views, so values like5.79are common. Use it only as one creator's trend. It's0on YouTube and Instagram.subscribersrepeatsfollowerson YouTube and isnullelsewhere.
Query parameters
- Name
start_date- Type
- string
- Description
ISO 8601, such as
2026-09-01.
- Name
end_date- Type
- string
- Description
A date alone means the start of that day, so that day is left out. Add
T23:59:59Zto include it.
- Name
limit- Type
- integer
- Description
How many of the most recent checks to return, 1 to 365. Default
30.
Request
curl -G https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/snapshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-d start_date=2026-09-17T00:00:00Z
Response
{
"data": [
{
"id": "1b2c3d4e-5f6a-4b7c-9d8e-0f1a2b3c4d5e",
"tracking_account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"followers": 162973075,
"following": 81,
"subscribers": null,
"total_videos": 1355,
"total_views": 463241900,
"total_likes": 2681204805,
"collected_post_count": 20,
"snapshot_at": "2026-09-24T14:00:05.120+00:00",
"engagement_rate": 5.787915,
"delta_followers": 50521,
"delta_following": 0,
"delta_total_videos": 1,
"delta_total_views": 1253800,
"delta_total_likes": 1254805,
"delta_engagement_rate": -0.012992
}
]
}
Update tracked creator
Pause, resume, or change the cadence. Send only what changes. The response is the full creator.
Cost: Free, but resuming triggers a $0.25 check.
- Resuming (
status: "active") runs that check now, or within an hour if the last one was under an hour ago. - A new
scrape_cadencesets the next check one full interval from now. Send it withstatusto resume without an immediate check.
Request body
The handle can't change: stop tracking and track the new one.
- Name
status- Type
- string
- Description
activeorpaused.
- Name
scrape_cadence- Type
- string
- Description
As in Track a creator.
Request
curl -X PATCH https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "scrape_cadence": "weekly" }'
Response
{
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"platform": "tiktok",
"platform_handle": "khaby.lame",
"status": "active",
"scrape_cadence": "weekly",
"next_scrape_at": "2026-10-01T16:20:41.918+00:00"
}
}
Stop tracking creator
Stops checks and charges, and hides the creator from your list. To take a break, pause instead.
Cost: Free.
- Everything stays readable by
id, withstatus: "deleted". - To come back, track the handle again (same
idand history, $0.25), or update theidtopausedoractive. If the last check was under an hour ago, the new one can take up to an hour to start. - A second DELETE also returns
204.
Request
curl -X DELETE https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer YOUR_API_KEY"
Response
(empty response body)
List creator posts
The creator's stored videos, with their stats.
Cost: Free.
Not the full history. Each check stores TikTok's 10 or so newest and 10 most popular videos, up to Instagram's 90 newest, or YouTube's Shorts only. For older videos, collect posts with deep or full.
Query parameters
- Name
sort- Type
- string
- Description
publish_date_desc(default),publish_date_asc, orviews_desc.
- Name
start_date- Type
- string
- Description
Published on or after. ISO 8601.
- Name
end_date- Type
- string
- Description
Published on or before.
- Name
page- Type
- integer
- Description
Default
1.
- Name
limit- Type
- integer
- Description
1 to 200. Default
50.
Full field reference
Every field is in the example. Notes:
is_outlier: over 3 times the median views on the check that stored it. Otherwiseoutlier_ratioandoutlier_weighted_scorearenull.sharesandbookmarks: TikTok only,0elsewhere.duration_seconds:nullon TikTok.sound:external_idis the platform's sound ID. YouTube posts get a sound only fromdeeporfullcollections.usage_countandowner_handleare often0ornull.
Request
curl -G "https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d limit=20 \
-d sort=views_desc
Response
{
"data": [
{
"id": "c3d4e5f6-a7b8-4901-8def-123456789012",
"tracking_account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"platform": "tiktok",
"platform_video_id": "7678009073421405471",
"url": "https://www.tiktok.com/@khaby.lame/video/7678009073421405471",
"title": "They were there yesterday, I promise #learnfromkhaby #comedy",
"description": "They were there yesterday, I promise #learnfromkhaby #comedy",
"thumbnail_url": "6893372b005aa6d33df99bfd7c8093090c52ead2dc2a83c346972e8a749f47c1.webp",
"publish_date": "2026-08-25T16:36:58+00:00",
"views": 101400000,
"likes": 6200000,
"comments": 31000,
"shares": 450000,
"bookmarks": 120000,
"is_duet": false,
"is_stitch": false,
"duration_seconds": null,
"hashtags": ["learnfromkhaby", "comedy"],
"collected_at": "2026-09-24T14:00:21.469+00:00",
"is_outlier": true,
"outlier_ratio": 8.52,
"outlier_weighted_score": 34.91,
"sound": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "original sound - khaby.lame",
"duration": 15,
"platform": "tiktok",
"cover_url": "abb4e3bcf8d355936aa54a444b83930591647f6c412843f9fa40dbb71478ce9a.jpg",
"external_id": "7559312683885201425",
"is_original": true,
"usage_count": 0,
"owner_handle": null,
"owner_nickname": "Khabane lame",
"is_commerce_music": false
}
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 20,
"total_pages": 1,
"has_next_page": false,
"has_prev_page": false
}
}
Get creator post
One stored post, with the same fields as the list.
Cost: Free.
Path parameters
- Name
post_id- Type
- string
- Required
- *
- Description
The post's
idfrom List creator posts. A platform video ID returns404.
Request
curl "https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/posts/c3d4e5f6-a7b8-4901-8def-123456789012" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"id": "c3d4e5f6-a7b8-4901-8def-123456789012",
"platform_video_id": "7678009073421405471",
"url": "https://www.tiktok.com/@khaby.lame/video/7678009073421405471",
"views": 101400000,
"is_outlier": true,
"outlier_ratio": 8.52,
"outlier_weighted_score": 34.91
}
}
Collect creator posts
Stores a creator's older videos once, for more history than checks keep.
Cost: set by depth, charged when it starts. Refunded in full if it finds no posts or its last attempt fails.
depth | Gets | Cost |
|---|---|---|
standard (default) | Up to 50 videos | $0.50 |
deep | Up to 200 videos | $1.00 |
full | Up to 500 videos | $2.00 |
How long: seconds for standard, longer for deep and full. Poll Get collection status.
- Every depth pages back to its target. On TikTok it also adds the most popular videos: one page at
standard, up to 100 atdeepandfull. - Wait for a successful check first (
enrichment_status: "ready"). If the last check failed, you get a409and no charge. - One collection at a time. Another returns a
409.
Request body
- Name
depth- Type
- string
- Description
standard,deep, orfull.
- Name
force- Type
- boolean
- Description
trueskips the failed-check409. A forced collection that finds nothing is still refunded.
Request
curl -X POST "https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/posts/collect" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "depth": "deep" }'
Response
{
"data": {
"collection_id": "e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a8b",
"status": "processing",
"depth": "deep",
"max_videos": 200,
"credits_reserved": 100
}
}
credits_reserved is the charge in credits (100 = $1.00).
Get collection status
Checks on a post collection. status is processing, completed, or failed (with an error). videos_collected includes videos Virlo already had. If a collection found no posts or failed, credits_refunded shows what was paid back (in credits: 50 = $0.50). It appears only when there was a refund. The status is kept for 24 hours, then returns 404.
Cost: Free.
Request
curl "https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/posts/collect/e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a8b" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"collection_id": "e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a8b",
"status": "completed",
"depth": "deep",
"videos_collected": 200,
"max_videos": 200,
"started_at": "2026-09-24T16:02:10.114Z",
"completed_at": "2026-09-24T16:03:21.580Z"
}
}
Get posting cadence
How often a creator posts, counted from stored posts only.
Cost: Free.
TikTok checks mix in old hit videos, so a daily poster can show under 1 post a week, and YouTube counts Shorts only. A deep or full collection helps, but the real rate is usually higher.
Weekdays run from "0" (Sunday) to "6", in UTC. Months are 30 days. With no posts, the rates are null.
Request
curl "https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/posting-cadence" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"total_posts": 200,
"avg_days_between_posts": 2.71,
"posts_per_week": 2.6,
"posts_per_month": 11.13,
"day_of_week_distribution": {
"0": 24, "1": 31, "2": 30, "3": 29,
"4": 28, "5": 30, "6": 28
},
"earliest_post_date": "2025-04-02T16:30:00.000Z",
"latest_post_date": "2026-09-23T17:40:45.000Z"
}
}
Audience data
Find out who engages with a tracked creator: age, gender, language, country, and city. Virlo builds an audience snapshot from the people who comment on recent videos.
- You ask for it with Refresh audience snapshot. Tracking never makes one, and the creator needs a successful check first.
- Cost: $0.50 per new snapshot, charged when it starts. Refunded automatically if the job fails or only has the creator's profile. Reading is free.
- Demographics and geography read the same snapshot.
data_source | Meaning |
|---|---|
comments | Commenters. The usual case. |
mixed or followers | TikTok, when commenters are few: adds followers, or uses only followers. |
comments_extended | Instagram and YouTube: commenters from more posts. |
profile_only | A guess from the profile. Always low confidence, and refunded. |
confidence_level is high (usually 200 or more people in sample_size), medium (100 or more), or low. confidence_per_signal scores each field from 0 to 1.
Refresh audience snapshot
Gets audience data. A snapshot younger than freshness_days comes back free (source: "cache"). Otherwise Virlo starts a new one (source: "fresh") and returns a job_id. Both return 202.
Cost: $0.50 for a new snapshot. Reusing one is free, but needs a $0.50 balance.
How long: 5 to 12 minutes. Poll the job, or wait for the audience.snapshot.completed webhook.
Repeating this call while a job runs is free. You get the same job_id back, with credits_used: 0.
A 409 means no check has succeeded yet, or the last one failed. Wrong handle? Stop tracking and track the right one. PATCH can't fix it, whatever the hint says.
Request body
- Name
freshness_days- Type
- integer
- Description
0 to 365. Default
30.0always makes a new one.
- Name
force- Type
- boolean
- Description
trueignores saved snapshots and skips the409. $0.50 each time, unless a job is already running.
Request
curl -X POST "https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/audience-refresh" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "freshness_days": 30 }'
Response
{
"data": {
"source": "fresh",
"snapshot": null,
"job_id": "9f8e7d6c-5b4a-4392-8a1b-0c9d8e7f6a5b",
"status": "processing",
"credits_used": 50,
"creator_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"credit_unit": "cent",
"pending_jobs": [
{
"type": "audience_demographics",
"status": "processing",
"job_id": "9f8e7d6c-5b4a-4392-8a1b-0c9d8e7f6a5b",
"poll_url": "/v1/audience/snapshot/9f8e7d6c-5b4a-4392-8a1b-0c9d8e7f6a5b",
"result_path": "data.snapshot",
"webhook_event": "audience.snapshot.completed",
"retry_after_seconds": 15
}
],
"finalized": false
}
}
credits_used is in credits (50 = $0.50).
Check audience refresh status
Checks on an audience job. status is processing, completed (with the snapshot), or failed.
Cost: Free.
- A failure has
error.codeanderror.message(INSUFFICIENT_SAMPLEmeans too few people), and is refunded. - The job is kept for 24 hours, then returns
404. The snapshot stays readable. pending_jobs[].poll_urlworks too. This route has friendlier field names.
Request
curl "https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/audience-refresh/9f8e7d6c-5b4a-4392-8a1b-0c9d8e7f6a5b" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"job_id": "9f8e7d6c-5b4a-4392-8a1b-0c9d8e7f6a5b",
"status": "completed",
"snapshot": {
"snapshot_id": "f5a3b2c1-d4e5-4f6a-8b7c-9d0e1f2a3b4c",
"snapshot_at": "2026-09-24T16:27:09.261+00:00",
"sample_size": 500,
"confidence_level": "high",
"data_source": "comments",
"model_version": "v1"
},
"error": null,
"pending_jobs": [],
"finalized": true
}
}
Get audience demographics
Age, gender, and language from the latest audience snapshot. Reading never starts a new one.
Cost: Free.
- You always get the latest snapshot, however old.
freshness_daysonly setsis_stale: truewhen it's older. Without it,is_staleisfalse. snapshotisnullif there's none. If the first is still running,pending_jobs[0]has itsjob_id.- Language
unmeans unknown.
Query parameters
- Name
freshness_days- Type
- integer
- Description
0 to 365. Only sets
is_stale.
Request
curl "https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/audience-demographics?freshness_days=30" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"platform": "tiktok",
"handle": "khaby.lame",
"snapshot": {
"snapshot_id": "f5a3b2c1-d4e5-4f6a-8b7c-9d0e1f2a3b4c",
"snapshot_at": "2026-09-24T16:27:09.261+00:00",
"sample_size": 500,
"age_distribution": { "13-17": 0.14, "18-24": 0.46, "25-34": 0.32, "35-44": 0.06, "45+": 0.02 },
"gender_distribution": { "male": 0.45, "female": 0.55 },
"language_distribution": { "en": 0.62, "it": 0.18, "pt": 0.09, "es": 0.07, "un": 0.04 },
"country_distribution": null,
"city_distribution": null,
"confidence_per_signal": { "age": 0.72, "city": 0.69, "gender": 0.84, "country": 0.79, "language": 0.92 },
"confidence_level": "high",
"data_source": "comments",
"signal_breakdown": { "comments": 500, "followers": 0 },
"evidence_summary": "Analysis of 500 commenters across 30 recent posts shows...",
"model_version": "v1"
},
"is_stale": false,
"pending_jobs": [],
"finalized": true
}
}
Get audience geography
Countries and cities, from the same snapshot as demographics and with the same rules.
Cost: Free.
- A country's
namerepeats itscode, such asUS. Small countries roll up intoOther (N countries). - A city's
nameis the city.city_distributioncan benull.
Query parameters
- Name
freshness_days- Type
- integer
- Description
0 to 365. Only sets
is_stale.
Request
curl "https://api.virlo.ai/v1/tracking/creators/a1b2c3d4-e5f6-7890-abcd-ef1234567890/audience-geography" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"platform": "tiktok",
"handle": "khaby.lame",
"snapshot": {
"snapshot_id": "f5a3b2c1-d4e5-4f6a-8b7c-9d0e1f2a3b4c",
"snapshot_at": "2026-09-24T16:27:09.261+00:00",
"sample_size": 500,
"age_distribution": null,
"gender_distribution": null,
"language_distribution": null,
"country_distribution": [
{ "pct": 0.22, "code": "US", "name": "US", "confidence": 0.81 },
{ "pct": 0.19, "code": "IT", "name": "IT", "confidence": 0.84 },
{ "name": "Other (14 countries)", "pct": 0.59 }
],
"city_distribution": [
{ "pct": 0.08, "code": "IT", "name": "Milan", "confidence": 0.71 }
],
"confidence_level": "high",
"data_source": "comments",
"model_version": "v1"
},
"is_stale": false,
"pending_jobs": [],
"finalized": true
}
}
Track a video
Starts tracking one video and runs the first check right away.
Cost: $0.25. The link isn't checked first. If the video can't be read, you're refunded about 40 seconds later, and it stays paused with enrichment_status: "failed".
How long: usually under a minute. Poll Get tracked video.
Videos follow the same once-per-account rule, with video_id in the 409. A video you stopped returns 409 too. 400 Failed to create tracked video means the tracking_account_id isn't a creator you track, or you sent two YouTube /shorts/ links seconds apart.
Request body
- Name
url- Type
- string
- Required
- *
- Description
TikTok:
https://www.tiktok.com/@user/video/ID. YouTube:https://www.youtube.com/watch?v=IDorhttps://youtu.be/ID(best), or/shorts/ID. Instagram:https://www.instagram.com/reel/CODE/or/p/CODE/.
- Name
platform- Type
- string
- Required
- *
- Description
tiktok,youtube, orinstagram.
- Name
scrape_cadence- Type
- string
- Description
As in Track a creator.
- Name
tracking_account_id- Type
- string
- Description
A tracked creator's
id, if it's their video, so the report can weigh views against their followers. Can't change later.
Request
curl -X POST https://api.virlo.ai/v1/tracking/videos \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.tiktok.com/@khaby.lame/video/7678009073421405471",
"platform": "tiktok",
"scrape_cadence": "daily"
}'
Response
{
"data": {
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"status": "active",
"message": "Video tracking started. Initial metrics and AI report are being generated."
}
}
List tracked videos
Works like List tracked creators, with the same platform, page, and limit. Each item includes the whole AI report, so items are large.
Cost: Free.
Query parameters
- Name
search- Type
- string
- Description
Part of the video's title or link.
Request
curl -G https://api.virlo.ai/v1/tracking/videos \
-H "Authorization: Bearer YOUR_API_KEY" \
-d limit=20
Response
{
"data": [
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"platform": "tiktok",
"url": "https://www.tiktok.com/@khaby.lame/video/7678009073421405471",
"status": "active",
"enrichment_status": "ready",
"latest_views": 101400000,
"growth_rate": 0.0091,
"next_scrape_at": "2026-09-25T14:00:04.723+00:00"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"total_pages": 1,
"has_next_page": false,
"has_prev_page": false
}
}
Get tracked video
One tracked video: numbers, settings, transcript, and latest AI report.
Cost: Free.
Full field reference
Every field is in the example, and there's no updated_at. Notes:
growth_rate: view change since the last check.0.009means up 0.9% per check, not per day. It reads0after the first check.latest_sharesandlatest_bookmarks: TikTok only,0elsewhere.duration: oftennullon YouTube.platform_video_id: empty for a YouTube/shorts/link until the first check.analysis: the report,nulluntil the first check.
Request
curl https://api.virlo.ai/v1/tracking/videos/b2c3d4e5-f6a7-8901-bcde-f12345678901 \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"platform": "tiktok",
"platform_video_id": "7678009073421405471",
"url": "https://www.tiktok.com/@khaby.lame/video/7678009073421405471",
"title": "They were there yesterday, I promise #learnfromkhaby #comedy",
"description": "They were there yesterday, I promise #learnfromkhaby #comedy",
"thumbnail_url": "https://p16-common-sign.tiktokcdn-us.com/...",
"duration": 21,
"published_at": "2026-08-25T16:36:58+00:00",
"author_handle": "khaby.lame",
"author_name": "Khabane lame",
"author_avatar_url": "https://p19-common-sign.tiktokcdn-us.com/...",
"status": "active",
"scrape_cadence": "daily",
"enrichment_status": "ready",
"latest_views": 101400000,
"latest_likes": 6200000,
"latest_comments": 31000,
"latest_shares": 450000,
"latest_bookmarks": 120000,
"latest_transcript": null,
"growth_rate": 0.0091,
"analysis": {
"key_insight": "A relatable mix-up with a silent payoff..."
},
"analysis_updated_at": "2026-09-24T14:00:31.026+00:00",
"tracking_account_id": null,
"last_scraped_at": "2026-09-24T14:00:04.723+00:00",
"next_scrape_at": "2026-09-25T14:00:04.723+00:00",
"created_at": "2026-09-20T10:30:00.000+00:00"
}
}
Get video report
The latest AI report on the video: how it's doing, why it works, the hook, and how commenters react. analysis is null until the first check.
Cost: Free.
video is the full tracked video, analysis included. overview.engagement_rate is a percent: 7.06 means 7.06%.
Request
curl https://api.virlo.ai/v1/tracking/videos/b2c3d4e5-f6a7-8901-bcde-f12345678901/report \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"video": {
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"platform": "tiktok",
"url": "https://www.tiktok.com/@khaby.lame/video/7678009073421405471",
"latest_views": 101400000
},
"analysis": {
"overview": {
"summary": "A silent comedy bit about a missing object...",
"outlier_ratio": null,
"growth_insight": "Views are still climbing a month after posting...",
"engagement_rate": 7.06,
"growth_trajectory": "steady",
"performance_verdict": "overperforming"
},
"key_insight": "A relatable mix-up with a silent payoff...",
"what_works": [
{ "insight": "The punchline lands without a single word", "evidence": "Top comments come in many languages..." }
],
"discoveries": [
{ "text": "Saves are unusually high for a comedy clip...", "metric": "1.2% save rate" }
],
"hook_analysis": {
"hook_type": "Pattern interrupt",
"description": "Opens mid-problem, so viewers stay to see the fix...",
"effectiveness": "strong"
},
"content_breakdown": {
"topics": ["Everyday mishaps"],
"format_style": "Silent reaction with one visual punchline...",
"target_audience": "A global audience of all ages..."
},
"audience_sentiment": {
"overall_summary": "Warm and amused...",
"sentiment_labels": ["appreciative", "amused"],
"notable_comments": [
{ "likes": 52000, "content": "This is literally me every morning", "insight": "Viewers see themselves in the joke" }
],
"key_findings": [
{ "finding": "Viewers tag friends who do the same thing...", "takeaway": "Relatable mistakes drive shares..." }
]
}
},
"analysis_updated_at": "2026-09-24T14:00:31.026+00:00"
}
}
Get video snapshots
The video's views, likes, comments, shares, and saves at each check.
Cost: Free.
Works like creator snapshots, with the same start_date, end_date, and limit: the most recent checks, listed oldest first.
shares and bookmarks are 0 on YouTube and Instagram.
Request
curl -G https://api.virlo.ai/v1/tracking/videos/b2c3d4e5-f6a7-8901-bcde-f12345678901/snapshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-d start_date=2026-09-17T00:00:00Z
Response
{
"data": [
{
"id": "8734c9e6-efce-4c49-8262-2e20ac8f204f",
"tracking_video_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"views": 101400000,
"likes": 6200000,
"comments": 31000,
"shares": 450000,
"bookmarks": 120000,
"snapshot_at": "2026-09-24T14:00:04.723+00:00",
"delta_views": 920000,
"delta_likes": 20000,
"delta_comments": 200,
"delta_shares": 2000,
"delta_bookmarks": 1000
}
]
}
Update tracked video
Works like Update tracked creator, with the same status and scrape_cadence fields and the same resume rules. The link and tracking_account_id can't change. The response is the full video.
Cost: Free, but resuming triggers a $0.25 check.
Request
curl -X PATCH https://api.virlo.ai/v1/tracking/videos/b2c3d4e5-f6a7-8901-bcde-f12345678901 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "paused" }'
Response
{
"data": {
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"platform": "tiktok",
"url": "https://www.tiktok.com/@khaby.lame/video/7678009073421405471",
"status": "paused",
"scrape_cadence": "daily",
"next_scrape_at": "2026-09-25T14:00:04.723+00:00"
}
}
Stop tracking video
Stops checks and charges, and hides the video from your list. Its data stays readable by id, with status: "deleted". A second DELETE also returns 204.
Cost: Free.
A stopped video can't be tracked again. The only way back is to update the old id to paused or active. To take a break, pause instead.
Request
curl -X DELETE https://api.virlo.ai/v1/tracking/videos/b2c3d4e5-f6a7-8901-bcde-f12345678901 \
-H "Authorization: Bearer YOUR_API_KEY"
Response
(empty response body)
Webhook notifications
To get a message on your server instead of polling, subscribe with the Webhooks API (POST /v1/webhooks). Only items tracked through the API send these.
| Event | Sent when |
|---|---|
tracking.cycle.completed | A check finished, and its report is ready. |
tracking.outlier_video.detected | A creator has a new breakout video. |
tracking.paused | 3 attempts failed, or your balance can't cover a check. |
audience.snapshot.completed | An audience snapshot is ready. Not sent on failure, so also check the job. |
After a low-balance pause, add funds, then set status to active. If Virlo couldn't reach the creator or video, the handle or link can't be edited: stop tracking and track the right one. Message fields: Tracking updates.
Workflow recipes
Vet a creator before a paid deal
- Track the creator and wait for
ready: $0.25. - Refresh the audience snapshot: $0.50.
- Read the report, demographics, and geography, free.
- Stop tracking so no more checks are charged.
Total: about $0.75.
Errors
Errors are never charged. For the full list, see Errors.
| Status | Usually means |
|---|---|
400 | A missing, misspelled, or unknown field, or a value like TikTok (use lowercase). |
402 | Your balance is too low. Read code and required_credits. |
404 | No item with that ID for your team. Use Virlo's id, not the platform's video ID. |
409 | Already tracked on your account, a post collection is already running, or a post collection or audience refresh is blocked by a failed check. |
