HomeBlogTranscribePlansAPI Keys

Transcripción de YouTube en Node.js: fetch Nativo, Sin npm Install

Código de Node.js recuperando una transcripción de YouTube con la API fetch incorporada

No necesitas un paquete para esto. Obtener una transcripción de YouTube en Node.js es una llamada HTTPS, fetch ha sido global desde Node 18, y el punto final habla JSON plano. Todo en este post se ejecuta en un directorio vacío sin package.json — al final tendrás una función transcribe() que devuelve título, fecha de publicación, y texto de transcripción completo para cualquier URL de YouTube, con manejo de errores que no adivina.

El registro npm tiene una docena de raspadores de transcripciones, y comparten un destino: obtienen de YouTube usando la IP del servidor, y YouTube bloquea IPs del centro de datos. Una API alojada evita eso por completo.

Todo esto

const KEY = process.env.YT2TEXT_KEY;

async function transcribe(videoUrl, maxChars = 150000) {
  const qs = new URLSearchParams({ url: videoUrl, maxChars: String(maxChars) });
  const res = await fetch(`https://youtube2text.org/api/transcribe?${qs}`, {
    headers: { "x-api-key": KEY },
  });
  const body = await res.json();
  if (!res.ok) {
    const err = new Error(`${body.error.code}: ${body.error.message}`);
    err.code = body.error.code;
    err.retryAfterSeconds = body.error.retryAfterSeconds;
    throw err;
  }
  return body.result;
}

const t = await transcribe("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
console.log(`${t.title} — ${t.contentSize} chars`);
console.log(t.content.slice(0, 300));

Guarda como index.mjs (top-level await quiere ESM), ejecuta node index.mjs. El parámetro url toma cualquier variante de URL de YouTube o un id de video de 11 caracteres desnudo, y maxChars limita la longitud de la transcripción — 150000 es tanto el predeterminado como el máximo, así que recórtalo cuando el texto vaya a un prompt de LLM.

¿Sin clave aún? Agarra la demo:

curl https://youtube2text.org/api/demo-key

Devuelve {"success":true,"apiKey":"yt_..."}. Ten cuidado de que esté compartida entre todos los usuarios anónimos y limitada a 5 videos por mes por IP — una clave de prueba, no una de producción.

Los errores son JSON, así que trátales de esa manera

Cada fallo tiene un campo code estable. Los que vale la pena ramificar:

try {
  await transcribe("https://youtu.be/xxxxxxxxxxx");
} catch (err) {
  switch (err.code) {
    case "RATE_LIMIT_EXCEEDED":
      console.log(`Back off for ${err.retryAfterSeconds}s, then retry`);
      break;
    case "TRANSCRIPT_UNAVAILABLE":
      console.log("Video has no captions — nothing to fetch, skip it");
      break;
    case "VIDEO_NOT_FOUND":
    case "INVALID_URL":
      console.log("Bad input, fix the URL");
      break;
    default:
      throw err; // UNAUTHORIZED, YOUTUBE_ERROR — genuinely unexpected
  }
}

TRANSCRIPT_UNAVAILABLE es la limitación honesta de todo el enfoque: las transcripciones provienen de las pistas de subtítulos propios de YouTube, manual o generadas automáticamente, inglés preferido con alternativa a cualquier idioma que exista. Un video con subtítulos desactivados devuelve un 404 y no hay nada que reintentar. Mánéjalo como un caso normal, no una ruta de excepción.

TypeScript, si eso es lo tuyo

La forma de respuesta es estable, así que un par de interfaces te proporciona seguridad de tipo total sin dependencias:

interface TranscriptResult {
  videoId: string;
  title: string;
  pubDate: string;
  content: string;
  contentSize: number;
  truncated: boolean;
}

interface ApiError {
  code: string;
  message: string;
  status: number;
  retryAfterSeconds?: number;
}

Escribe body como { result: TranscriptResult } | { error: ApiError } y estrecha en res.ok. Sin any, sin casting.

Qué se conecta a esto

La mayoría de la gente que llama a esto desde Node está alimentando transcripciones a un modelo de lenguaje o un pipeline de contenido — convertir charlas en borradores se cubre en Video de YouTube a post de blog, y si tu marco de agente habla MCP puedes saltarte la capa HTTP por completo con el servidor MCP para Claude y Codex. El mismo punto final funciona idénticamente desde Python si tu stack es mixto — ver la versión de Python.

La referencia de parámetros y errores completa vive en youtube2text.org/api.md. Está escrita para que las máquinas la lean, que como efecto secundario la hace misericordiosamente corta para los humanos también.