Instagram no me deja avanzar un Reel. Así que construí ReelBit.

En Instagram web no puedes mover la barra de un Reel. Ni cambiar la velocidad. Ni saltar cinco segundos. Si te perdiste algo, o quieres volver a ver el giro del final, tienes que ver el Reel entero otra vez.
Me molestó lo suficiente como para dedicarle un fin de semana. Lo llamé playIg, y la idea era simple: una extensión de Chrome que pegue unos controles de reproductor de verdad encima de cada Reel. Hoy se llama ReelBit, tiene landing, política de privacidad y un vídeo promocional, y ya está publicada en la Chrome Web Store. Esto es lo que pasó entre una cosa y la otra.
El enfoque: no pelearse con el DOM de Instagram
Es una extensión MV3 sin framework y sin build step. Tres piezas:
- un content script + CSS que dibuja la barra,
- un script minúsculo en el MAIN world para tocar cosas que el content script no ve,
- un popup para los ajustes.
La decisión que más me ahorró dolor: no meter nada dentro del DOM de Instagram. Su markup cambia, está generado, y cualquier cosa que cuelgues ahí se rompe en el siguiente deploy. En su lugar, la barra es un elemento con position: fixed colgado de document.body, y sigue a cada <video> leyendo su getBoundingClientRect. Un único bucle de requestAnimationFrame compartido y un IntersectionObserver para saber qué vídeo está en pantalla. Nada más.
Los gotchas que aprendí a golpes
Instagram pausa los vídeos en visibilitychange. Cambias de pestaña y el Reel se para. Para que ReelBit permita reproducción en segundo plano (opt-in), el script del MAIN world sobrescribe document.hidden. Es el único sitio donde tiene sentido tocarlo: el content script vive en otro mundo y no lo vería.
Instagram secuestra los clics sobre el Reel. Un clic sobre el vídeo dispara sus propias acciones. Mis botones recibían clics que no eran suyos, así que la barra hace stopPropagation antes de que lleguen al Reel.
El botón de mute es una trampa. Lo obvio es video.muted = true. Funciona... y desincroniza el estado de React de Instagram: el vídeo calla, pero el icono sigue diciendo que suena. La solución es fea pero estable: ReelBit hace clic en el propio botón de audio de Instagram. Y no puedo buscarlo por aria-label, porque está localizado, ni por su SVG, porque cambia según el estado. Lo encuentro por posición: abajo a la derecha, con un único SVG de 12px.
Las fechas salen del shortcode. Cuando la página no trae un <time>, decodifico la fecha desde el shortcode de la URL: es base64 con un alfabeto propio → el id del media → un timestamp en los bits altos.
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
const EPOCH_MS = 1314220021721n;
function shortcodeToDate(shortcode) {
let id = 0n;
for (const ch of shortcode) id = id * 64n + BigInt(ALPHABET.indexOf(ch));
return new Date(Number((id >> 23n) + EPOCH_MS));
}
(La versión real valida el alfabeto y descarta fechas imposibles. Esto es la idea.) Con eso, cada Reel muestra su fecha de publicación en la barra y las cuadrículas de perfil ganan una insignia de fecha en cada miniatura.
Una barra que no estorba
La primera versión tapaba la cabecera de las Stories. Funcional, pero molesta. Ahora la barra se colapsa a una línea fina de progreso y se expande al pasar el ratón por encima. Si prefieres tenerla siempre visible, la fijas con el pin.

Un historial que Instagram solo da en el móvil
En octubre de 2025 Instagram añadió un historial de Reels vistos, pero solo en la app móvil. En la web, nada. ReelBit guarda uno propio: los últimos 500 Reels en chrome.storage.local.
Y nunca con cookies. Una cookie en instagram.com viaja a los servidores de Meta en cada petición; justo lo contrario de lo que quiero para algo que es solo mío. chrome.storage.local se queda en tu dispositivo, punto.

El nombre: del "playIg" al "ReelBit for Instagram"
Antes de publicar leí las brand guidelines de Meta. No permiten usar "Insta", "Gram" ni abreviaturas como "IG" en el nombre de un producto. Lo único permitido, y solo de forma descriptiva, es el patrón "X for Instagram". Así que playIg murió y nació ReelBit for Instagram. Y el disclaimer, bien visible: no está afiliado a Instagram ni a Meta.
Un rename a última hora duele, pero es mejor que el rechazo en la tienda.
Identidad: pixel art en todas partes
Ya que iba a renombrarlo, le di una identidad propia. Pixel art:
- el logo es una rejilla de 16×16,
- los iconos son SVG de 9×9 píxeles con
currentColor, así heredan el color del tema, - la fuente es Silkscreen, que solo se ve nítida en múltiplos de 8px. Fuera de esos múltiplos, los píxeles se emborronan.
Las capturas de la tienda y el vídeo promocional los renderizo de forma determinista, frame a frame, con Playwright + ffmpeg, a partir de una página HTML que usa el CSS y los iconos reales de la extensión. Sin contenido de gente real: los "Reels" de las capturas son pixel art de atardeceres y ciudades.

Publicar: la landing y el formulario de privacidad
La landing vive en reelbit.joca.dev, servida por este mismo sitio Next.js. No monté otro proyecto: un check del host en el middleware, antes de next-intl, reescribe las rutas del subdominio al árbol /[locale]/reelbit. Un sitio, un deploy, dos dominios.
Lo otro que no esperaba: el formulario de privacidad de la Chrome Web Store te obliga a declarar los datos aunque solo vivan en tu dispositivo. ReelBit guarda un historial, así que "historial web" va marcado como sí, aunque nunca salga del navegador. Tiene sentido, pero hay que leerlo con calma. Tienes la política de privacidad completa.
Qué viene
Ya está publicada en la Chrome Web Store: Instalar ReelBit desde la Chrome Web Store.
Mientras tanto puedes ver la landing o el vídeo de presentación. Si la pruebas y algo se rompe, o Instagram cambia algo y la barra se descoloca, me interesa saberlo. Es justo la clase de proyecto que vive de feedback.