Deep-dive lookup

Hashtag lookup

Size up one hashtag on TikTok, Instagram, or YouTube Shorts before you build a campaign or brief creators around it.

At a glance
What it does
Collects a sample of videos from one hashtag and sums up their views, creators, related tags, sounds, and posting dates. Optional trend analysis finds their creative patterns.
You send
The platform (tiktok, instagram, or youtube) and one hashtag, without the #.
You get back
A job_id right away. Check it every 10 to 15 seconds (this is called polling) until it says completed, then read the results.
Cost
$0.50, or up to $2.50 with more videos and trend analysis. Status checks, saved results, and the same lookup repeated within 6 hours are free.
How long
About 15 seconds on TikTok and 1 minute on YouTube or Instagram. Trend analysis on TikTok takes about 2 minutes. Bigger YouTube lookups take a few minutes.

Every number comes from a sample: the videos the platform lists first, not every video under the hashtag. On TikTok the sample can span years. For quick numbers on many hashtags, use Hashtags ($0.05 a request).


What it costs

You pay when the lookup starts. 1 credit is $0.01.

You ask forVideos collected, at mostPrice
Standard (the default)50, or up to 100 with max_videos$0.50 (50 credits)
trend_analysis=true, depth=deep, or bothAbout 300$1.00 (100 credits)
depth=fullAbout 500$2.00 (200 credits)
depth=full with trend analysisAbout 500$2.50 (250 credits)
  • A failed lookup is refunded in full, and the trend fee when no trends come out. Finding fewer videos than you paid for isn't refunded: depth=deep on YouTube #cleantok found 103 videos and still cost $1.00. For a small hashtag, try max_videos=100 first.
  • Repeats within 6 hours are free (cached: true) when sort matches and the saved lookup already has the trends and depth you ask for (or deeper). A different max_videos still gets the saved result as it was. Anything else is a new, billed lookup.
  • Your balance must cover the full price, even for a free repeat. To skip that check, open the saved run.
  • The exact charge is in the X-Cost (dollars) and X-Credits-Used (credits) response headers.

GET/v1/satellite/hashtags/:platform/:hashtag

Start a hashtag lookup

Starts a lookup in the background and returns its ID at data.job_id. Each new lookup is billed (unusual for a GET), so don't call it in a loop. A free repeat returns status: "completed" and cached: true instead.

Base price, before options:$0.50

Up to $2.50 with options. See What it costs.

Path parameters

  • Name
    platform
    Type
    string
    Required
    *
    Description

    tiktok, instagram, or youtube, in lowercase. YouTube collects Shorts only.

  • Name
    hashtag
    Type
    string
    Required
    *
    Description

    One tag, up to 100 characters, any case. Leave off the # (or send it as %23). Spaces and other % signs are rejected. Comma lists like cleantok,organizing are not: they run as one tag, and you're billed.

Query parameters

  • Name
    trend_analysis
    Type
    boolean
    Description

    true adds trend analysis (+$0.50) and collects about 300 videos (500 with depth=full). Only true or 1 work. True or yes count as false, with no error. Default false.

  • Name
    max_videos
    Type
    integer
    Description

    How many videos to collect, 1 to 100. Default 50. Standard lookups only.

  • Name
    sort
    Type
    string
    Description

    top (most views first, the default) or recent (newest first). It only reorders the videos, but changing it bills a new lookup.

  • Name
    depth
    Type
    string
    Description

    standard (the default, uses max_videos), deep (up to about 300 videos, +$0.50, no extra with trend analysis), or full (up to about 500, +$1.50). The charge stays the same if fewer turn up. Not available on Instagram.

Request

GET
/v1/satellite/hashtags/:platform/:hashtag
curl -G https://api.virlo.ai/v1/satellite/hashtags/tiktok/cleaninghacks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d trend_analysis=true

Response

{
  "data": {
    "job_id": "0bebf4eb-01a0-4b3c-b880-3c36fe32c4ea",
    "status": "processing"
  }
}

