# YouTube Live Stream Real-Time Monitor (`sian.agency/youtube-live-stream-monitor`) Actor

Monitor any YouTube livestream's concurrent viewers in real time. List currently-live & recent streams for any channel. Bulk poll 100s of stream IDs. For esports analytics, live-commerce, news-event tracking and brand-safety teams.

- **URL**: https://apify.com/sian.agency/youtube-live-stream-monitor.md
- **Developed by:** [SIÁN OÜ](https://apify.com/sian.agency) (community)
- **Categories:** Videos, Social media, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 live stream rows

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

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## YouTube Live Stream Real-Time Monitor — Concurrent Viewers API 📡🚀

[![Store-SIÁN Agency](https://img.shields.io/badge/Store-SI%C3%81N%20Agency-1AE392)](https://apify.com/sian.agency?fpr=sian) [![Store-YouTube Shorts Transcript](https://img.shields.io/badge/Store-YouTube%20Shorts%20Transcript-FF0000)](https://apify.com/sian.agency/youtube-shorts-ai-transcript-and-metadata-extractor?fpr=sian) [![Store-YouTube Comments Scraper](https://img.shields.io/badge/Store-YouTube%20Comments%20Scraper-FF0000)](https://apify.com/sian.agency/cheapest-youtube-comments-scraper?fpr=sian) [![Store-YouTube AI Comments](https://img.shields.io/badge/Store-YouTube%20AI%20Comments-FF0000)](https://apify.com/sian.agency/youtube-ai-comments-scraper-and-questions-extractor?fpr=sian)

#### 🎉 The ONLY actor returning real-time `concurrentViewers` for ANY YouTube livestream — poll every minute
##### Perfect for esports analytics, live-commerce intel, news monitoring, brand-safety teams & creator-management agencies.

---

### 📋 Overview

**Track concurrent viewers on any YouTube livestream — the real-time signal that actually matters.** Every other YouTube scraper returns cumulative views; this actor returns **`concurrentViewers`** — the live audience count that drives ad-buy timing, peak-detection, and brand-safety alerts. Two operations: list a channel's currently-live and recently-ended streams, or bulk-poll a list of stream IDs for real-time viewer-count snapshots.

**Why analytics teams & creator agencies choose us:**
- ✅ **Only `concurrentViewers` feed on Apify**: every other YouTube scraper returns cumulative views — we return the real-time integer.
- ⚡ **Bulk-poll 500 streams per run**: feed an entire tournament bracket, news roster, or talent agency in one snapshot call.
- 🎯 **Derived `streamState` field**: `live` / `ended` / `scheduled` / `not_live` — no manual parsing of YouTube's inconsistent live markers.
- 💰 **Real-time-friendly pricing**: $0.005 per live-stream row at BRONZE, $0.008 per viewer snapshot — built for sub-minute polling loops without quota burn.
- 💎 **Auto-resolves channel handles**: paste `https://www.youtube.com/@LofiGirl` or any handle URL — the actor converts it to the canonical channel ID for you.
- ✨ **NEW**: scheduled premieres tagged `streamState: scheduled` with null viewer count — never confuse upcoming with live.

---

### ✨ Features

- 👁 **Real-Time Concurrent Viewers**: `concurrentViewers` integer for any currently-live YouTube stream — the only one of its kind on Apify.
- 📺 **Channel Live Streams Listing**: paginated list of a channel's currently-live and recently-ended streams, with viewer counts per row.
- 🏷 **Derived `streamState` Field**: `live` / `ended` / `scheduled` / `not_live` — filter dataset rows by state without writing parsing logic.
- 📦 **Bulk Snapshot Mode**: up to 500 video IDs per run for `viewerSnapshot` — bracket-wide tournament polling in one call.
- 🔗 **Handle & Custom URL Auto-Resolve**: paste any YouTube channel URL format — the actor finds the canonical `UC…` ID for free.
- ⏱ **Schedule-Friendly Output**: each run is a fresh snapshot row with `_fetchedAt` timestamp — combine with Apify Scheduler to build a viewer-count time series.
- 🌍 **Geo + Language Localization**: pass `geo` (e.g. `US`, `GB`, `JP`) and `lang` to control region/locale of the response.
- 📦 **Schema-Stable Output**: every row matches a published dataset schema — predictable for downstream ETL.
- 🛡️ **No Account, No API Key, No Proxies**: just an Apify token and you're scraping.

---

### 🎬 Quick Start

Pick an operation — channel listing or viewer snapshot — pass a channel ID or video IDs, and run. Each run produces one clean dataset row per livestream.

```bash
curl -X POST "https://api.apify.com/v2/acts/sian.agency~youtube-live-stream-monitor/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"operation":"viewerSnapshot","videoIds":"JD-kMIpDfnY"}'
````

***

### 🚀 Getting Started (3 Simple Steps)

#### Step 1: Choose your operation

- **`channelLiveStreams`** — pass a channel ID → get the paginated list of currently-live and recently-ended livestreams.
- **`viewerSnapshot`** — pass one or more video IDs → get real-time concurrent viewer counts.

#### Step 2: Provide your input

- For `channelLiveStreams`: a canonical channel ID (`UCSJ4gkVC6NrvII8umztf0Ow`), a channel URL, or a handle URL (`https://www.youtube.com/@LofiGirl`).
- For `viewerSnapshot`: one or more 11-character video IDs (one per line, comma-separated, or full URLs — up to 500).

#### Step 3: Run it

Optionally tune `maxPages` (1–25 for `channelLiveStreams`), `geo` (country code), and `lang` (language code). Hit run.

**That's it! In seconds, you'll have:**

- A dataset of livestreams with `streamState` and `concurrentViewers` per row
- HTML report summarising peak concurrent viewers and stream-state breakdown
- Time-series-ready rows stamped with `_fetchedAt` ISO timestamps

***

### 📥 Input Configuration

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `operation` | string | Yes | `channelLiveStreams` (channel listing) or `viewerSnapshot` (real-time poll) |
| `channelId` | string | Conditional | Required for `channelLiveStreams`. Canonical channel ID, channel URL, or handle URL |
| `videoIds` | string | Conditional | Required for `viewerSnapshot`. One per line, comma-separated, or full URLs. Max 500 |
| `maxPages` | integer | No | Pagination cap for `channelLiveStreams` (default 3, max 25). Ignored for `viewerSnapshot` |
| `geo` | string | No | ISO 3166-1 alpha-2 country code (e.g. `US`, `GB`, `IN`). Defaults to `US` |
| `lang` | string | No | ISO 639-1 language code (e.g. `en`, `es`, `ja`). Defaults to `en` |

**Example — list currently-live streams for a channel:**

```json
{
  "operation": "channelLiveStreams",
  "channelId": "UCSJ4gkVC6NrvII8umztf0Ow",
  "maxPages": 1
}
```

**Example — bulk viewer-count snapshot:**

```json
{
  "operation": "viewerSnapshot",
  "videoIds": "JD-kMIpDfnY\nEWrX250Zhko"
}
```

***

### 📤 Output

Results are saved to the Apify dataset with **20+ fields** including:

| Field | Type | Description |
|-------|------|-------------|
| `streamState` | string | `live`, `ended`, `scheduled`, or `not_live` |
| `videoId` | string | 11-character YouTube video ID |
| `videoPageUrl` | string | Canonical watch URL |
| `videoTitle` | string | Livestream title |
| `channelId` | string | Canonical channel ID (`UC…`) |
| `channelTitle` | string | Channel display name |
| `channelPageUrl` | string | Canonical channel URL |
| `isLive` | boolean | True iff stream is currently live |
| `concurrentViewers` | integer | Real-time concurrent viewer count |
| `concurrentViewersText` | string | Raw text e.g. `486 watching` / `19K watching` |
| `viewCount` | integer | Cumulative views (for ended streams) |
| `likeCount` | integer | Like count (real-time for live, cumulative otherwise) |
| `lengthText` | string | `LIVE` for currently-live, `HH:MM:SS` for ended |
| `publishedAt` | string | ISO 8601 published / first-streamed timestamp |
| `thumbnailUrl` | string | Best-resolution thumbnail URL |
| `status` | string | `success` or `error` |

**Example row (`channelLiveStreams`):**

```json
{
  "_operation": "channelLiveStreams",
  "_fetchedAt": "2026-05-22T00:30:42.013Z",
  "streamState": "live",
  "isLive": true,
  "videoId": "JD-kMIpDfnY",
  "videoPageUrl": "https://www.youtube.com/watch?v=JD-kMIpDfnY",
  "videoTitle": "lofi hip hop radio 💤 beats to sleep/chill to",
  "channelId": "UCSJ4gkVC6NrvII8umztf0Ow",
  "channelTitle": "Lofi Girl",
  "channelPageUrl": "https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow",
  "concurrentViewers": 486,
  "concurrentViewersText": "486 watching",
  "lengthText": "LIVE",
  "thumbnailUrl": "https://i.ytimg.com/vi/JD-kMIpDfnY/hqdefault.jpg",
  "status": "success"
}
```

***

### 💼 Use Cases & Examples

#### 1. Esports Analytics — Tournament Viewership Curves

**Esports analytics teams use this to build live-vs-vod retention dashboards across tournament weekends.**

**Input:** League channel ID, polled every hour during the bracket.
**Output:** Viewer-count snapshots for every active stream + cumulative views for ended.
**Use:** Build peak-concurrent retention dashboards without writing a custom scraper.

#### 2. Live-Commerce Intel — Shopping Event Peak Detection

**Live-commerce analytics teams use this to time ad buys and merchandise pushes to peak attention.**

**Input:** A creator's livestream ID, polled every 5 minutes during a product drop.
**Output:** Sub-minute-fresh `concurrentViewers` + `likeCount` + `streamState` rows.
**Use:** Plot drop-off curves and trigger ad spend at organic peak-viewer windows.

#### 3. News Outlets — Breaking-Event Livestream Discovery

**News organisations use this to catch breaking-news livestreams as they go viral, not after.**

**Input:** News org channel ID, polled every minute.
**Output:** Real-time `channelLiveStreams` rows with concurrent viewer counts.
**Use:** Trigger downstream alerts when concurrent viewers cross a threshold — newsroom-ready.

#### 4. Brand-Safety Teams — Real-Time Creator Live Tracking

**Brand-safety teams use this to identify off-brand live behavior on their creator rosters in minutes.**

**Input:** Roster of creator channel IDs, polled hourly.
**Output:** Live-feed of currently-live content with viewer counts and titles.
**Use:** Flag off-brand or unsafe live behavior fast, before screenshots circulate.

#### 5. Creator-Management Agencies — Talent Performance Reports

**Talent agencies use this to automate weekly performance reports across the roster.**

**Input:** Talent roster channel IDs, polled nightly via Apify Scheduler.
**Output:** Peak-concurrent and average-concurrent viewer aggregates per stream.
**Use:** Benchmark performance across the roster automatically — no manual logging.

#### 6. Live-Stream Trend Researchers — Viral Moment Detection

**Trend research teams use this to surface viral livestream moments before they trend on Twitter.**

**Input:** A watchlist of channel IDs across niches.
**Output:** Snapshot rows showing which streams cross 10K / 100K / 1M concurrent viewers.
**Use:** Build "what's hot right now" feeds for media intelligence dashboards.

#### 7. Creator-Tools Platforms — Premiere & Scheduled Tracking

**Creator-tools platforms use this to detect scheduled premieres and notify their users.**

**Input:** Subscribed channels' IDs, polled hourly.
**Output:** Rows tagged `streamState: scheduled` with null `concurrentViewers`.
**Use:** Power "your subscriptions are going live in N minutes" notifications.

***

### 🔗 Integration Examples

#### JavaScript / Node.js

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });

const run = await client.actor('sian.agency/youtube-live-stream-monitor').call({
  operation: 'viewerSnapshot',
  videoIds: 'JD-kMIpDfnY\nEWrX250Zhko',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const row of items) {
  console.log(`${row.videoTitle}: ${row.concurrentViewers} watching now (${row.streamState})`);
}
```

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')

run = client.actor('sian.agency/youtube-live-stream-monitor').call(
    run_input={
        'operation': 'channelLiveStreams',
        'channelId': 'UCSJ4gkVC6NrvII8umztf0Ow',
        'maxPages': 1,
    }
)

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item['streamState'], item.get('concurrentViewers'), '—', item.get('videoTitle'))
```

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/sian.agency~youtube-live-stream-monitor/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"operation":"channelLiveStreams","channelId":"UCSJ4gkVC6NrvII8umztf0Ow","maxPages":1}'
```

#### Automation Workflows (N8N / Zapier / Make)

1. **Trigger**: Apify Scheduler (`*/5 * * * *` for 5-minute polling) or webhook
2. **HTTP Request**: Call this actor's run API with seed channel ID or video IDs
3. **Process**: Iterate the dataset rows in your workflow — each is one snapshot
4. **Action**: Push to Google Sheets, Slack, BigQuery, Notion, or your alerting stack

***

### 📊 Performance & Pricing

#### FREE Tier (Try It Now)

- Generous free credit covers initial channel listings or single viewer snapshots — full feature access, same data quality.
- No credit card required.
- Perfect for testing the real-time feed against your favorite livestream.

#### PAID Tier (Production-Ready)

- **Unlimited** livestream rows and viewer snapshots per run.
- Pay-per-event: only charged for successful rows (errors don't burn your credit).
- Pricing ladder scales from BRONZE to DIAMOND as your volume grows.

**Pricing Highlights — `live-stream-row` (headline):**

- BRONZE: `$0.005` per channel-live-stream row
- GOLD / PLATINUM / DIAMOND: `$0.0025` per row

**Real-time mode — `viewer-count-snapshot`:**

- BRONZE: `$0.008` per snapshot
- GOLD / PLATINUM / DIAMOND: `$0.004` per snapshot

**Run start — `apify-actor-start`:**

- BRONZE+ (paying tiers): `$0.002` per run

💰 **Designed for sub-minute polling loops** — pricing is built to make real-time monitoring viable at scale.

🔗 [View live pricing](https://apify.com/sian.agency/youtube-live-stream-monitor?fpr=sian)

***

### ❓ Frequently Asked Questions

**Q: Does this work for any YouTube channel?**
A: Yes — any public channel. Private / membership-gated streams return as `not_live` or an error row.

**Q: How fresh is the concurrent viewer count?**
A: It's pulled live from YouTube's player metadata endpoint at the moment the run executes. Expect <30 seconds freshness.

**Q: Can I poll the same stream every minute?**
A: Yes — combine with Apify Scheduler. Each run is a fresh snapshot row with `_fetchedAt` timestamp; no in-actor cooldowns.

**Q: What if the stream ends mid-run?**
A: For `viewerSnapshot`: the row returns `streamState: not_live` (no `concurrentViewers`). For `channelLiveStreams`: the row will be `streamState: ended` with cumulative `viewCount`.

**Q: Does it handle scheduled premieres?**
A: Yes — they're tagged `streamState: scheduled`. `concurrentViewers` is null until the stream actually starts.

**Q: How many video IDs can I poll per run?**
A: Up to 500 per `viewerSnapshot` run. Esports orgs can poll a whole tournament bracket in a single call.

**Q: What output formats are available?**
A: JSON, CSV, Excel, RSS, HTML — export directly from the Apify dataset.

**Q: Is this legal?**
A: Yes — we only extract publicly available data that YouTube already exposes to every viewer. See our legal section below.

*YouTube is a trademark of Google LLC. This actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Google LLC.*

***

### 🐛 Troubleshooting

**Channel ID not resolving**

- Paste the canonical `UC…` ID, or any channel/handle URL. If using a handle URL, ensure the channel exists by opening it in a browser first.

**`streamState: not_live` for what I thought was a live stream**

- The stream may have just ended, or the video isn't actually a livestream. Check the URL in a browser to confirm. Membership-gated streams also surface as `not_live`.

**`concurrentViewers` is null on a `streamState: live` row**

- Rare upstream timing edge — the stream went live within the last few seconds. Re-poll after 30s to get a populated count.

**Pagination stops earlier than `maxPages`**

- That's expected — the run stops when YouTube returns no more results for that channel.

**Geo / language not returning local results**

- Most livestreams surface globally; `geo` and `lang` adjust localized labels but don't filter the underlying stream set.

***

### ⚖️ Is it legal to scrape data?

Our actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our actors, when used for ethical purposes by Apify users, are safe.

However, you should be aware that your results could contain personal data. Personal data is protected by the **GDPR** in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

You can also read Apify's blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

***

### 🤝 Support

[![Telegram Support](https://img.shields.io/badge/Telegram-Support%20Group-0088cc?logo=telegram)](https://t.me/+vyh1sRE08sAxMGRi)

**Join our active support community**

- For issues or questions, open an issue in the actor's repository
- Check [SIÁN Agency Store](https://apify.com/sian.agency?fpr=sian) for more automation tools
- ✉️ <apify@sian-agency.online>

***

**Built by [SIÁN Agency](https://www.sian-agency.online)** | **[More Tools](https://apify.com/sian.agency?fpr=sian)**

# Actor input Schema

## `operation` (type: `string`):

🎯 **PICK ONE OPERATION PER RUN.** Each run produces one clean dataset matching the chosen mode.

- **📺 Channel Live Streams** — pass a channel ID → get the paginated list of currently-live and recently-ended livestreams for that channel, with `streamState` (live / ended), concurrent viewers, titles and thumbnails.
- **👁 Viewer Count Snapshot** — pass one or more livestream video IDs → get real-time concurrent viewer counts. The **real-time USP** — perfect for polling loops at 1–5 minute intervals.

💡 **TIP:** Start with `Channel Live Streams` to discover currently-live videoIds for a channel. Then feed those IDs into repeated `Viewer Count Snapshot` runs (every N minutes) to build a time series of concurrent viewers per stream.

## `channelId` (type: `string`):

📺 **Required for `Channel Live Streams`.**

Accepts any of:

- Canonical channel ID: `UCSJ4gkVC6NrvII8umztf0Ow`
- Channel URL: `https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow`
- Handle URL: `https://www.youtube.com/@LofiGirl`
- Custom URL: `https://www.youtube.com/c/LofiGirl`

💡 **TIP:** If you paste a handle or custom URL, the actor will resolve it to the canonical channel ID for you (consumes 1 extra upstream call — no extra charge).

## `videoIds` (type: `string`):

👁 **Required for `Viewer Count Snapshot`.**

One or more 11-character YouTube video IDs. Each ID is polled with one upstream call → one dataset row with real-time `concurrentViewers`, `streamState`, `likeCount`.

Accepts:

- One ID per line: `JD-kMIpDfnY\nEWrX250Zhko`
- Comma-separated: `JD-kMIpDfnY, EWrX250Zhko`
- Full URLs: `https://www.youtube.com/watch?v=JD-kMIpDfnY` (the actor will extract the ID)

💡 **TIP:** Combine this with the Apify Scheduler to poll the same set of IDs every N minutes — build a real-time viewer-count time series.

## `maxPages` (type: `integer`):

📄 **Applies to `Channel Live Streams`.** Ignored for `Viewer Count Snapshot`.

Most active channels return all current livestreams on page 1 (~16-30 rows). Channels with many recent ended streams (esports orgs, news networks) may paginate.

- **Channel Live Streams:** ~16-30 streams per page

⚠️ Hard cap: 25 pages to prevent runaway runs.

## `geo` (type: `string`):

🌍 **Optional.** Two-letter country code to localize results. Defaults to `US`.

Examples: `US` (United States), `GB` (United Kingdom), `IN` (India), `BR` (Brazil), `DE` (Germany), `JP` (Japan), `KR` (Korea), `MX` (Mexico).

## `lang` (type: `string`):

🗣 **Optional.** Two-letter language code for localized labels. Defaults to `en`.

Examples: `en`, `es`, `pt`, `hi`, `ja`, `ko`.

## Actor input object example

```json
{
  "operation": "channelLiveStreams",
  "channelId": "UCSJ4gkVC6NrvII8umztf0Ow",
  "videoIds": "JD-kMIpDfnY\nEWrX250Zhko",
  "maxPages": 3,
  "geo": "US",
  "lang": "en"
}
```

# Actor output Schema

## `output` (type: `string`):

Livestream rows with curated camelCase fields (streamState, concurrentViewers, isLive, videoId, videoPageUrl, channelTitle, viewCount, …). One row per livestream listed (channelLiveStreams) or per video polled (viewerSnapshot).

## `report` (type: `string`):

HTML report with run status, success/error counts, peak concurrent viewers, stream-state breakdown, pages fetched, duration, and inputs — written even on fatal crash.

# 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 = {
    "channelId": "UCSJ4gkVC6NrvII8umztf0Ow",
    "videoIds": "JD-kMIpDfnY"
};

