# Raw data

> Live, unprocessed TikTok, YouTube Shorts and Instagram Reels data in one normalized schema: keyword search, hashtag videos, video details, comments, transcripts, creator profiles and creator videos. $0.01 per call.

Source: https://dev.virlo.ai/docs/raw
Markdown: https://dev.virlo.ai/docs/raw.md
Section: Explore data

## About the Virlo API (applies to every page)

- Base URL: `https://api.virlo.ai/v1`. Every request needs the header `Authorization: Bearer YOUR_API_KEY` (keys start with `virlo_tkn_`).
- Responses are JSON inside a `data` field, except the `/v1/webhooks` endpoints, which return the object or array directly. Field names are snake_case.
- Prices are in US dollars from a prepaid balance. 1 credit = $0.01. The `X-Cost` response header on each successful response is the exact charge. Errors are free.
- Slow jobs return an ID. Check its status every 15 seconds (or whatever `retry_after_seconds` says) until `finalized` is `true`.
- All docs pages: https://dev.virlo.ai/llms.txt. Every page in one file: https://dev.virlo.ai/llms-full.txt. MCP server for AI assistants: https://dev.virlo.ai/api/mcp/mcp.

---

Live, unprocessed data from TikTok, YouTube Shorts and Instagram Reels, normalized into one schema. Virlo fetches it from the platform when you call, and the answer comes back in the same request.

**At a glance**

