# YouTube Live Stream & Replay Chat Extractor (`dataspryva/youtube-live-stream-and-replay-chat-extractor`) Actor

Collect chat messages, Super Chats, Super Stickers, and membership events from an active YouTube livestream or an ended stream's saved chat replay, with author and timestamp detail.

- **URL**: https://apify.com/dataspryva/youtube-live-stream-and-replay-chat-extractor.md
- **Developed by:** [Dataspryva](https://apify.com/dataspryva) (community)
- **Categories:** Social media, Videos, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

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

## YouTube Live Stream & Replay Chat Extractor

Read the chat behind a YouTube live stream — while it is running or from the saved replay after it ends. Give the actor a video link, a video ID or a channel, and it returns the chat timeline as structured records: text messages, Super Chats, Super Stickers, memberships, gift memberships and paid gift messages.

No cookies, login, API key or proxy setup is required.

### What you get

- **Replay chat in full** — pages through the saved chat to the end of the stream instead of stopping after a fixed number of pages.
- **Live chat capture** — opens the live chat feed, emits the recent history already on screen, then polls at YouTube's own interval until your time window ends.
- **Channel discovery** — finds the current live stream and recent stream replays from an `@handle`, channel URL or `UC…` channel ID.
- **Every visible event type** — normal messages, Super Chats, Super Stickers, memberships, gift purchases, gift redemptions, paid gift messages, engagement notices and slow-mode/system notices.
- **Replay offsets** — each replay event carries `videoOffsetMsec` and a readable `videoOffsetText` such as `0:05:06`.
- **Numeric money** — `amountText` plus `amountValue` and `currency` when the amount is unambiguous.
- **Author detail** — display name, channel ID, avatar, badges, handle, profile URL, and owner / moderator / member / verified flags.
- **Stream context** — title, channel, live status, start/end time, publish date, duration, views, likes and category.
- **Type filters and caps** — include or exclude event families, cap messages per video and total items, and restrict replay output to a time range.
- **Optional summary** — one `stream_summary` record per video with event counts, per-currency totals, top supporters and a completeness note.

### Inputs

| Field | Default | What it does |
|---|---|---|
| `videoRefs` | — | Watch, live, shorts or `youtu.be` links, bare 11-character IDs, or channel live links such as `@handle/live`. |
| `channelRefs` | — | `@handle`, channel URL or `UC…` ID. Each channel is searched for streams. |
| `mode` | `auto` | `auto` detects live versus replay. `active` forces live chat. `replay` forces saved replay chat. |
| `channelDiscoveryMode` | `current_live_then_replays` | `current_live`, `current_live_then_replays` or `latest_replays`. |
| `maxVideosPerChannel` | `5` | How many streams to take from each channel. |
| `lookbackDays` | `30` | How far back to include ended streams from a channel. `0` means no limit. |
| `includeUpcomingLives` | `false` | Emit an `upcoming` status row for scheduled channel streams. |
| `maxMessagesPerVideo` | `5000` | Chat events per video. `0` collects every available event. |
| `maxTotalItems` | `0` | Whole-run dataset cap. `0` means no limit. |
| `maxTimePerVideoSecs` | `600` | Safety budget for replay pagination on one video. |
| `includeNormalMessages` | `true` | Include standard text messages. |
| `includeSuperChats` | `true` | Include Super Chats and Super Stickers. |
| `includeMembershipEvents` | `true` | Include memberships. |
| `includeGiftEvents` | `true` | Include gift purchases, redemptions and paid gift messages. |
| `includeSystemEvents` | `true` | Include engagement, slow-mode and other system notices. |
| `includePlaceholders` | `false` | Include empty placeholder rows. |
| `includeSummary` | `false` | Add a stream summary row per video. |
| `startOffsetSecs` / `endOffsetSecs` | `0` / `0` | Replay-only time window inside the video. |
| `liveCollectSecs` | `60` | How long to poll an active chat. |
| `pollIntervalMs` | `2000` | Minimum live poll delay; YouTube's longer timeout is honoured. |
| `language` / `regionCode` | `en` / `US` | Page and chat request locale. |
| `includeMetadata` | `true` | Repeat stream metadata on each chat row. |

### Output

Every chat record has `recordType: "live_chat_message"` and:

- identity and timing: `videoId`, `videoUrl`, `chatType`, `messageId`, `eventType`, `messageType`, `timestamp`, `timestampUsec`, `publishedAt`, `videoOffsetMsec`, `videoOffsetText`, `scrapedAt`
- author: `authorName`, `authorChannelId`, `authorHandle`, `authorPhotoUrl`, `authorProfileUrl`, `authorBadges`, `memberBadge`, `isOwner`, `isModerator`, `isMember`, `isVerified`
- content: `messageText`, `messageParts[]` (text and emoji runs)
- money and membership: `amountText`, `amountValue`, `currency`, `superChatColor`, `stickerName`, `stickerUrl`, `membershipText`, `membershipLevel`, `memberMonths`
- gifts: `giftCount`, `giftName`, `giftImageUrl`, `giftedBy`
- system: `systemAction`, `systemText`
- stream context when `includeMetadata` is on: `videoTitle`, `channelName`, `channelId`, `channelUrl`, `channelHandle`, `isLiveContent`, `isLiveNow`, `streamStatus`, `streamStartedAt`, `streamEndedAt`, `videoPublishedAt`, `videoDurationSeconds`, `videoViewCount`, `videoLikeCount`, `videoCategory`
- channel discovery context when the target came from a channel: `discoverySource`, `channelRef`, `isDiscoveredLive`, `isDiscoveredUpcoming`, `discoveredAt`

Event values include `message`, `super_chat`, `super_sticker`, `membership`, `membership_gift`, `gift_received`, `gift`, `system` and `placeholder`.

When chat cannot be read, the actor emits a `recordType: "status"` row with a specific status such as `chat_disabled`, `upcoming`, `no_replay`, `stream_ended`, `stream_live`, `channel_not_live`, `rate_limited` or `partial_capture`, plus a plain-language `error`.

### Examples

Read a complete replay:

```json
{
  "videoRefs": ["https://www.youtube.com/watch?v=FQbNtLOVlwU"],
  "mode": "replay",
  "maxMessagesPerVideo": 0
}
```

Capture 60 seconds of a live chat:

```json
{
  "videoRefs": ["https://www.youtube.com/live/74WjpIH4jeE"],
  "mode": "active",
  "liveCollectSecs": 60
}
```

Find a channel's current live stream and its two most recent replays:

```json
{
  "channelRefs": ["@CBSNews"],
  "channelDiscoveryMode": "current_live_then_replays",
  "maxVideosPerChannel": 2,
  "lookbackDays": 30,
  "includeSummary": true
}
```

Read only paid events from a replay between two offsets:

```json
{
  "videoRefs": ["1vvDbx3nYpg"],
  "mode": "replay",
  "includeNormalMessages": false,
  "includeMembershipEvents": false,
  "includeGiftEvents": false,
  "includeSystemEvents": false,
  "startOffsetSecs": 60,
  "endOffsetSecs": 600
}
```

### FAQ

**Do I need cookies, an API key or a proxy?**
No. The actor reads public chat data without cookies or credentials. It connects directly and switches proxy automatically only when a request is blocked.

**Why is a live run shorter than the whole chat?**
A live read only sees what appears while the actor is collecting. The actor emits the recent history already on screen, then polls until `liveCollectSecs` ends. Run replay mode after the stream ends for the full timeline.

**How much replay chat can I get?**
As much as YouTube exposes. Pagination stops only at the end of the replay, `maxMessagesPerVideo`, `maxTotalItems`, `maxTimePerVideoSecs`, or a real error. There is no fixed page cap.

**What is the difference between `active` and `auto`?**
`auto` checks the video and chooses live or replay. `active` insists on live chat and reports `stream_ended` if the stream is already over. `replay` insists on saved chat and reports `stream_live` if the stream is still running.

**Why is `amountValue` sometimes missing?**
Only unambiguous amounts are converted to a number and currency. The original `amountText` is always kept. Unusual formats are counted in `amountsNotRead` on the summary row instead of being guessed.

**Are gift memberships the same as memberships?**
No. A purchase is `membership_gift` (the buyer sent memberships), a redemption is `gift_received` (someone received one), and a paid gift message is `gift`. The summary keeps separate counts.

**Why are some messages missing from a channel result?**
Channel discovery only returns streams that match `channelDiscoveryMode`, `lookbackDays` and `maxVideosPerChannel`. Some streams have chat disabled, no saved replay, or are members-only. Each of those cases produces a status row instead of fabricated data.

**Does the actor convert currencies or provide a single total?**
No. Totals stay per currency in `totalAmountByCurrency`; no exchange-rate service is used. Top supporters are ranked by numeric amount and keep their own currency.

**Can it read members-only chat or deleted-message moderation details?**
No. Those require an authenticated channel session. The actor reads public chat, reports unavailable paths as status rows, and never fakes restricted data.

### Limits

- Live captures are partial by design; replay is the complete path.
- Members-only chat, age/region-gated videos and moderation logs are not available without authentication.
- Reply-thread parent IDs and a numeric concurrent-viewer count are not exposed in the public chat payload, so they are not returned.
- Currency conversion is intentionally not performed.
- Chat availability is controlled by the creator. A stream can be public while its chat or replay is disabled.

### Data source

The actor reads YouTube's public watch pages and its public InnerTube live-chat endpoints. It does not log in, post messages, or perform moderation actions.

# Actor input Schema

## `videoRefs` (type: `array`):

YouTube watch, live, shorts or youtu.be links, 11-character video IDs, or a channel live link such as @handle/live.

## `channelRefs` (type: `array`):

Channel handles (@name), channel URLs or UC… channel IDs. The actor discovers current live streams and recent stream replays from each channel.

## `mode` (type: `string`):

Auto detects live versus replay. Active captures an ongoing live chat. Replay reads the saved chat of an ended stream.

## `channelDiscoveryMode` (type: `string`):

Which streams to pick from each channel. Used with channel references.

## `maxVideosPerChannel` (type: `integer`):

Maximum streams to process from each channel.

## `lookbackDays` (type: `integer`):

How far back to include ended streams from a channel. Use 0 for no limit.

## `includeUpcomingLives` (type: `boolean`):

Emit an upcoming status row for scheduled channel streams instead of skipping them.

## `maxMessagesPerVideo` (type: `integer`):

Maximum unique chat events collected from each video. Use 0 to collect every available event.

## `maxTotalItems` (type: `integer`):

Whole-run cap across all videos and summary rows. Use 0 for no limit.

## `maxTimePerVideoSecs` (type: `integer`):

Safety limit for replay pagination on one video, in seconds. A run that reaches it reports partial_capture.

## `includeNormalMessages` (type: `boolean`):

Include standard text chat messages.

## `includeSuperChats` (type: `boolean`):

Include paid Super Chat messages and paid Super Stickers.

## `includeMembershipEvents` (type: `boolean`):

Include new and renewed channel membership events.

## `includeGiftEvents` (type: `boolean`):

Include gift membership purchases, gift membership redemptions and paid gift messages.

## `includeSystemEvents` (type: `boolean`):

Include engagement notices, slow-mode changes, restricted participation and other system rows.

## `includePlaceholders` (type: `boolean`):

Include raw placeholder rows that contain only an ID and timestamp.

## `includeSummary` (type: `boolean`):

Add one stream_summary row per video with event counts, per-currency totals, top supporters and completeness.

## `startOffsetSecs` (type: `integer`):

Replay only. Skip events before this video offset. Use 0 to start at the beginning.

## `endOffsetSecs` (type: `integer`):

Replay only. Stop after this video offset. Use 0 to read to the end.

## `liveCollectSecs` (type: `integer`):

How long to keep polling an active chat before stopping. Live captures are always partial.

## `pollIntervalMs` (type: `integer`):

Minimum delay between live chat polls. YouTube's own timeout is honoured when it is longer.

## `language` (type: `string`):

Interface language used when requesting YouTube pages and chat.

## `regionCode` (type: `string`):

Region used for YouTube page and chat requests.

## `includeMetadata` (type: `boolean`):

Repeat video and stream metadata on each chat row.

## Actor input object example

```json
{
  "videoRefs": [
    "https://www.youtube.com/watch?v=FQbNtLOVlwU"
  ],
  "mode": "auto",
  "channelDiscoveryMode": "current_live",
  "maxVideosPerChannel": 1,
  "lookbackDays": 30,
  "includeUpcomingLives": false,
  "maxMessagesPerVideo": 3,
  "maxTotalItems": 3,
  "maxTimePerVideoSecs": 120,
  "includeNormalMessages": true,
  "includeSuperChats": true,
  "includeMembershipEvents": true,
  "includeGiftEvents": true,
  "includeSystemEvents": true,
  "includePlaceholders": false,
  "includeSummary": false,
  "startOffsetSecs": 0,
  "endOffsetSecs": 0,
  "liveCollectSecs": 10,
  "pollIntervalMs": 2000,
  "language": "en",
  "regionCode": "US",
  "includeMetadata": true
}
```

# Actor output Schema

## `messages` (type: `string`):

Dataset containing chat messages, paid events, memberships, gifts, system rows and stream summaries.

# 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 = {
    "videoRefs": [
        "https://www.youtube.com/watch?v=FQbNtLOVlwU"
    ],
    "mode": "auto",
    "channelDiscoveryMode": "current_live",
    "maxVideosPerChannel": 1,
    "lookbackDays": 30,
    "includeUpcomingLives": false,
    "maxMessagesPerVideo": 3,
    "maxTotalItems": 3,
    "maxTimePerVideoSecs": 120,
    "includeNormalMessages": true,
    "includeSuperChats": true,
    "includeMembershipEvents": true,
    "includeGiftEvents": true,
    "includeSystemEvents": true,
    "includePlaceholders": false,
    "includeSummary": false,
    "startOffsetSecs": 0,
    "endOffsetSecs": 0,
    "liveCollectSecs": 10,
    "pollIntervalMs": 2000,
    "language": "en",
    "regionCode": "US",
    "includeMetadata": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataspryva/youtube-live-stream-and-replay-chat-extractor").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 = {
    "videoRefs": ["https://www.youtube.com/watch?v=FQbNtLOVlwU"],
    "mode": "auto",
    "channelDiscoveryMode": "current_live",
    "maxVideosPerChannel": 1,
    "lookbackDays": 30,
    "includeUpcomingLives": False,
    "maxMessagesPerVideo": 3,
    "maxTotalItems": 3,
    "maxTimePerVideoSecs": 120,
    "includeNormalMessages": True,
    "includeSuperChats": True,
    "includeMembershipEvents": True,
    "includeGiftEvents": True,
    "includeSystemEvents": True,
    "includePlaceholders": False,
    "includeSummary": False,
    "startOffsetSecs": 0,
    "endOffsetSecs": 0,
    "liveCollectSecs": 10,
    "pollIntervalMs": 2000,
    "language": "en",
    "regionCode": "US",
    "includeMetadata": True,
}