GET/v1/satellite/hashtags/status/:job_id

Check lookup status

Free to call. status is processing, then completed (with result) or failed (with error, refunded in full). Keep checking until you see one of those.

This check works for 24 hours, then returns 404. The same ID still opens the saved run.

Rather not poll? The satellite.lookup.completed webhook, with type: "hashtag_lookup", fires on success or failure. A free repeat sends no webhook, so read its result right away.

What's in the result

  • Name
    run_id
    Type
    string
    Description

    Same value as your job_id. Reopens this result for free.

  • Name
    stats
    Type
    object
    Description

    See Stats.

  • Name
    trends
    Type
    object
    Description

    See Trend analysis. analyzed: false if you didn't ask for it.

  • Name
    videos
    Type
    array
    Description

    The collected videos, in your sort order.

  • Name
    request
    Type
    object
    Description

    Your settings as applied. max_videos shows the real target: 300 or 500 on bigger lookups.

Request

GET
/v1/satellite/hashtags/status/:job_id
curl https://api.virlo.ai/v1/satellite/hashtags/status/0bebf4eb-01a0-4b3c-b880-3c36fe32c4ea \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "data": {
    "status": "completed",
    "result": {
      "run_id": "0bebf4eb-01a0-4b3c-b880-3c36fe32c4ea",
      "request": {
        "hashtag": "cleaninghacks",
        "platform": "tiktok",
        "trend_analysis": true,
        "max_videos": 300,
        "sort": "top",
        "depth": "standard"
      },
      "hashtag": {
        "name": "cleaninghacks",
        "platform": "tiktok",
        "page_url": "https://www.tiktok.com/tag/cleaninghacks"
      },
      "data_captured_at": "2026-09-24T17:48:57.782Z",
      "credits_charged": 100,
      "stats": {
        "videos_analyzed": 300,
        "views": { "total": 1529643491, "avg": 5098812, "median": 2628772, "max": 36788449, "min": 1011 },
        "engagement": {
          "total_likes": 93695696, "total_comments": 440623, "total_shares": 4075438, "total_collects": 10542388,
          "avg_likes": 312319, "avg_comments": 1469, "avg_shares": 13585, "avg_collects": 35141,
          "engagement_rate": 0.0711
        },
        "velocity": {
          "videos_per_week": [{ "iso_week": "2026-W38", "count": 8 }, { "iso_week": "2026-W39", "count": 14 }],
          "last_4w_avg_videos_per_week": 7.5,
          "prior_4w_avg_videos_per_week": 4.5,
          "is_accelerating": true
        },
        "verified_creator_count": 36,
        "verified_creator_pct": 0.12,
        "duration_distribution": { "under_15s": 33, "between_15_30s": 64, "between_30_60s": 47, "over_60s": 110 },
        "top_creators": [
          { "unique_id": "creator_a", "nickname": "Creator A", "is_verified": true, "follower_count": null, "video_count": 10, "total_views": 95651889, "avg_views": 9565189 }
        ],
        "related_hashtags": [
          { "hashtag": "cleantok", "used_count": 172, "total_views": 820116970, "avg_views": 4768122 }
        ],
        "top_sounds": [
          { "external_id": "7468711641658525713", "title": "SHAKE IT TO THE MAX (FLY) [REMIX]", "artist": "MOLIY & Shenseea & Skillibeng & Silent Addy", "is_original": false, "used_count": 2, "total_views": 38805562, "avg_views": 19402781 }
        ],
        "top_video": { "id": "7171372479372365099", "...": "same fields as a videos[] item" }
      },
      "sample_quality": { "truncated_by_cap": true, "pages_fetched": 17, "note": "deep_corpus" },
      "trends": {
        "analyzed": true,
        "status": "ok",
        "summary": "The #cleaninghacks corpus reveals a strong and continuous interest in practical, satisfying, and motivational cleaning content.",
        "trends": [
          {
            "name": "Quick Cleaning Hacks & Everyday Tips",
            "description": "Short, practical videos demonstrating clever and easy cleaning solutions or organizational tips for daily household problems.",
            "tactics": ["Present a common problem and a quick solution", "Target everyday household items or situations"],
            "confidence": 0.92,
            "video_count": 82,
            "evidence_video_ids": ["6984134268918271237", "7099896027146177797", "..."],
            "time_windows": [
              { "start_date": "2020-05-26", "end_date": "2026-09-04", "video_count": 82, "total_views": 494830450, "total_likes": 30599073, "total_comments": 130883, "total_shares": 1640360, "avg_views": 6034518, "description": "A continuous run of quick cleaning tips and life hacks from 2020 to 2026." }
            ],
            "resurged": false,
            "momentum": null
          }
        ]
      },
      "videos": [
        {
          "id": "7171372479372365099",
          "url": "https://www.tiktok.com/@creator_b/video/7171372479372365099",
          "description": "Car retreading #fyp #carbeauty #cleaninghacks",
          "publish_date": "2022-11-29T09:48:06.000Z",
          "duration_seconds": 15,
          "views": 36788449, "likes": 630082, "comments": 4351, "shares": 30904, "collects": 69181,
          "hashtags": ["fyp", "carbeauty", "cleaninghacks"],
          "is_duet": false,
          "is_stitch": false,
          "region": "US",
          "author": { "unique_id": "creator_b", "nickname": "Creator B", "is_verified": false, "follower_count": null }
        }
      ]
    }
  }
}

