Dataspryva

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.

FieldTypeRequiredDescription
broadcastIdsarrayrequiredPaste 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.
includeViewerStatsbooleanoptionalInclude current/total viewers, the viewer-history graph when X exposes it, and derived peak/average viewers. Turn off for a lighter output.
includeViewerTimelinebooleanoptionalPush 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
FieldTypeRequiredDescription
broadcastIdsarrayrequiredPaste 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.
includeViewerStatsbooleanoptionalInclude current/total viewers, the viewer-history graph when X exposes it, and derived peak/average viewers. Turn off for a lighter output.
includeViewerTimelinebooleanoptionalPush one "viewer timeline point" row per point of the broadcast's viewer-history graph. No rows are emitted when X provides no graph.
maxViewerTimelinePointsintegeroptionalMaximum 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.
includeReplayVideobooleanoptionalResolve 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.
includeChatHistorybooleanoptionalCollect 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.
maxChatMessagesintegeroptionalMaximum public chat text messages per broadcast. Older events and join/heart events are not counted.
includeThumbnailbooleanoptionalStore the broadcast cover image in the run's key-value store and return its stable URL plus the original X image URL.
includeBroadcasterProfilebooleanoptionalAdd 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.

FieldTypeRequiredDescription
broadcastsstringoptionalCollected 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

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/w share links, Spaces, deleted broadcasts, and rate limits each get a clear message instead of a silent failure.
  • Empty fields are omitted — no null values 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
}
{
  "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.

Open the step-by-step Python guide →

Source build RQ0JBxm63hdzUYFf3. Documentation is regenerated from the default published build; private drafts are not included.