// Run the Actor and wait for it to finish
const run = await client.actor("sian.agency/youtube-live-stream-monitor").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 = {
    "channelId": "UCSJ4gkVC6NrvII8umztf0Ow",
    "videoIds": "JD-kMIpDfnY",
}

# Run the Actor and wait for it to finish
run = client.actor("sian.agency/youtube-live-stream-monitor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "channelId": "UCSJ4gkVC6NrvII8umztf0Ow",
  "videoIds": "JD-kMIpDfnY"
}' |
apify call sian.agency/youtube-live-stream-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=sian.agency/youtube-live-stream-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "YouTube Live Stream Real-Time Monitor",
        "description": "Monitor any YouTube livestream's concurrent viewers in real time. List currently-live & recent streams for any channel. Bulk poll 100s of stream IDs. For esports analytics, live-commerce, news-event tracking and brand-safety teams.",
        "version": "1.0",
        "x-build-id": "wgGQIy1ZiauBj3htD"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/sian.agency~youtube-live-stream-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-sian.agency-youtube-live-stream-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/sian.agency~youtube-live-stream-monitor/runs": {
            "post": {
                "operationId": "runs-sync-sian.agency-youtube-live-stream-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/sian.agency~youtube-live-stream-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-sian.agency-youtube-live-stream-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "operation"
                ],
                "properties": {
                    "operation": {
                        "title": "🎯 Operation — what do you want to scrape?",
                        "enum": [
                            "channelLiveStreams",
                            "viewerSnapshot"
                        ],
                        "type": "string",
                        "description": "🎯 **PICK ONE OPERATION PER RUN.** Each run produces one clean dataset matching the chosen mode.\n\n- **📺 Channel Live Streams** — pass a channel ID → get the paginated list of currently-live and recently-ended livestreams for that channel, with `streamState` (live / ended), concurrent viewers, titles and thumbnails.\n- **👁 Viewer Count Snapshot** — pass one or more livestream video IDs → get real-time concurrent viewer counts. The **real-time USP** — perfect for polling loops at 1–5 minute intervals.\n\n💡 **TIP:** Start with `Channel Live Streams` to discover currently-live videoIds for a channel. Then feed those IDs into repeated `Viewer Count Snapshot` runs (every N minutes) to build a time series of concurrent viewers per stream.",
                        "default": "channelLiveStreams"
                    },
                    "channelId": {
                        "title": "📺 Channel ID or YouTube channel URL",
                        "type": "string",
                        "description": "📺 **Required for `Channel Live Streams`.**\n\nAccepts any of:\n- Canonical channel ID: `UCSJ4gkVC6NrvII8umztf0Ow`\n- Channel URL: `https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow`\n- Handle URL: `https://www.youtube.com/@LofiGirl`\n- Custom URL: `https://www.youtube.com/c/LofiGirl`\n\n💡 **TIP:** If you paste a handle or custom URL, the actor will resolve it to the canonical channel ID for you (consumes 1 extra upstream call — no extra charge)."
                    },
                    "videoIds": {
                        "title": "👁 Video IDs to snapshot (one per line, or comma-separated)",
                        "type": "string",
                        "description": "👁 **Required for `Viewer Count Snapshot`.**\n\nOne or more 11-character YouTube video IDs. Each ID is polled with one upstream call → one dataset row with real-time `concurrentViewers`, `streamState`, `likeCount`.\n\nAccepts:\n- One ID per line: `JD-kMIpDfnY\\nEWrX250Zhko`\n- Comma-separated: `JD-kMIpDfnY, EWrX250Zhko`\n- Full URLs: `https://www.youtube.com/watch?v=JD-kMIpDfnY` (the actor will extract the ID)\n\n💡 **TIP:** Combine this with the Apify Scheduler to poll the same set of IDs every N minutes — build a real-time viewer-count time series."
                    },
                    "maxPages": {
                        "title": "📄 Max pages to fetch",
                        "minimum": 1,
                        "maximum": 25,
                        "type": "integer",
                        "description": "📄 **Applies to `Channel Live Streams`.** Ignored for `Viewer Count Snapshot`.\n\nMost active channels return all current livestreams on page 1 (~16-30 rows). Channels with many recent ended streams (esports orgs, news networks) may paginate.\n\n- **Channel Live Streams:** ~16-30 streams per page\n\n⚠️ Hard cap: 25 pages to prevent runaway runs.",
                        "default": 3
                    },
                    "geo": {
                        "title": "🌍 Country (optional, ISO 3166-1 alpha-2)",
                        "type": "string",
                        "description": "🌍 **Optional.** Two-letter country code to localize results. Defaults to `US`.\n\nExamples: `US` (United States), `GB` (United Kingdom), `IN` (India), `BR` (Brazil), `DE` (Germany), `JP` (Japan), `KR` (Korea), `MX` (Mexico).",
                        "default": "US"
                    },
                    "lang": {
                        "title": "🗣 Language (optional, ISO 639-1)",
                        "type": "string",
                        "description": "🗣 **Optional.** Two-letter language code for localized labels. Defaults to `en`.\n\nExamples: `en`, `es`, `pt`, `hi`, `ja`, `ko`.",
                        "default": "en"
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