# Run the Actor and wait for it to finish
run = client.actor("dataspryva/youtube-live-stream-and-replay-chat-extractor").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 '{
  "videoRefs": [
    "https://www.youtube.com/watch?v=FQbNtLOVlwU"
  ],
  "mode": "auto",
  "channelDiscoveryMode": "current_live",
  "maxVideosPerChannel": 1,
  "lookbackDays": 30,
  "includeUpcomingLives": false,
  "maxMessagesPerVideo": 3,
  "maxTotalItems": 3,
  "maxTimePerVideoSecs": 120,
  "includeNormalMessages": true,
  "includeSuperChats": true,
  "includeMembershipEvents": true,
  "includeGiftEvents": true,
  "includeSystemEvents": true,
  "includePlaceholders": false,
  "includeSummary": false,
  "startOffsetSecs": 0,
  "endOffsetSecs": 0,
  "liveCollectSecs": 10,
  "pollIntervalMs": 2000,
  "language": "en",
  "regionCode": "US",
  "includeMetadata": true
}' |
apify call dataspryva/youtube-live-stream-and-replay-chat-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dataspryva/youtube-live-stream-and-replay-chat-extractor"
        }
    }
}
```

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/KuR4Wj8bAkeGAly61/builds/RX1LgB29gltcaO0El/openapi.json
