Anular todas las suscripciones de YouTube a la vez

Date de baja de todos los canales de golpe y conserva los que elijas. Gratis, en tu navegador, sin dar tu contraseña a nadie.

unsubscribe-all.js · 133 líneaspégalo en la consola (F12) de www.youtube.com
// Responsive Muse · Unsubscribe From All YouTube Channels · v1.1 · 2026-10-22
// Unsubscribes you from every channel, except the ones you list in KEEP.
// Runs only on youtube.com/feed/channels. It counts first and asks before changing anything,
// then clicks the same Unsubscribe button and confirmation you would. It makes no network
// requests of its own and never reads cookies, passwords or tokens.
(async () => {
  const TOOL = 'Anular todas las suscripciones';
  const KEEP = [];        // channels to keep, by name or @handle, e.g. ['@mkbhd', 'Veritasium']
  const LIMIT = 0;        // stop after this many channels (0 = no limit)
  const DELAY = 900;      // pause between actions, in milliseconds

  if (location.hostname !== 'www.youtube.com' || location.pathname !== '/feed/channels') {
    alert('Abre primero tus suscripciones (con tu sesión iniciada):\nhttps://www.youtube.com/feed/channels');
    return;
  }
  // A small box on the page shows progress and asks before changing anything,
  // so you never need to read or edit the console.
  const many = (n, word) => `${n} ${n === 1 ? word : ({ canal: 'canales', 'canción': 'canciones', 'publicación': 'publicaciones', 'elemento guardado': 'elementos guardados' })[word] || word + 's'}`;   // 1 vídeo, 2 vídeos
  const panel = (() => {
    const box = document.createElement('div');
    box.style.cssText = 'position:fixed;right:16px;bottom:16px;z-index:2147483647;width:340px;max-width:calc(100vw - 32px);' +
      'background:#111318;color:#e6e8ee;font:14px/1.5 system-ui,sans-serif;border-radius:12px;padding:16px;' +
      'box-shadow:0 8px 30px rgba(0,0,0,.4);text-align:left';
    const head = document.createElement('strong');
    head.textContent = TOOL;
    const msg = document.createElement('p');
    msg.style.cssText = 'margin:8px 0 12px;white-space:pre-line';
    const row = document.createElement('div');
    row.style.cssText = 'display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end';
    box.append(head, msg, row);
    document.body.append(box);
    const button = (label, primary, onClick) => {
      const b = document.createElement('button');
      b.textContent = label;
      b.style.cssText = 'font:600 14px system-ui,sans-serif;padding:8px 14px;border-radius:8px;cursor:pointer;' +
        (primary ? 'background:#0f766e;color:#fff;border:1px solid #0f766e' : 'background:none;color:#e6e8ee;border:1px solid #3a3f4b');
      b.onclick = onClick;
      row.append(b);
    };
    return {
      text(t) { msg.textContent = t; },
      ask(t, yes) {
        msg.textContent = t;
        row.replaceChildren();
        return new Promise(r => {
          button('Cancelar', false, () => { row.replaceChildren(); r(false); });
          button(yes, true, () => { row.replaceChildren(); r(true); });
        });
      },
      stoppable(onStop) { row.replaceChildren(); button('Parar', false, onStop); },
      actions(t, list) {
        msg.textContent = t;
        row.replaceChildren();
        list.forEach(([label, primary, run]) => button(label, primary, run));
      },
      finish(t) { this.actions(t, [['Cerrar', true, () => box.remove()]]); },
      close() { box.remove(); },
    };
  })();
  const sleep = ms => new Promise(r => setTimeout(r, ms));
  // Wait until something shows up on screen (menus can take a moment to open)
  const visible = e => e.getClientRects().length > 0;
  const waitFor = async (find, ms = 4000) => {
    for (let t = 0; t < ms; t += 150) {
      const hit = find();
      if (hit) return hit;
      await sleep(150);
    }
    return null;
  };
  const keep = new Set(KEEP.map(k => k.trim().toLowerCase()));
  const text = (el, sel) => (el.querySelector(sel)?.textContent || '').trim();
  const kept = el => keep.has(text(el, '#channel-title #text').toLowerCase()) || keep.has(text(el, '#subscribers').toLowerCase());
  // The button that unsubscribes is labelled "Unsubscribe from <channel>" (also in other languages)
  const UNSUB = /^(unsubscribe|cancelar (la )?suscripción|anular suscripción|cancelar inscrição|se désabonner|désabonner|abo beenden|annulla iscrizione)/i;
  const unsubButton = el => [...el.querySelectorAll('#subscribe-button button[aria-label]')]
    .find(b => UNSUB.test(b.getAttribute('aria-label')));
  const done = new Set();   // each channel is handled once, even if YouTube is slow to update the button
  const channelId = el => el.data?.channelId || text(el, '#channel-title #text');
  const subscribed = () => [...document.querySelectorAll('ytd-channel-renderer')]
    .filter(el => !kept(el) && !done.has(channelId(el)) && unsubButton(el));

  // 1. Load the whole list
  let last = -1, idle = 0;
  while (idle < 3) {
    window.scrollTo(0, document.documentElement.scrollHeight);
    await sleep(1200);
    const n = document.querySelectorAll('ytd-channel-renderer').length;
    idle = n === last ? idle + 1 : 0;
    last = n;
    panel.text(`Cargando tus suscripciones… ${n} canales`);
  }
  const total = LIMIT ? Math.min(LIMIT, subscribed().length) : subscribed().length;
  if (!total) {
    panel.finish(keep.size ? 'Solo quedan los canales que elegiste conservar.' : 'No estás suscrito a ningún canal.');
    return 0;
  }

  // 2. Ask
  const kept_ = keep.size ? `\nSe conservan: ${KEEP.join(', ')}` : '';
  if (!await panel.ask(`¿Anular la suscripción a ${many(total, 'canal')}?${kept_}\nNo se puede deshacer.`, `Anular ${total}`)) {
    panel.finish('Cancelado. No se ha cambiado nada.');
    return 0;
  }

  // 3. Unsubscribe one by one: the button, then YouTube's confirmation dialog
  let stop = false;
  panel.stoppable(() => { stop = true; });
  let count = 0;
  while (!stop && count < total) {
    const el = subscribed()[0];
    if (!el) break;
    done.add(channelId(el));
    const name = text(el, '#channel-title #text');
    el.scrollIntoView({ block: 'center' });
    unsubButton(el).click();
    const dialog = await waitFor(() => [...document.querySelectorAll('yt-confirm-dialog-renderer')].find(visible));
    const confirm = dialog && [...dialog.querySelectorAll('button')].pop();
    if (!confirm) {
      panel.finish(`Anuladas ${count}; después YouTube no mostró la confirmación para ${name}.\nPuede que YouTube haya cambiado su diseño: avísanos en responsive-muse.com.`);
      return count;
    }
    confirm.click();
    // Wait for the dialog to close, so the next channel doesn't reuse it
    await waitFor(() => !visible(dialog) || null);
    count++;
    panel.text(`Unsubscribing… ${count} of ${total}\n${name}`);
    await sleep(DELAY);
  }
  panel.finish(`${stop ? 'Parado' : 'Hecho'}: anuladas ${count} de ${many(total, 'canal')}.\nRecarga la página para ver el resultado.`);
  return count;
})();

