Keep Instagram videos and reels playing when you switch tabs or apps. Stops Instagram from pausing playback the moment you look away, and keeps picture-in-picture live instead of frozen.
// ==UserScript==
// @name Instagram Background Play
// @description Keep Instagram videos and reels playing when you switch tabs or apps. Stops Instagram from pausing playback the moment you look away, and keeps picture-in-picture live instead of frozen.
// @version 1.0.3
// @author Zingzy
// @namespace https://github.com/Zingzy/instagram-background-play
// @homepageURL https://github.com/Zingzy/instagram-background-play
// @supportURL https://github.com/Zingzy/instagram-background-play/issues
// @match https://www.instagram.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=instagram.com
// @license MIT
// @run-at document-start
// @grant none
// ==/UserScript==
(function () {
'use strict';
// Instagram pauses playback as soon as the tab or window loses focus.
// It detects this through the Page Visibility API and focus events,
// and additionally calls pause() from its own player logic.
// This script defuses all three paths.
// Keep a handle on the real visibility getter before spoofing it,
// so we can still tell when the tab is genuinely hidden.
const nativeVisibility = Object.getOwnPropertyDescriptor(
Document.prototype,
'visibilityState'
).get;
const reallyHidden = () => nativeVisibility.call(document) !== 'visible';
// 1. Spoof the Page Visibility API: the page always reports "visible".
Object.defineProperty(Document.prototype, 'visibilityState', {
get: () => 'visible',
configurable: true,
});
Object.defineProperty(Document.prototype, 'hidden', {
get: () => false,
configurable: true,
});
document.hasFocus = () => true;
// 2. Swallow the events Instagram listens to for detecting you leaving.
// Capturing on window runs before any page listener can react.
const block = (e) => e.stopImmediatePropagation();
for (const type of [
'visibilitychange',
'webkitvisibilitychange',
'blur',
'focusout',
'pagehide',
'freeze',
]) {
window.addEventListener(type, block, true);
}
// 3. The hammer: drop programmatic pause() calls while the tab is
// actually backgrounded. Manual pauses still work, since they happen
// while the tab is visible or go through browser UI (like
// picture-in-picture controls) which bypasses this method entirely.
const nativePause = HTMLMediaElement.prototype.pause;
HTMLMediaElement.prototype.pause = function () {
if (reallyHidden()) return;
return nativePause.call(this);
};
})();