Force Chrome tabs to behave as if they have focus, even when the browser window is in the background. This is useful for testing or automating pages that pause animations, timers, or other behavior when the tab loses focus.
Both scripts prevent focus/blur/visibility detection using two approaches:
Emulation.setFocusEmulationEnabled- Tells Chrome to emulate focus at the protocol level- JavaScript API overrides - Injects code to override:
document.visibilityState→'visible'document.hidden→falsedocument.hasFocus()→truewindow.blur()/window.focus()→ no-op- Blocks
visibilitychangeandblurevents
- Bun runtime installed
- Google Chrome with remote debugging enabled
# Quit existing Chrome first
pkill -f "Google Chrome"
# Start Chrome with remote debugging
open -a "Google Chrome" --args --remote-debugging-port=9222
# Optional: Add flags for better visibility suppression
open -a "Google Chrome" --args --remote-debugging-port=9222 \
--disable-backgrounding-occluded-windows \
--disable-renderer-backgrounding \
--disable-background-timer-throttlingUses the chrome-remote-interface library. Requires bun install to install dependencies.
Standalone version with no dependencies. Uses raw WebSocket + fetch instead of chrome-remote-interface. Has a fallback mechanism: tries HTTP discovery (/json) first, then falls back to the browser WebSocket if discovery endpoints are unavailable.
Both scripts automatically discover and attach to all open Chrome tabs.
# Simple version (requires bun install first)
bun run focus-emulation-cdp-lib.js [port]
# Standalone version (no dependencies)
bun run focus-emulation-raw-ws.js [port]Port defaults to 9222 if not specified. Press Ctrl+C to disable focus emulation and disconnect.
The scripts connect to Chrome's DevTools Protocol (CDP) over WebSocket. For each tab, they:
- Attach via
Target.attachToTarget(avoids conflicts with other debuggers) - Enable focus emulation with
Emulation.setFocusEmulationEnabled - Inject a script via
Page.addScriptToEvaluateOnNewDocumentto override visibility/focus APIs
The connection must stay open for the emulation to remain active — closing the script reverts the behavior.
- Emulation applies to all tabs — both scripts automatically discover and attach to all open Chrome tabs.
- Emulation is per-tab — switching to another tab doesn't move emulation; the original tab keeps it.
- New tabs require restart — tabs opened after the script starts won't have emulation. Restart the script to pick them up.