Skip to content

Live Chat Fallback

SynacNipo edited this page Aug 5, 2026 · 5 revisions

Live chat rate limits (DOM fallback)

YouTube rate-limits the InnerTube API used by the default fetch-based chat reader (HTTP 429), which can kill a live chat session entirely. When that happens (persistent 429 / 5xx on connect or poll), the script automatically switches to a DOM fallback instead of disconnecting.

How it works

  1. Launches a hidden Chrome/Edge instance on the live chat popout: https://www.youtube.com/live_chat?is_popout=1&v=<videoId>
  2. Scrapes new messages straight off the page's DOM via the Chrome DevTools Protocol (CDP) - no API, no rate limit.
  3. The first read primes the baseline (the pre-existing backlog is never replayed), then every message is deduped by its id, so only new messages are delivered. Priming waits a few seconds (settleMs) for YouTube to hydrate the recent messages into the page, and the prime read itself is swallowed - so the console never floods with old chat.
  4. Every couple of minutes it probes the fetch API; the moment YouTube stops rate-limiting, the browser is closed and the session silently returns to the faster fetch path. !live stop always disconnects.

The fallback needs Node 22+ (built-in WebSocket) and a Chrome or Edge install - no puppeteer, no playwright.

Settings (settings.jsonlivechat.fallback)

"livechat": {
  "fallback": {
    "enabled": true,
    "headless": true,
    "chromePath": "auto",
    "baseUrl": "https://www.youtube.com/live_chat?is_popout=1&v=",
    "publicFallback": true,
    "profileDir": "",
    "pollMs": 1500,
    "loadTimeoutMs": 30000,
    "connectTimeoutMs": 15000,
    "tryFetchMs": 120000,
    "settleMs": 4000
  }
}
setting default what it does
enabled true false = fail (and disconnect) instead of opening a browser
headless true true = hidden browser, false = visible window (you can watch the chat)
chromePath auto 'auto' = first Chrome/Edge found, or an explicit .exe path
baseUrl https://www.youtube.com/live_chat?is_popout=1&v= popout page opened by the fallback
publicFallback true bounce to the public popout if the page redirects to a sign-in/consent page
profileDir '' persistent Chrome profile folder; keeps login across sessions
pollMs 1500 ms between DOM scrapes
loadTimeoutMs 30000 max wait for the chat panel to appear
connectTimeoutMs 15000 max wait for the browser's debugging port/page
tryFetchMs 120000 after this long on the fallback, start probing whether the fetch API recovered; on success the browser is closed and the session silently returns to fast fetch polling. 0 = stay on DOM until !live stop
settleMs 4000 wait this long after the chat panel appears before priming, so YouTube's backlog hydration settles and is swallowed as baseline instead of flooding the console

The browser is only meant as a bridge during a rate-limit storm: once the fetch API answers again (default after ~2 minutes), Chrome is killed and the session goes back to the faster fetch path - no browser left running when it isn't needed.

Subscribers-only / members-only chat

If the stream's chat is restricted, set profileDir to a folder (e.g. modern-youtubechat/FallbackDOMcontent/profile) and connect once with a visible window (headless: false). Sign in to the YouTube account in that window, then !live stop and reconnect - the login is kept in the profile folder and reused on every fallback session.

Notes

  • The log shows live chat: fetch path failing (...) - switching to DOM fallback when the handoff happens.
  • If the chat panel never appears, you'll see live chat fallback: chat panel not detected - stream may not have chat enabled - the streamer may have chat disabled entirely.
  • probeDomChat (in modern-youtubechat/FallbackDOMcontent/fallback-chat.mjs) is a one-shot helper for testing a stream without running the full loop.

Clone this wiki locally