Marcador: arrastra el botón del medio a tu barra de marcadores, abre www.youtube.com y pulsa el marcador. Ejecuta el mismo script con las opciones de arriba.

Por qué es seguro ejecutarloComprobación automática superada 23 oct 2026 · probado en una cuenta real el 22 oct 2026
  • No envía nada a ningún sitio. Sin fetch, XHR ni scripts externos. La única actividad de red es la de www.youtube.com cargando tu lista.
  • No toca tu sesión. No lee cookies, contraseñas, tokens ni el almacenamiento del navegador.
  • Solo funciona en www.youtube.com. En cualquier otra web se detiene antes de hacer nada.
  • Corto y legible. 133 líneas comentadas, sin minificar ni ofuscar.
  • Pregunta antes de cambiar nada. Un recuadro en la página muestra lo que ha encontrado y espera tu OK. Puedes pararlo cuando quieras.
  • El mismo código para todos. SHA-256 de la versión por defecto: d8c35a21c2862426…
Compruébalo tú mismo en 30 segundos
  1. Léelo: todas las líneas están arriba, con comentarios.
  2. Busca en el código fetch, XMLHttpRequest, cookie, localStorage o eval. No aparece ninguna.
  3. Abre la pestaña Red (Network) antes de ejecutarlo: solo verás peticiones a www.youtube.com.

Ten en cuenta: esto no se puede deshacer en bloque. El script siempre muestra cuántos hay y pregunta antes de empezar. Deja la pestaña abierta hasta que el recuadro diga «Hecho».

¿Te ha funcionado?

Cómo usarlo

  1. Abre tus suscripciones con tu sesión iniciada.
  2. Abre la consola: F12 o Ctrl+Mayús+J (Cmd+Opción+J en Mac). Si Chrome te lo pide, escribe permitir pegar (o allow pasting si lo tienes en inglés) y pulsa Enter.
  3. Elige las opciones, copia el script, pégalo en la consola y pulsa Enter. Un recuadro te dice cuántos ha encontrado y espera tu confirmación antes de empezar. Puedes pulsar Parar cuando quieras.

Antes de empezar

Si quieres guardar la lista, expórtala primero con el exportador de suscripciones. YouTube no avisa a los canales cuando te das de baja.

Preguntas frecuentes

¿Se enteran los canales de que me he dado de baja?

No. YouTube no avisa a los creadores cuando alguien anula su suscripción.

¿Puedo conservar algunos canales?

Sí. Escribe sus nombres o @usuarios en «Canales que conservar» y el script se los salta.

¿Exporto antes mis suscripciones?

Es buena idea. Usa el exportador de suscripciones para guardar una copia en CSV u OPML antes de empezar.

Más herramientas gratis

Limpiar

Exportar y hacer copia