Descargar la transcripción de un vídeo de YouTube (texto, SRT o CSV)

Consigue la transcripción completa de cualquier vídeo de YouTube en segundos: en texto para pegarlo en ChatGPT, Claude o Gemini, con marcas de tiempo, como subtítulos SRT o en una hoja de cálculo. Gratis, sin clave de API y sin extensiones.

Abre el vídeo (no hace falta iniciar sesión) y ejecuta el script: abre él solo el panel de la transcripción.

export-transcript.js · 128 líneaspégalo en la consola (F12) de www.youtube.com
// Responsive Muse · YouTube Transcript Downloader · v1.0 · 2026-10-23
// Saves the transcript of a YouTube video as plain text (handy to paste into ChatGPT, Claude or
// Gemini), text with timestamps, SRT subtitles or CSV. Works on any video that has a transcript
// (most do, auto-generated or not), in the language YouTube shows it. It opens the transcript
// panel itself. It makes no network requests of its own and never reads cookies, passwords or tokens.
(async () => {
  const TOOL = 'Descargar transcripción de YouTube';
  const FORMAT = 'txt';        // 'txt' (plain text), 'timestamps' (text with [mm:ss]), 'srt' (subtitles) or 'csv'

  const video = new URLSearchParams(location.search).get('v');
  if (location.hostname !== 'www.youtube.com' || !video) {
    alert('Abre primero el vídeo de YouTube, por ejemplo:\nhttps://www.youtube.com/watch?v=zjkBMFhNj_g');
    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(); },
    };
  })();
  // Offer the result as a downloaded file or as clipboard text (a real click, so it always works)
  const deliver = (summary, body, file) => {
    const save = () => {
      const a = document.createElement('a');
      a.href = URL.createObjectURL(new Blob([/\.csv$/.test(file) ? '\ufeff' + body : body], { type: 'text/plain;charset=utf-8' }));
      a.download = file;
      a.click();
      setTimeout(() => URL.revokeObjectURL(a.href), 5000);
      panel.text(`${summary}\nGuardado como ${file} (mira tu carpeta de Descargas).`);
    };
    const copy = () => navigator.clipboard.writeText(body)
      .then(() => panel.text(`${summary}\nCopiado. Pégalo en una hoja de cálculo o en una nota.`))
      .catch(() => panel.text(`${summary}\nEl navegador ha bloqueado el portapapeles: usa Descargar.`));
    panel.actions(summary, [['Cerrar', false, () => panel.close()], ['Copiar', false, copy], ['Descargar', true, save]]);
  };
  const sleep = ms => new Promise(r => setTimeout(r, ms));
  const clean = s => (s || '').replace(/\s+/g, ' ').trim();
  // New transcript panel (transcript-segment-view-model) and the old one (ytd-transcript-segment-renderer)
  const segments = () => document.querySelectorAll('transcript-segment-view-model, ytd-transcript-segment-renderer');

  // 1. Open the transcript panel (the "Show transcript" button in the description) and wait for it to fill
  document.querySelector('video')?.pause();
  if (!segments().length) {
    const open = document.querySelector('ytd-video-description-transcript-section-renderer button');
    if (!open) {
      panel.finish('Este vídeo no tiene transcripción (no hay botón «Mostrar transcripción» en la descripción). Prueba con otro vídeo.');
      return 0;
    }
    open.click();
  }
  panel.text('Abriendo la transcripción…');
  let n = 0;
  for (let i = 0, stable = 0; i < 40 && stable < 4; i++) {   // up to 20 s, until the count stops growing
    await sleep(500);
    const now = segments().length;
    stable = now && now === n ? stable + 1 : 0;
    n = now;
  }
  const rows = [...segments()].map(s => ({
    ts: clean((s.querySelector('[class$="SegmentViewModelTimestamp"], .segment-timestamp') || {}).textContent),
    text: clean((s.querySelector('.ytAttributedStringHost, .segment-text') || {}).textContent),
  })).filter(r => r.text);
  if (!rows.length) {
    panel.finish(n ? 'La transcripción está vacía o YouTube ha cambiado su diseño: avísanos en responsive-muse.com.'
      : 'La transcripción no se ha cargado. Recarga la página, espera a que empiece el vídeo y vuelve a ejecutar el script.');
    return 0;
  }

  // 2. Build the file and offer it
  const secs = ts => ts.split(':').reduce((a, v) => a * 60 + Number(v), 0);
  const srtTime = s => {
    const h = Math.floor(s / 3600), m = Math.floor(s / 60) % 60, sec = Math.floor(s % 60), ms = Math.round((s % 1) * 1000);
    return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')},${String(ms).padStart(3, '0')}`;
  };
  const end = document.querySelector('video')?.duration || secs(rows[rows.length - 1].ts) + 5;
  const cell = v => '"' + String(v).replace(/"/g, '""') + '"';
  const body = {
    txt: rows.map(r => r.text).join(' ').replace(/ {2,}/g, ' '),
    timestamps: rows.map(r => `[${r.ts}] ${r.text}`).join('\n'),
    srt: rows.map((r, i) => `${i + 1}\n${srtTime(secs(r.ts))} --> ${srtTime(i + 1 < rows.length ? secs(rows[i + 1].ts) : end)}\n${r.text}\n`).join('\n'),
    csv: ['Inicio,Segundos,Texto', ...rows.map(r => [r.ts, secs(r.ts), r.text].map(cell).join(','))].join('\n'),
  }[FORMAT] || rows.map(r => r.text).join(' ');
  const title = clean(document.querySelector('h1.ytd-watch-metadata, #title h1')?.textContent) || video;
  const ext = { txt: 'txt', timestamps: 'txt', srt: 'srt', csv: 'csv' }[FORMAT] || 'txt';
  const name = ('transcripcion-' + title).slice(0, 80).replace(/[\\/:*?"<>|]+/g, '_');
  const words = rows.map(r => r.text).join(' ').split(/\s+/).length;
  deliver(`Transcripción lista: ${rows.length} líneas, unas ${words.toLocaleString('es-ES')} palabras (hasta ${rows[rows.length - 1].ts}).`, body, `${name}.${ext}`);
  return rows.length;
})();

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 23 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. 128 líneas comentadas, sin minificar ni ofuscar.
  • Muestra su progreso en la página. Un pequeño recuadro te dice qué está haciendo y al final te ofrece Descargar o Copiar.
  • El mismo código para todos. SHA-256 de la versión por defecto: 2d604841b59e9c01…
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.
¿Te ha funcionado?

Cómo usarlo

  1. Abre el vídeo en youtube.com. No hace falta iniciar sesión.
  2. Abre la consola: F12 o Ctrl+Mayús+J (Cmd+Opción+J en Mac). Si Chrome te lo pide, escribe permitir pegar y pulsa Enter.
  3. Copia el script, pégalo en la consola y pulsa Enter. Pausa el vídeo, abre la transcripción y a los pocos segundos te ofrece el archivo.

¿Qué formato elijo?

  • Texto: un bloque de texto sin tiempos. Lo mejor para resumir un vídeo con IA, traducirlo o leerlo.
  • Texto con marcas de tiempo: cada línea empieza por [mm:ss], práctico para notas y citas.
  • Subtítulos SRT: un archivo de subtítulos para un reproductor o editor de vídeo.
  • CSV: inicio, segundos y texto en columnas, para analizarlo en Excel o Sheets.

Resumir un vídeo de YouTube con ChatGPT o Claude

Descarga el texto, pégalo en el chat y pide, por ejemplo: «Resume esta charla en 10 puntos y enumera las afirmaciones principales con su minuto» (para eso, usa el formato con marcas de tiempo). Un vídeo de una hora son unas 10.000 palabras.

Preguntas frecuentes

¿Qué vídeos tienen transcripción?

Casi todos: YouTube la genera sola en muchos idiomas y los creadores pueden subir la suya. Si en la descripción no aparece el botón «Mostrar transcripción», el vídeo no tiene.

¿Puedo resumir un vídeo con IA?

Sí. Descarga el texto, pégalo en ChatGPT, Claude o Gemini y pide un resumen, las ideas clave o citas. Una charla de una hora son unas 10.000 palabras y cabe en cualquiera de ellos.

¿En qué idioma sale la transcripción?

En el que muestra YouTube en el panel de la transcripción. Si el vídeo tiene varios, elige allí el idioma y vuelve a ejecutar el script.

¿Es gratis y seguro?

Sí. Se ejecuta en tu propia pestaña de YouTube, no necesita clave de API ni cuenta y no envía nada a ningún sitio.

Más herramientas para YouTube