-
Notifications
You must be signed in to change notification settings - Fork 0
Live Chat 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.
- Launches a hidden Chrome/Edge instance on the live chat popout:
https://www.youtube.com/live_chat?is_popout=1&v=<videoId> - Scrapes new messages straight off the page's DOM via the Chrome DevTools Protocol (CDP) - no API, no rate limit.
- 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. - 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 stopalways disconnects.
The fallback needs Node 22+ (built-in WebSocket) and a Chrome or Edge install - no puppeteer, no playwright.
"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.
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.
- The log shows
live chat: fetch path failing (...) - switching to DOM fallbackwhen 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(inmodern-youtubechat/FallbackDOMcontent/fallback-chat.mjs) is a one-shot helper for testing a stream without running the full loop.