# Twitch All-in-One API (`romy/twitch-all-in-one-api`) Actor

Unofficial always-on REST API for live Twitch data: channels, live streams, search, categories, VODs, clips, VOD chat archive, teams, emotes and badges. No account, app or device needed.

- **URL**: https://apify.com/romy/twitch-all-in-one-api.md
- **Developed by:** [Romy](https://apify.com/romy) (community)
- **Categories:** Developer tools
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.94 / 1,000 channel profiles

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Twitch All-in-One API

Unofficial, always-on REST API for live Twitch data: channels, live streams,
search, categories, VODs, clips, VOD chat archive, teams, emotes and badges.
Wraps Twitch's own public web GraphQL API (`gql.twitch.tv`), verified live
against the real API — including from Apify's own IPs. No account, login,
app or device needed for any endpoint here.

### Why

Twitch's own web client talks to `gql.twitch.tv` with a public client id
that every anonymous visitor sends — no login, no signing. Every parameter
below was live-tested and classified as a real filter, a shaping/ordering
flag, or inert (accepted but ignored) before being exposed here.

- **Pagination is honest.** Twitch's cursor pagination (`after`) on most
  list connections (streams, videos, clips) requires a device-attestation
  token this API cannot obtain — every affected endpoint here is a single
  page (`first`, up to 100), clearly documented, not a silent lie about
  crawling a full catalog. The one genuine exception is `/teams/:name/members`,
  which has real working cursor pagination, and `/videos/:id/chat`, which
  sidesteps the limit entirely by seeking through a VOD by timestamp instead
  of a cursor.
- **VOD chat archive is the standout feature**: walks a VOD's full chat log
  (commenter, message, emotes, badges, color) from any starting second,
  verified end-to-end across a 5.5-hour VOD.
- **Dead/inert fields are left out.** Twitch's schema still has old fields
  (`stream.tags`, `topTags`, raid/host data) that no longer return real data
  since product changes — this API exposes the field that actually works
  (`freeformTags`) instead of a field that always returns nothing.
- **What isn't anonymously available and isn't promised here**: who a
  channel follows, subscriber lists/counts, active polls or predictions,
  moderator/VIP lists, stream markers, and hosting/raids (Twitch removed
  Host Mode in 2022). These need a real logged-in user token Twitch does not
  grant anonymously; this API does not fake or guess at them.

### Endpoints

#### Channels

##### `GET /channels/:login`

Channel/user profile: bio, profile image, banner, creation date, partner/affiliate status, follower count, primary team, plus embedded live stream info (title, game, viewersCount, startedAt, thumbnailUrl, freeformTags) if currently live. `profileViewCount` is included but is confirmed to always be null upstream -- Twitch no longer populates it. Returns 0 items for an unknown login (upstream returns null, not an error).

| Param | Required | Description |
| --- | --- | --- |
| `login` | yes | Twitch channel login (the part after twitch.tv/, lowercase, not the display name). |

Billed per item returned (`get-channel` event); an empty result is free.

##### `GET /search`

Twitch search (searchFor). `target` selects the index: CHANNEL, GAME, or VOD -- the only 3 SearchIndex values confirmed valid (CATEGORY/CLIP/CLIPS/VIDEO confirmed invalid). Results are confirmed relevance-ranked per query text.

| Param | Required | Description |
| --- | --- | --- |
| `q` | yes | Search text. |
| `target` | no | What to search: CHANNEL (channels/users), GAME (games/categories), or VOD (past broadcasts). Default CHANNEL. Only these 3 SearchIndex values are confirmed valid upstream -- CATEGORY/CLIP/CLIPS/VIDEO were live-tested and confirmed invalid. (one of `CHANNEL`, `GAME`, `VOD`) |
| `first` | no | Number of results to return, 1-100 (default 10). Confirmed honored exactly at 50 and 100 in testing; no cap found up to 100. |

Billed per item returned (`search` event); an empty result is free.

##### `GET /streams`

Top live streams, either the global front page (default, Twitch's own front-page listing sorted by viewersCount descending) or scoped to one `game`. `sort` (StreamSort) only applies when `game` is set. The `tags` filter available on this upstream connection is confirmed INERT (identical results with/without it) and is deliberately not exposed here.

| Param | Required | Description |
| --- | --- | --- |
| `game` | no | Restrict to one game/category (exact name, e.g. "Just Chatting"). Omit for the global front-page top streams. An unknown game name returns zero results rather than an error (confirmed upstream behaviour). |
| `sort` | no | Stream ordering (StreamSort enum) -- only applies when `game` is set; each of these 4 values was confirmed live to produce a distinct, meaningfully different order. Ignored for the global front-page listing (game omitted), which was only ever verified as viewersCount descending. (one of `VIEWER_COUNT`, `VIEWER_COUNT_ASC`, `RECENT`, `RELEVANCE`) |
| `first` | no | Number of streams to return, 1-100 (default 20). This endpoint can only return one page: Twitch's cursor pagination requires a device-attestation token the public API does not grant. |

Billed per item returned (`top-streams` event); an empty result is free.

##### `GET /games`

Twitch's Browse-page games/categories directory, sorted by live viewer count descending.

| Param | Required | Description |
| --- | --- | --- |
| `first` | no | Number of games to return, 1-100 (default 20). This endpoint can only return one page: Twitch's cursor pagination requires a device-attestation token the public API does not grant. |

Billed per item returned (`top-games` event); an empty result is free.

##### `GET /channels/:login/tags`

A currently-live channel's real freeform stream tags (freeformTags), the ones actually shown in Twitch's UI. The legacy `tags` field is confirmed dead (always empty) and is deliberately not exposed. Returns 0 items if the channel is offline or unknown to Twitch (both confirmed, non-error upstream states).

| Param | Required | Description |
| --- | --- | --- |
| `login` | yes | Twitch channel login (the part after twitch.tv/, lowercase, not the display name). |

Billed per item returned (`channel-tags` event); an empty result is free.

##### `GET /channels/:login/schedule`

A channel's published upcoming broadcast schedule segments (id, title, startAt, endAt). Many channels don't publish one at all -- confirmed upstream as either `schedule: null` or `schedule.segments: null`, both mapped here to 0 items rather than an error, same as an unknown login.

| Param | Required | Description |
| --- | --- | --- |
| `login` | yes | Twitch channel login (the part after twitch.tv/, lowercase, not the display name). |

Billed per item returned (`schedule` event); an empty result is free.

#### Videos

##### `GET /videos`

One page of a channel's videos/VODs (up to 100, newest-first by default). Twitch's cursor pagination (`after`) is rejected with an integrity-check error requiring a device-attestation token this API does not have -- so this endpoint returns a single page only, sized by `first` (server max 100). A channel with more than 100 matching videos cannot have the rest listed.

| Param | Required | Description |
| --- | --- | --- |
| `login` | yes | Twitch channel login (the part after twitch.tv/, lowercase, not the display name). |
| `first` | no | Number of videos to return, 1-100 (default 20). This endpoint can only return one page: Twitch's cursor pagination requires a device-attestation token the public API does not grant. |
| `sort` | no | Sort order for the video list: TIME (default, newest first) or VIEWS (highest view count first). Confirmed to genuinely reorder results. (one of `TIME`, `VIEWS`) |
| `type` | no | Filter by broadcast type: ARCHIVE (past live broadcasts), HIGHLIGHT (creator-curated highlights), or UPLOAD (direct uploads). Confirmed genuine filter -- every returned video matches the requested type. (one of `ARCHIVE`, `HIGHLIGHT`, `UPLOAD`) |

Billed per item returned (`list-videos` event); an empty result is free.

##### `GET /videos/:id`

Full detail for one VOD: title, description, duration, view count, and per-segment game/chapter markers (`chapters`, from `momentRequestType: VIDEO_CHAPTER_MARKERS`) for multi-game broadcasts. Resolution/quality list and muted-segment info are not exposed by this query (open gaps -- see the source contract) and are omitted rather than guessed.

| Param | Required | Description |
| --- | --- | --- |
| `id` | yes | Twitch video/VOD numeric id (as seen in a twitch.tv/videos/<id> URL, or from a /videos list result). |

Billed per item returned (`video-detail` event); an empty result is free.

##### `GET /clips`

One page of a channel's top clips (up to 100), optionally windowed by `period`. Same pagination caveat as /videos: `after` is integrity-gated, so this is a single page sized by `first` (max 100).

| Param | Required | Description |
| --- | --- | --- |
| `login` | yes | Twitch channel login (the part after twitch.tv/, lowercase, not the display name). |
| `first` | no | Number of clips to return, 1-100 (default 20). This endpoint can only return one page: Twitch's cursor pagination requires a device-attestation token the public API does not grant. |
| `period` | no | Time window for the top-clips ranking (default ALL\_TIME). Confirmed genuine filter: each period returns a distinct, date-bounded set of clips with different view counts. (one of `LAST_DAY`, `LAST_WEEK`, `LAST_MONTH`, `ALL_TIME`) |

Billed per item returned (`list-clips` event); an empty result is free.

##### `GET /clips/:slug`

Full detail for one clip, including per-quality direct MP4 download URLs (`videoQualities`) and the offset (`videoOffsetSeconds`) into its source VOD.

| Param | Required | Description |
| --- | --- | --- |
| `slug` | yes | Twitch clip slug (from a /clips list result -- never guessed). |

Billed per item returned (`clip-detail` event); an empty result is free.

##### `GET /videos/:id/chat`

Replays a VOD's chat log by seeking forward with `contentOffsetSeconds` instead of cursor pagination -- unlike every other list endpoint in this API, this is NOT integrity-gated and is confirmed walkable end-to-end across an entire VOD (verified offset 0 through 20050 on a 20,056s VOD, no blocker hit). Each message carries its VOD offset, the commenter, message text broken into fragments with any emote references, chat badges, and name color. Commenter logins are Twitch's own public usernames, the same ones visible in the platform's live/VOD chat -- not additional PII, though archiving them at scale is a different exposure profile than one-off viewing. To read a whole long VOD, keep calling with `startSeconds` set to the previous response's `nextOffsetSeconds` until it comes back null.

| Param | Required | Description |
| --- | --- | --- |
| `id` | yes | Twitch video/VOD numeric id (as seen in a twitch.tv/videos/<id> URL, or from a /videos list result). |
| `startSeconds` | no | VOD offset (seconds) to start walking chat from (default 0). To page through a long VOD, pass the previous call's `nextOffsetSeconds` back in here. |
| `maxMessages` | no | Max chat messages to walk and return in this single call (default 500, max 5000). Caps how many upstream page-fetches one request can make so it can never run forever or hammer Twitch; a caller wanting a whole long VOD's chat should keep calling with `startSeconds` set to the returned `nextOffsetSeconds` until it comes back null. |

Billed per item returned (`vod-chat-message` event); an empty result is free.

#### Social

##### `GET /channels/:login/followers/count`

Live follower count for a channel. The follower LIST is not available: Twitch's API resolves an always-empty `edges` array for it (verified, not an auth error) while still resolving this same totalCount field -- so only the count is exposed here, deliberately.

| Param | Required | Description |
| --- | --- | --- |
| `login` | yes | Twitch channel login (the part after twitch.tv/, lowercase, not the display name). |

Billed once per successful request (`follower-count` event).

##### `GET /teams/:name`

A Twitch team's profile: id, name, display name, description and banner/logo image URLs.

| Param | Required | Description |
| --- | --- | --- |
| `name` | yes | Twitch team name (the part after twitch.tv/team/, lowercase). |

Billed once per successful request (`team` event).

##### `GET /teams/:name/members`

One page of a Twitch team's member roster. This is the one list endpoint in this whole API with genuine working cursor pagination (verified: `after` advances exactly `first` positions forward, no overlap/gap) -- it is not subject to the IntegrityCheckFailed device-attestation wall most other list endpoints hit. Pass the returned `nextCursor` back as `after` to fetch the next page; `hasNextPage: false` or a missing `nextCursor` means the roster is exhausted.

| Param | Required | Description |
| --- | --- | --- |
| `name` | yes | Twitch team name (the part after twitch.tv/team/, lowercase). |
| `first` | no | Number of members to return, 1-100 (default 100). Unlike most list endpoints on this API, this one has genuine, verified working cursor pagination -- see `after`. |
| `after` | no | Opaque pagination cursor from a previous page's `nextCursor`. Omit to fetch the first page. |

Billed per item returned (`team-members` event); an empty result is free.

##### `GET /channels/:login/subscription-products`

A channel's paid subscription tiers: display name, tier code, price and per-tier emote set. This is tier/pricing metadata, NOT a subscriber count or list -- no subscriber count or list field exists anonymously anywhere in this API.

| Param | Required | Description |
| --- | --- | --- |
| `login` | yes | Twitch channel login (the part after twitch.tv/, lowercase, not the display name). |

Billed per item returned (`subscription-products` event); an empty result is free.

##### `GET /channels/:login/emotes`

All of a channel's anonymously-public emotes in one call: subscriber emotes (per tier), follower/local emotes, and cheermote name prefixes. Subscriber and follower/local items include a resolvable `cdnUrl` built from the verified static CDN URL pattern (not a GraphQL field). Cheermote items only expose `id` (the name prefix, e.g. "Cheer"/"Kappa") -- per-tier bit thresholds/colors/images were not part of the verified contract, so no cdnUrl is claimed for them.

| Param | Required | Description |
| --- | --- | --- |
| `login` | yes | Twitch channel login (the part after twitch.tv/, lowercase, not the display name). |

Billed per item returned (`channel-emotes` event); an empty result is free.

##### `GET /channels/:login/badges`

A channel's subscriber-month chat badge set: title, description and an image URL at the requested resolution. Each badge also exposes `idDecoded`, the raw base64-decoded id string -- see the field note in the response for why any numeric pattern inside it is not treated as a documented tenure code.

| Param | Required | Description |
| --- | --- | --- |
| `login` | yes | Twitch channel login (the part after twitch.tv/, lowercase, not the display name). |
| `size` | no | Badge image resolution: NORMAL (1x), DOUBLE (2x, default), QUADRUPLE (4x). SMALL/LARGE are real values that were tried and rejected upstream ("Value does not exist in BadgeImageSize enum") -- not offered here. (one of `NORMAL`, `DOUBLE`, `QUADRUPLE`) |

Billed per item returned (`channel-badges` event); an empty result is free.

### Pricing

Pay-per-event (PPE), tiered by Apify plan (FREE/BRONZE/SILVER/GOLD/PLATINUM/DIAMOND
\= 100/92/85/78/72/68% of the FREE price). See the Actor's Pricing tab for exact
current prices.

### Known limitations

- Most list endpoints (`/streams`, `/games`, `/videos`, `/clips`, `/search`)
  return one page only (`first`, up to 100) — see "Why" above.
- `/videos/:id/chat` caps how many messages a single call walks
  (`maxMessages`); page a long VOD by passing the previous call's
  `nextOffsetSeconds` back in as `startSeconds`.
- `/channels/:login/followers/count` returns a count only — Twitch does not
  expose the follower list anonymously, by design.
- `/channels/:login/subscription-products` returns tiers/prices/emotes, not
  a subscriber list or count, which does not exist in the public schema.

### Getting started

```bash
npm install
npm run start:dev
```

# Actor input Schema

## Actor input object example

```json
{}
```

# Actor output Schema

## `info` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("romy/twitch-all-in-one-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("romy/twitch-all-in-one-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call romy/twitch-all-in-one-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,romy/twitch-all-in-one-api"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Uo6z9Pk28AdBKSwE6/builds/ANDVln4YCt7iXkD12/openapi.json