What each platform returns

Each platform shares different data, so compare hashtags within one platform.

TikTokYouTubeInstagram
Where videos come fromThe hashtag page, including photo slideshows (url contains /photo/)The hashtag page, Shorts onlyPublic reels, 100 to 150 at most, even with trend analysis
depth optionsAll threeAll threestandard only
viewsYesYes0 when Virlo couldn't look up that reel. Treat it as unknown.
shares, collects (saves)YesAlways 0Always 0
duration_secondsnull for slideshowsYesOften null
author.unique_idHandleChannel ID (starts with UC)Handle
author.follower_countnull (use a Creator lookup)Channel subscribersnull
top_soundsYesYesUsually empty
is_duet, is_stitch, regionYesfalse, nullfalse, null

Stats

Plain math over your sample, with no AI.

  • Name
    views
    Type
    object
    Description

    total, avg, median, max, and min.

  • Name
    engagement
    Type
    object
    Description

    Totals and averages of likes, comments, shares, and collects (saves). engagement_rate is their sum divided by total views (0.0711 means 7.11%). YouTube and Instagram have no shares or saves, so don't compare it across platforms.

  • Name
    velocity
    Type
    object
    Description

    How many of the sampled videos were posted each week. It reflects the sample, not every post under the hashtag.

    • videos_per_week: counts by calendar week, for up to the 26 most recent weeks that have videos. Empty weeks are left out.
    • last_4w_avg_videos_per_week, prior_4w_avg_videos_per_week: the average of the latest 4 of those weeks (or fewer, if that's all), and of up to 4 weeks before them (0 if none).
    • is_accelerating: true when the last-4-week average beats the prior one by 15% or more. Also true with 4 or fewer weeks of videos: ignore it then.
  • Name
    top_creators
    Type
    array
    Description

    Up to 10 creators with the most views in the sample.

  • Name
    related_hashtags
    Type
    array
    Description

    Up to 20 other hashtags on the same videos, ranked by total views, leaving out the one you looked up. used_count is how many videos use it.

  • Name
    top_sounds
    Type
    array
    Description

    Up to 10 sounds with the most views. is_original means the creator's own audio.

  • Name
    verified_creator_count / verified_creator_pct
    Type
    number
    Description

    How many videos come from verified accounts, and that share. It counts videos, not separate creators.

  • Name
    duration_distribution
    Type
    object
    Description

    Videos per length band. Videos of unknown length aren't counted, so the bands can add up to less than videos_analyzed.


Filled in only with trend_analysis=true. An AI model reads each video's caption, hashtags, and numbers (it doesn't watch the videos). It groups them into named creative patterns, with tactics a creator can copy. It reads up to 240 videos, most viewed first, so depth=full adds videos to the stats but not to the trends.

