82 OSS
Documentation

just-ytv0.1.2

Typed YouTube data, without an API key

A TypeScript SDK for public YouTube data. Search, videos, channels, transcripts, and suggestions come back as stable typed objects, read from the same endpoints YouTube’s own clients use.

bun add just-yt

Fetch a video with one call

Pass an ID or any watch, youtu.be, /shorts/, /embed/, or /live/ URL. The client opens one Innertube session on its first request and reuses it, so create it once and keep it for the life of your app.

import { YouTube } from 'just-yt';

const yt = new YouTube();
const video = await yt.video('jNQXAC9IVRw');

video.title; // 'Me at the zoo'
video.viewCount; // 403522943
video.channel.handle; // '@jawed'

Search with familiar filters

Filter by type, upload date, duration, sort order, and features such as HD or subtitles. One results page comes back by default; set a limit and the SDK follows YouTube’s continuation tokens for you.

const page = await yt.search('effect ts', {
  type: 'video',
  uploadDate: 'week',
  sortBy: 'view_count',
  features: ['hd', 'subtitles'],
});

page.results[0].title; // 'Stop the agent slop with Effect | Maxwell Brown'
page.results[0].viewCount; // 1396

const many = await yt.search('effect ts', {
  limit: 100,
});

Transcripts, plain or timed

Captions arrive as one normalized paragraph—the shape you want for a summary or an embedding. Ask for segments instead and each line carries its start and end in seconds.

const text = await yt.transcript(id, {
  language: 'en',
});

text.title; // 'Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)'
text.data; // "[♪♪♪] ♪ We're no strangers to love ♪ ♪ You know the rules and so do I ♪…"

const timed = await yt.transcript(id, {
  segmented: true,
});

timed.data[0]; // { start: 1.36, end: 3.04, text: '[♪♪♪]' }

Every failure is tagged

Narrow rejections with instanceof, or switch on _tag. ExtractionError is the one to watch: it means YouTube reshaped a response, and its path field points at where extraction gave up.

import { NotFoundError } from 'just-yt';

try {
  await yt.transcript(id, { language: 'en' });
} catch (error) {
  if (error instanceof NotFoundError) {
    return null;
  }

  throw error;
}

The same SDK as an Effect service

Promises are the default and need nothing else installed. When you want errors in the type system, together with retries, timeouts, and search as a Stream, the service exposes the same API.

import { Effect } from 'effect';
import { YouTubeApi, layer } from 'just-yt';

const program = Effect.gen(function* () {
  const yt = yield* YouTubeApi;
  return yield* yt.video('dQw4w9WgXcQ');
});

Effect.runPromise(
  program.pipe(Effect.provide(layer())),
);

Install it and read something

Public metadata only: no sign-in, no downloads, and no private or members-only content. Node 18 or newer, Bun, Deno, and modern edge runtimes are supported.

Get started View on GitHub