- **What it does:** Gets the current facts about a search, a hashtag, a video, its comments or a creator, straight from the platform.
- **You send:** A platform and a keyword, hashtag, video link or ID, or creator handle.
- **You get back:** Videos, comments, a transcript or a creator profile, with the same fields on every platform.
- **Cost:** $0.01 (1 credit) per call, including a call that finds nothing. Errors are free.
- **Synchronous.** No job to poll. Each call returns one page. Most calls answer in 1 to 6 seconds. Instagram search and hashtag calls usually take about 10 seconds, so set your client timeout to at least 30 seconds.
- **Same schema on all three platforms.** A field the platform doesn't report is `null`. Fields only one platform has are in `platform_data`.
- **Short-form only.** On YouTube, search, hashtag and creator videos return Shorts only. On Instagram they return Reels only. Video details, comments and transcripts take any video ID or URL.
- **Instagram has no transcript.** `GET /v1/raw/instagram/video/transcript` returns `400` with `unsupported_platform`.
- **Unprocessed.** No Virality Score, AI fields or history. For those, use [agents](https://dev.virlo.ai/docs/agents), [creator lookups](https://dev.virlo.ai/docs/satellite), [hooks](https://dev.virlo.ai/docs/hooks) or [Pop culture & News](https://dev.virlo.ai/docs/trends).

`:platform` is `tiktok`, `youtube` or `instagram` on every route.

## Which one do I need?

- **Videos for a keyword right now:** [keyword search](https://dev.virlo.ai/docs/raw#search)
- **Videos posted under a hashtag:** [hashtag videos](https://dev.virlo.ai/docs/raw#hashtag)
- **One video's current counts and details:** [video details](https://dev.virlo.ai/docs/raw#video)
- **What people say under a video:** [comments](https://dev.virlo.ai/docs/raw#comments)
- **What is said in a video:** [transcript](https://dev.virlo.ai/docs/raw#transcript)
- **A creator's profile and follower count:** [creator profile](https://dev.virlo.ai/docs/raw#creator)
- **A creator's videos:** [creator videos](https://dev.virlo.ai/docs/raw#creator-videos)

## The response shape

A single item comes back as `{ "data": { ... } }`. A list comes back as `{ "data": [ ... ], "pagination": { "next_cursor": "...", "has_more": true } }`. Timestamps are ISO 8601 in UTC. Counts are numbers or `null`, never strings.

Every video, from any route, has these fields:

- `id` (string, optional): The platform's video ID (TikTok video ID, YouTube video ID, Instagram shortcode).
- `platform` (string, optional): `tiktok`, `youtube` or `instagram`.
- `url` (string, optional): Link to the video.
- `caption` (string | null, optional): The caption or title.
- `hashtags` (string[], optional): Hashtags in the caption, without `#`. Empty when there are none.
- `published_at` (string | null, optional): When it was posted.
- `duration_seconds` (number | null, optional): Length in seconds.
- `thumbnail_url` (string | null, optional): Cover image. Platform image links expire after a while, so save a copy if you need it later.
- `author` (object, optional): `id`, `handle`, `display_name`, `avatar_url` and `verified`. Any of them can be `null`.
- `stats` (object, optional): `views`, `likes`, `comments`, `shares` and `saves`, each a number or `null`.
- `sound` (object | null, optional): `id`, `title` and `artist` of the audio, or `null`.
- `platform_data` (object, optional): Fields only this platform has, in snake_case. Can be empty.

---

## Keyword search

**Endpoint:** `GET https://api.virlo.ai/v1/raw/:platform/search`

Videos that match a keyword, as the platform's own search returns them now.

Cost per request: $0.01

Instagram search returns fewer results per page than TikTok and YouTube.

### Query parameters

- `q` (string, optional): Required. The keyword or phrase, 1 to 200 characters.
- `cursor` (string, optional): `next_cursor` from the previous page. See [paging](https://dev.virlo.ai/docs/raw#pagination).

**cURL request:**

```bash
curl -G "https://api.virlo.ai/v1/raw/tiktok/search" \
  --data-urlencode "q=protein breakfast" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response:**

```json
{
  "data": [
    {
      "id": "7491823365019208974",
      "platform": "tiktok",
      "url": "https://www.tiktok.com/@mealprepmia/video/7491823365019208974",
      "caption": "3 protein breakfasts under 5 minutes #protein #breakfastideas",
      "hashtags": ["protein", "breakfastideas"],
      "published_at": "2026-10-14T13:22:05Z",
      "duration_seconds": 38,
      "thumbnail_url": "https://p16-sign.tiktokcdn.com/obj/example.jpeg",
      "author": {
        "id": "6812045538201543685",
        "handle": "mealprepmia",
        "display_name": "Mia | Meal Prep",
        "avatar_url": "https://p16-sign.tiktokcdn.com/obj/avatar.jpeg",
        "verified": false
      },
      "stats": {
        "views": 418200,
        "likes": 31540,
        "comments": 212,
        "shares": 1890,
        "saves": 9620
      },
      "sound": {
        "id": "7301254880142231298",
        "title": "original sound",
        "artist": "Mia | Meal Prep"
      },
      "platform_data": {}
    }
  ],
  "pagination": {
    "next_cursor": "eyJ2IjoxLCJjIjoiQTFiMmMzIn0",
    "has_more": true
  }
}
```

---

## Hashtag videos

**Endpoint:** `GET https://api.virlo.ai/v1/raw/:platform/hashtag/:hashtag`

Videos posted under a hashtag. For stats on a hashtag over time, see [Hashtags](https://dev.virlo.ai/docs/hashtags). For a deep study of one hashtag with trends, see [Hashtag lookup](https://dev.virlo.ai/docs/satellite/hashtags).

Cost per request: $0.01

### Path parameters

- `hashtag` (string, optional): The hashtag. A leading `#` is removed; send it URL-encoded as `%23`, or leave it out.

### Query parameters

- `cursor` (string, optional): `next_cursor` from the previous page. See [paging](https://dev.virlo.ai/docs/raw#pagination).

**cURL request:**

```bash
curl "https://api.virlo.ai/v1/raw/youtube/hashtag/homegym" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response:**

```json
{
  "data": [
    {
      "id": "kq3Vb8XfT2c",
      "platform": "youtube",
      "url": "https://www.youtube.com/shorts/kq3Vb8XfT2c",
      "caption": "Garage gym on a $500 budget #homegym #shorts",
      "hashtags": ["homegym", "shorts"],
      "published_at": "2026-10-11T18:04:51Z",
      "duration_seconds": 47,
      "thumbnail_url": "https://i.ytimg.com/vi/kq3Vb8XfT2c/hq2.jpg",
      "author": {
        "id": "UCx4Rk2pQm8sT1aZ9bYc3dEf",
        "handle": "liftwithleo",
        "display_name": "Lift With Leo",
        "avatar_url": "https://yt3.ggpht.com/example=s88",
        "verified": null
      },
      "stats": {
        "views": 96400,
        "likes": 4210,
        "comments": 158,
        "shares": null,
        "saves": null
      },
      "sound": null,
      "platform_data": {}
    }
  ],
  "pagination": {
    "next_cursor": null,
    "has_more": false
  }
}
```

---

## Video details

**Endpoint:** `GET https://api.virlo.ai/v1/raw/:platform/video`

One video's details and its counts right now. To learn why a video did well against its creator's usual numbers, use the [video outlier check](https://dev.virlo.ai/docs/satellite/video-outlier).

Cost per request: $0.01

### Query parameters

Send exactly one of `url` or `id`.

- `url` (string, optional): Link to the video.
- `id` (string, optional): The platform's video ID: a TikTok video ID, a YouTube video ID or an Instagram shortcode.

**cURL request:**

```bash
curl -G "https://api.virlo.ai/v1/raw/instagram/video" \
  --data-urlencode "url=https://www.instagram.com/reel/DAbC12xYz9Q/" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response:**

```json
{
  "data": {
    "id": "DAbC12xYz9Q",
    "platform": "instagram",
    "url": "https://www.instagram.com/reel/DAbC12xYz9Q/",
    "caption": "The 10-second fix for a wobbly table",
    "hashtags": [],
    "published_at": "2026-10-09T08:47:12Z",
    "duration_seconds": 21,
    "thumbnail_url": "https://scontent.cdninstagram.com/v/example.jpg",
    "author": {
      "id": "51288730042",
      "handle": "fixitfelix.diy",
      "display_name": "Felix | DIY",
      "avatar_url": "https://scontent.cdninstagram.com/v/avatar.jpg",
      "verified": false
    },
    "stats": {
      "views": 1204500,
      "likes": 58300,
      "comments": 412,
      "shares": null,
      "saves": null
    },
    "sound": {
      "id": "1120934455312876",
      "title": "Original audio",
      "artist": "fixitfelix.diy"
    },
    "platform_data": {}
  }
}
```

---

## Video comments

**Endpoint:** `GET https://api.virlo.ai/v1/raw/:platform/video/comments`

A page of a video's comments. Replies to comments are not included.

Cost per request: $0.01

### Query parameters

Send exactly one of `url` or `id`.

- `url` (string, optional): Link to the video.
- `id` (string, optional): The platform's video ID.
- `cursor` (string, optional): `next_cursor` from the previous page. See [paging](https://dev.virlo.ai/docs/raw#pagination).

### Comment fields

- `id` (string, optional): The comment's ID.
- `text` (string, optional): What the comment says.
- `published_at` (string | null, optional): When it was posted.
- `likes` (number | null, optional): Likes on the comment.
- `reply_count` (number | null, optional): How many replies it has.
- `author` (object, optional): `id`, `handle`, `display_name`, `avatar_url` and `verified`.

**cURL request:**

```bash
curl "https://api.virlo.ai/v1/raw/tiktok/video/comments?id=7491823365019208974" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response:**

```json
{
  "data": [
    {
      "id": "7492011873320486913",
      "text": "Made the second one this morning, actually filling",
      "published_at": "2026-10-15T07:31:44Z",
      "likes": 386,
      "reply_count": 4,
      "author": {
        "id": "7038812290045513733",
        "handle": "runner.jess",
        "display_name": "Jess",
        "avatar_url": "https://p16-sign.tiktokcdn.com/obj/avatar2.jpeg",
        "verified": false
      }
    }
  ],
  "pagination": {
    "next_cursor": "eyJ2IjoxLCJjIjoiWjl5OHg3In0",
    "has_more": true
  }
}
```

---

## Video transcript

**Endpoint:** `GET https://api.virlo.ai/v1/raw/:platform/video/transcript`

What is said in a TikTok or YouTube video. Instagram is not supported and returns `400` with `unsupported_platform`.

Cost per request: $0.01

### Query parameters

Send exactly one of `url` or `id`.

- `url` (string, optional): Link to the video.
- `id` (string, optional): The platform's video ID.

### Transcript fields

- `video_id` (string, optional): The video's ID.
- `platform` (string, optional): `tiktok` or `youtube`.
- `language` (string | null, optional): Language code, such as `en`.
- `has_transcript` (boolean, optional): `false` when the video exists but has nothing to transcribe: no speech and no captions. `text` is then `""`. This is an answer, not an error, so it costs $0.01 like any other call. A video that does not exist returns `404` `not_found` instead.
- `text` (string, optional): The full transcript as one string. `""` when `has_transcript` is `false`.
- `segments` (array | null, optional): Timed lines: `start_seconds`, `end_seconds` (can be `null`) and `text`. `null` when the transcript has no timestamps.

**cURL request:**

```bash
curl "https://api.virlo.ai/v1/raw/youtube/video/transcript?id=kq3Vb8XfT2c" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response:**

```json
{
  "data": {
    "video_id": "kq3Vb8XfT2c",
    "platform": "youtube",
    "language": "en",
    "has_transcript": true,
    "text": "Here's my whole garage gym and it cost under five hundred dollars. Rack was one fifty used.",
    "segments": [
      {
        "start_seconds": 0,
        "end_seconds": 3.4,
        "text": "Here's my whole garage gym and it cost under five hundred dollars."
      },
      {
        "start_seconds": 3.4,
        "end_seconds": 5.9,
        "text": "Rack was one fifty used."
      }
    ]
  }
}
```

---

## Creator profile

**Endpoint:** `GET https://api.virlo.ai/v1/raw/:platform/creator/:handle`

A creator's profile and counts right now. For their outlier videos, history and content patterns, use a [creator lookup](https://dev.virlo.ai/docs/satellite).

Cost per request: $0.01

### Path parameters

- `handle` (string, optional): The creator's handle. A leading `@` is removed. On YouTube a channel ID that starts with `UC` also works.

### Creator fields

- `id` (string | null, optional): The platform's account ID.
- `platform` (string, optional): `tiktok`, `youtube` or `instagram`.
- `handle` (string, optional): The handle, without `@`.
- `display_name, bio, avatar_url` (string | null, optional): Name, bio and profile picture.
- `url` (string, optional): Link to the profile.
- `verified` (boolean | null, optional): Whether the platform shows a verified badge.
- `external_url` (string | null, optional): The link in bio.
- `stats` (object, optional): `followers`, `following`, `likes` and `videos`, each a number or `null`.
- `platform_data` (object, optional): Fields only this platform has. Can be empty.

**cURL request:**

```bash
curl "https://api.virlo.ai/v1/raw/tiktok/creator/mealprepmia" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response:**

```json
{
  "data": {
    "id": "6812045538201543685",
    "platform": "tiktok",
    "handle": "mealprepmia",
    "display_name": "Mia | Meal Prep",
    "bio": "High-protein meals in 15 min or less",
    "avatar_url": "https://p16-sign.tiktokcdn.com/obj/avatar.jpeg",
    "url": "https://www.tiktok.com/@mealprepmia",
    "verified": false,
    "external_url": "https://mealprepmia.com",
    "stats": {
      "followers": 284300,
      "following": 312,
      "likes": 9120400,
      "videos": 641
    },
    "platform_data": {}
  }
}
```

---

## Creator videos

**Endpoint:** `GET https://api.virlo.ai/v1/raw/:platform/creator/:handle/videos`

A creator's videos, in the order the platform lists them. On YouTube, Shorts only. On Instagram, Reels only.

Cost per request: $0.01

### Path parameters

- `handle` (string, optional): The creator's handle. A leading `@` is removed. On YouTube a channel ID that starts with `UC` also works.

### Query parameters

- `cursor` (string, optional): `next_cursor` from the previous page. See [paging](https://dev.virlo.ai/docs/raw#pagination).

**cURL request:**

```bash
curl "https://api.virlo.ai/v1/raw/instagram/creator/fixitfelix.diy/videos" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response:**

```json
{
  "data": [
    {
      "id": "DAbC12xYz9Q",
      "platform": "instagram",
      "url": "https://www.instagram.com/reel/DAbC12xYz9Q/",
      "caption": "The 10-second fix for a wobbly table",
      "hashtags": [],
      "published_at": "2026-10-09T08:47:12Z",
      "duration_seconds": 21,
      "thumbnail_url": "https://scontent.cdninstagram.com/v/example.jpg",
      "author": {
        "id": "51288730042",
        "handle": "fixitfelix.diy",
        "display_name": "Felix | DIY",
        "avatar_url": "https://scontent.cdninstagram.com/v/avatar.jpg",
        "verified": false
      },
      "stats": {
        "views": 1204500,
        "likes": 58300,
        "comments": 412,
        "shares": null,
        "saves": null
      },
      "sound": null,
      "platform_data": {}
    }
  ],
  "pagination": {
    "next_cursor": "eyJ2IjoxLCJjIjoiUTdyOHM5In0",
    "has_more": true
  }
}
```

---

## Paging through results

Search, hashtag videos, comments and creator videos return one page per call.

- **Keep going while `has_more` is `true`.** Send the same request again with `cursor` set to `next_cursor`. On the last page `next_cursor` is `null` and `has_more` is `false`.
- **There is no `limit`.** The platform decides how many items are on a page, so page sizes vary.
- **Cursors are opaque and short-lived.** Don't build or change one, and use it soon. A cursor works only with the request that produced it (same route, platform and input). A changed, expired or mismatched cursor returns `400` with `invalid_cursor`: start again from page 1.
- **Each page is a separate call** and costs $0.01.

**Page 2:**

```bash
curl -G "https://api.virlo.ai/v1/raw/tiktok/search" \
  --data-urlencode "q=protein breakfast" \
  --data-urlencode "cursor=eyJ2IjoxLCJjIjoiQTFiMmMzIn0" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

## Costs and errors

- **$0.01 (1 credit) per call** on every route and platform. A call that succeeds but finds nothing (an empty page) is charged.
- **Errors cost nothing.** That includes every `4xx` and `5xx` below. `X-Cost` shows the charge in dollars and `X-Credits-Used` in credits.
- **Not saved.** Virlo does not keep these results for you. Call again to get fresh numbers.

Errors come back with `message`, `error`, `statusCode` and `code` ([more on errors](https://dev.virlo.ai/docs/errors)):

| Error | When it happens |
| - | - |
| **400** `validation_error` | A missing or bad parameter: no `q`, a `q` over 200 characters, both or neither of `url` and `id`, a link that is not a video on that platform, or a parameter the route doesn't take. |
| **400** `unsupported_platform` | The platform isn't `tiktok`, `youtube` or `instagram`, or you asked for an Instagram transcript. |
| **400** `invalid_cursor` | The cursor was changed, has expired, or belongs to a different request. Start again from page 1. |
| **402** `insufficient_credits` | Your balance is below $0.01. |
| **404** `not_found` | The video or creator doesn't exist, was deleted, or is private. |
| **429** `rate_limit_exceeded` | Your key sent too many requests. Wait `retry_after` seconds. |
| **502** `upstream_error` | Virlo could not get the data from the platform this time. Retry after a few seconds. |
| **503** `service_unavailable` | Raw data is briefly unavailable. Retry later. |
| **504** `request_timeout` | The platform took too long to answer. Retry after a few seconds. |

---

More in Explore data:

- [Pop culture & News](https://dev.virlo.ai/docs/trends.md)
- [Content Trends](https://dev.virlo.ai/docs/content-trends.md)
- [Sounds](https://dev.virlo.ai/docs/sounds.md)
- [Hooks](https://dev.virlo.ai/docs/hooks.md)
- [Hashtags](https://dev.virlo.ai/docs/hashtags.md)
- [Videos](https://dev.virlo.ai/docs/videos.md)