Each trend's time_windows are the date ranges when its videos were posted. resurged means the pattern faded and came back, and momentum compares views in the last two windows. A pattern that never paused has one window, resurged: false, and momentum: null.

status is ok, skipped (you didn't ask), or insufficient_corpus (under 10 videos, $0.50 refunded). If the AI step errors, you still get ok with an empty trends list, and the $0.50 is refunded too.

Full field reference
  • Name
    confidence
    Type
    number
    Description

    The AI's own score, from 0 to 1, for how clear the pattern is.

  • Name
    evidence_video_ids
    Type
    string[]
    Description

    The videos that show the pattern. All of them are in videos[].

  • Name
    time_windows
    Type
    array
    Description

    A sample covering under 14 days gets one window per trend.

  • Name
    momentum
    Type
    string | null
    Description

    stronger (average views 15% or more higher than the window before), weaker (15% or more lower), or similar.

A trend that came back after a gap:

A trend that resurged

{
  "name": "Before/after speed-cleans",
  "description": "Sub-30s transformations that hard-cut from mess to spotless on the beat.",
  "tactics": ["open on the worst angle of the mess", "single hard cut to the reveal", "text overlay with the time it took"],
  "confidence": 0.84,
  "video_count": 78,
  "evidence_video_ids": ["7412345678901234567", "7419876543210987654", "..."],
  "time_windows": [
    { "start_date": "2026-06-14", "end_date": "2026-06-30", "video_count": 31, "total_views": 44000000, "total_likes": 3600000, "total_comments": 21000, "total_shares": 96000, "avg_views": 1419355, "description": "First wave, mostly small-account transformations." },
    { "start_date": "2026-07-18", "end_date": "2026-07-31", "video_count": 47, "total_views": 88000000, "total_likes": 7400000, "total_comments": 43000, "total_shares": 214000, "avg_views": 1872340, "description": "Came back with larger creators joining the format." }
  ],
  "resurged": true,
  "momentum": "stronger"
}

Re-read past runs

Every paid lookup is saved as its own run that never expires. Reopening it is free:

  • GET /v1/satellite/runs/:run_id: the full saved result, under result.
  • GET /v1/satellite/runs?type=hashtag_lookup&platform=tiktok: your past hashtag lookups.
  • GET /v1/satellite/runs/:run_id/videos?limit=50&offset=0: the videos, a page at a time (limit up to 200, default 25).

A newer lookup of the same hashtag gets a new run_id. That happens after 6 hours, or sooner if you change sort, add trends, or ask for a bigger depth. The older run stays as it was, even if the new lookup fails.


Errors

These happen before a lookup starts, so they are never charged.

  • Name
    400 Bad Request
    Description

    Unknown platform. Empty hashtag, over 100 characters, or with a space or a % other than %23. depth=deep or full on Instagram. Unknown depth or sort value, max_videos outside 1 to 100, or an unknown query parameter.

  • Name
    401 Unauthorized
    Description

    API key missing (missing_api_key), or wrong or revoked (invalid_api_key). See Authentication.

  • Name
    402 Payment Required
    Description

    Balance below the full price, even for a repeat that would be free. Under $0.50, the error always says $0.50.

  • Name
    404 Not Found
    Description

    Status check only: wrong ID, another lookup type's ID, or over 24 hours old.

  • Name
    429 Too Many Requests
    Description

    Your key's daily request limit is used up. Lookups have no per-minute or hourly limit. See Rate limits.

Was this page helpful?