X Broadcast Viewer History & Replay Link Scraper
Get a public X broadcast's title, state, start/end times, viewer counts over time, thumbnail, broadcaster profile, and an optional replay stream link, resolved from a broadcast link or ID.
Input schema
Input fields, types, required flags, descriptions, defaults, and prefills come from the published definition. Prefill examples are distinct from defaults.
| Field | Type | Required | Description |
|---|---|---|---|
broadcastIds | array | required | Paste broadcast links such as https://x.com/i/broadcasts/1YGNrbPLejQGw, bare broadcast IDs, post links that announce a broadcast, or legacy Periscope links (/v/<id> or /<user>/<id>). Old pscp.tv/w share links cannot be resolved and return a status row. |
includeViewerStats | boolean | optional | Include current/total viewers, the viewer-history graph when X exposes it, and derived peak/average viewers. Turn off for a lighter output. |
includeViewerTimeline | boolean | optional | Push one "viewer timeline point" row per point of the broadcast's viewer-history graph. No rows are emitted when X provides no graph. |
Show all input fields
| Field | Type | Required | Description |
|---|---|---|---|
broadcastIds | array | required | Paste broadcast links such as https://x.com/i/broadcasts/1YGNrbPLejQGw, bare broadcast IDs, post links that announce a broadcast, or legacy Periscope links (/v/<id> or /<user>/<id>). Old pscp.tv/w share links cannot be resolved and return a status row. |
includeViewerStats | boolean | optional | Include current/total viewers, the viewer-history graph when X exposes it, and derived peak/average viewers. Turn off for a lighter output. |
includeViewerTimeline | boolean | optional | Push one "viewer timeline point" row per point of the broadcast's viewer-history graph. No rows are emitted when X provides no graph. |
maxViewerTimelinePoints | integer | optional | Maximum timeline rows per broadcast. 0 means all points. When capped, points are evenly sampled across the full broadcast and each row keeps its original index. |
includeReplayVideo | boolean | optional | Resolve the HLS playback URL and stream status. For a live broadcast the URL is the live stream; for an ended broadcast it is the replay. |
includeChatHistory | boolean | optional | Collect text messages from the broadcast's public chat replay after it ends. Live chat and private chats are not collected. No text is emitted when the chat only contains join/heart events. |
maxChatMessages | integer | optional | Maximum public chat text messages per broadcast. Older events and join/heart events are not counted. |
includeThumbnail | boolean | optional | Store the broadcast cover image in the run's key-value store and return its stable URL plus the original X image URL. |
includeBroadcasterProfile | boolean | optional | Add the broadcaster's public profile (followers, bio, location, account creation date, pinned posts). Falls back to the compact broadcaster record if the profile is unavailable. |
Download the published input schema
View complete JSON
{
"properties": {
"broadcastIds": {
"description": "Paste broadcast links such as https://x.com/i/broadcasts/1YGNrbPLejQGw, bare broadcast IDs, post links that announce a broadcast, or legacy Periscope links (/v/<id> or /<user>/<id>). Old pscp.tv/w share links cannot be resolved and return a status row.",
"editor": "stringList",
"example": [
"https://x.com/i/broadcasts/1YGNrbPLejQGw",
"1YGNrbPLejQGw",
"https://x.com/SpaceX/status/1649033533846097927"
],
"minItems": 1,
"prefill": [
"https://x.com/i/broadcasts/1YGNrbPLejQGw"
],
"title": "Broadcast links, IDs or broadcast posts",
"type": "array"
},
"includeBroadcasterProfile": {
"default": true,
"description": "Add the broadcaster's public profile (followers, bio, location, account creation date, pinned posts). Falls back to the compact broadcaster record if the profile is unavailable.",
"prefill": true,
"title": "Include broadcaster profile",
"type": "boolean"
},
"includeChatHistory": {
"default": false,
"description": "Collect text messages from the broadcast's public chat replay after it ends. Live chat and private chats are not collected. No text is emitted when the chat only contains join/heart events.",
"prefill": false,
"title": "Include public chat replay",
"type": "boolean"
},
"includeReplayVideo": {
"default": false,
"description": "Resolve the HLS playback URL and stream status. For a live broadcast the URL is the live stream; for an ended broadcast it is the replay.",
"prefill": false,
"title": "Include replay video link",
"type": "boolean"
},
"includeThumbnail": {
"default": true,
"description": "Store the broadcast cover image in the run's key-value store and return its stable URL plus the original X image URL.",
"prefill": true,
"title": "Include thumbnail image",
"type": "boolean"
},
"includeViewerStats": {
"default": true,
"description": "Include current/total viewers, the viewer-history graph when X exposes it, and derived peak/average viewers. Turn off for a lighter output.",
"prefill": true,
"title": "Include viewer statistics",
"type": "boolean"
},
"includeViewerTimeline": {
"default": false,
"description": "Push one \"viewer timeline point\" row per point of the broadcast's viewer-history graph. No rows are emitted when X provides no graph.",
"prefill": false,
"title": "Emit viewer timeline points as rows",
"type": "boolean"
},
"maxChatMessages": {
"default": 1000,
"description": "Maximum public chat text messages per broadcast. Older events and join/heart events are not counted.",
"maximum": 100000,
"minimum": 1,
"prefill": 100,
"title": "Max chat messages per broadcast",
"type": "integer"
},
"maxViewerTimelinePoints": {
"default": 0,
"description": "Maximum timeline rows per broadcast. 0 means all points. When capped, points are evenly sampled across the full broadcast and each row keeps its original index.",
"maximum": 50000,
"minimum": 0,
"prefill": 0,
"title": "Max viewer timeline points per broadcast",
"type": "integer"
}
},
"required": [
"broadcastIds"
],
"schemaVersion": 1,
"title": "Twitter (X) Broadcast Scraper",
"type": "object"
}
Output schema
Published result links and storage locations. This schema is not an exhaustive contract for every field in a dataset record.
| Field | Type | Required | Description |
|---|---|---|---|
broadcasts | string | optional | Collected broadcast rows and status rows. |
Download the published output schema
View complete JSON
{
"actorOutputSchemaVersion": 1,
"description": "One row per X broadcast, viewer-timeline point, public chat message, or status row, with metadata, viewer statistics, HLS replay, broadcaster profile and chat counts.",
"properties": {
"broadcasts": {
"description": "Collected broadcast rows and status rows.",
"template": "{{links.apiDefaultDatasetUrl}}/items",
"title": "X broadcasts",
"type": "string"
}
},
"title": "X Broadcast Viewer History & Replay Link Scraper Output",
"type": "object"
}
Dataset schema
Published dataset views and any declared field definitions. A view can select only a subset of the returned record fields.
Download the published dataset schema
View complete JSON
{
"actorSpecification": 1,
"views": {
"overview": {
"display": {
"component": "table",
"properties": {}
},
"title": "Broadcasts",
"transformation": {
"fields": [
"type",
"title",
"state",
"broadcaster.username",
"viewersNow",
"viewersTotal",
"startedAt",
"url"
]
}
}
}
}
Key-value schema
Published key-value store definitions, when provided by this build.
This definition is not present in the default published build. See the published README for available documentation.
Published README
Read the full published documentation
X Broadcast Viewer History & Replay Link Scraper
Collect public X broadcasts from a broadcast link, a bare broadcast ID, an announcement post, or a legacy Periscope link. Get the title, state, timing, viewer counts and viewer-history graph, an HLS playback link, a stable cover image, the broadcaster's public profile, and — when the broadcast has ended and its chat is public — the chat replay text. No X account, cookies, or API key required.
What this actor does
- One target list, many link forms:
x.com/i/broadcasts/...,twitter.com/i/broadcasts/..., bare IDs, post links that announce a broadcast, and legacy Periscope/v/<id>or/<user>/<id>links. - Metadata and timing: title, state, creation/start/end times, duration, dimensions, media key, language, tags, and the announcement post.
- Viewer statistics: current/total counters, the viewer-history graph when X exposes it, and derived peak/average viewers. The graph is sample counts, not a fabricated timeline.
- Replay and playback: an HLS playback URL and stream status. Live broadcasts return the live HLS URL; ended broadcasts return the replay URL.
- Public chat replay: optional text messages from an ended, public chat. Live and private chats are not collected; join/heart events are ignored.
- Broadcaster profile: followers, bio, location, account creation date, pinned posts, and verification details, with a compact fallback.
- Stable cover image: the expiring X thumbnail is stored in the run's key-value store; the original X URL is kept beside it.
- Honest status rows: invalid links, old
pscp.tv/wshare links, Spaces, deleted broadcasts, and rate limits each get a clear message instead of a silent failure. - Empty fields are omitted — no
nullvalues or placeholder strings.
Output per record
Each row has a type:
type |
Meaning |
|---|---|
broadcast |
One broadcast's metadata, viewer statistics, playback, chat summary and broadcaster |
viewer timeline point |
One sampled point of the viewer-history graph (only when timeline rows are enabled) |
chat message |
One public chat text message (only when chat replay is enabled and available) |
status |
A problem row with a status and a human-readable message |
Broadcast fields
- Identity:
id,url,title,state,status(X's machine state when it publishes one) - Timing:
createdAt,updatedAt,startedAt,endedAt,durationSeconds - Viewers:
viewersNow,viewersTotal,viewCountGraph[],viewerHistoryAvailable,viewerGraphPoints,peakViewers,averageViewers,viewerTimelineSampled - Media:
thumbnailUrl(stable),thumbnailUrlOriginal,width,height,mediaKey,cameraRotation,isHighLatency - Replay:
replayAvailable,playbackKind(live/replay/upcoming),streamStatus,replayVideoUrl,replayVideoFormat - Chat:
chatHistoryStatus,chatMessageCount,chatEventCount,chatHistoryTruncated - Broadcaster:
broadcaster(public profile; compact fallback) - Context:
language,tags[],announcementTweetId,announcementTweetUrl,sourceTweetId,sourceTweetUrl(when the input was a post),chatOption,privateChat,isLocked,noHearts,hasModeration,source,collectedAt
Viewer timeline fields
broadcastId, broadcastUrl, title, pointIndex (original graph position), viewers, elapsedSeconds, timestamp, timeEstimated, collectedAt.
Chat message fields
broadcastId, broadcastUrl, title, messageId, username, displayName, text, timestamp, elapsedSeconds, profileImageUrl, twitterId, verified, participantIndex, collectedAt.
Input
| Field | Type | Default | Description |
|---|---|---|---|
broadcastIds |
array | – | Broadcast links, bare IDs, announcement posts, or legacy Periscope /v/<id> / /<user>/<id> links (required) |
includeViewerStats |
boolean | true |
Current/total viewers, viewer-history graph and derived peak/average |
includeViewerTimeline |
boolean | false |
Emit one row per viewer-history point |
maxViewerTimelinePoints |
integer | 0 |
Max timeline rows per broadcast; 0 = all; capped runs sample evenly |
includeReplayVideo |
boolean | false |
Resolve the HLS playback URL and stream status |
includeChatHistory |
boolean | false |
Collect public chat replay text after the broadcast ends |
maxChatMessages |
integer | 1000 |
Max public chat text messages per broadcast |
includeThumbnail |
boolean | true |
Store the cover image and return a stable URL plus the original |
includeBroadcasterProfile |
boolean | true |
Add the broadcaster's public profile; falls back to the compact record |
Example: broadcast metadata
{
"broadcastIds": ["https://x.com/i/broadcasts/1YGNrbPLejQGw"]
}
Example: viewer history plus replay
{
"broadcastIds": ["1YGNrbPLejQGw"],
"includeViewerTimeline": true,
"includeReplayVideo": true
}
Example: public chat replay
{
"broadcastIds": ["https://x.com/i/broadcasts/1BdGYEQPeDNGX"],
"includeChatHistory": true,
"maxChatMessages": 200
}
Example: mixed links and a deleted broadcast
{
"broadcastIds": [
"https://x.com/i/broadcasts/1YGNrbPLejQGw",
"https://www.periscope.tv/v/1kvJpmapzboxE",
"https://x.com/i/broadcasts/1AAAAAAAAAAAA"
],
"includeReplayVideo": true
}
Use cases
- Live-event monitoring: track audience size during and after a public broadcast.
- Newsroom verification: confirm viewer counts, timing and the announcement post for a public statement.
- Archival: preserve broadcast metadata, a stable cover image and a replay URL while they are still available.
- Creator comparison: compare audience, duration and chat activity across broadcasters.
- Dashboard feeds: load the viewer timeline or chat rows directly into a chart or spreadsheet.
- Chat research: study public chat replay around an event without collecting private or live chat.
FAQ
Do I need an X account, cookies or a proxy? No. The actor reads publicly visible broadcast data and selects a working connection automatically. Just add one or more targets and run it.
What counts as an X broadcast?
X live video, the product that replaced Periscope. Its canonical link is x.com/i/broadcasts/<id>; twitter.com links redirect there. Legacy Periscope replay pages no longer exist, but their broadcast IDs can still resolve at x.com when the broadcast survives. If X returns an upcoming broadcast, the row reports the state X publishes and playbackKind: "upcoming"; X's guest payload does not expose reliable scheduled start times or pre-live slate URLs, so those fields are omitted rather than guessed.
Why is the viewer-history graph missing for some broadcasts?
X exposes view_count_graph for only a subset of broadcasts: 26 of 50 (52%) in our October 2026 sample, and rarely for older ones. The actor never invents points; when X has no graph it reports viewerHistoryAvailable: false and omits peak/average.
Are the viewer timeline timestamps exact?
X returns viewer counts only, without per-point times. Timestamps are derived evenly from the broadcast's real start/end (or the collection time for a live broadcast) and flagged timeEstimated: true. averageViewers is the mean of X's sampled points.
What do viewersTotal and viewersNow mean?
They are X's own counters. viewersTotal is not a unique-viewer count, and on an ended broadcast viewersNow is the last concurrent count X reported, not a live figure.
Is the replay a downloadable video?
No. replayVideoUrl is an HLS playback URL for a standard player or your own pipeline. For a live broadcast it is the live HLS URL (playbackKind: "live"); the replay appears after the broadcast ends. Some regional CDN edges return 403 unless the request carries Referer: https://x.com/; add that header if your player is refused.
Why is a replay or chat missing?
A deleted or non-public broadcast has no replay. A live broadcast has no replay yet. Chat replay is collected only after a broadcast ends, only for public chats, and only when X still serves the chat history; many chats contain only join/heart events, so chatMessageCount can be 0. History is read in pages of up to 1,000 events with a 50-page cap per broadcast; maxChatMessages caps text rows, and chatHistoryTruncated marks a capped result.
Do legacy Periscope links work?
/v/<id> and /<user>/<id> links resolve by their trailing broadcast ID. Old pscp.tv/w/... share links are not broadcast IDs and return a legacyShareLinkUnsupported status row.
Does this work on X Spaces?
No. Spaces are audio rooms; they return a spacesNotSupported status row.
Is this affiliated with X? No. This is an independent, third-party actor that reads publicly visible broadcast data and is not operated by or affiliated with X Corp.
Python quickstart
Use a schema-derived input and the Python standard library to start a run. An Apify account and token are required for execution.
Source build RQ0JBxm63hdzUYFf3. Documentation is regenerated from the default published build; private drafts are not included.