Package Exports
- ytdl-core-enhanced
- ytdl-core-enhanced/lib/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (ytdl-core-enhanced) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
ytdl-core-enhanced
Stable YouTube downloader using Android InnerTube client with automatic signature decoding.
Features
- ✅ Android InnerTube Client - Reliable format extraction using YouTube's official Android API
- ✅ Automatic Signature Decoding - Handles encrypted format URLs transparently
- ✅ Restricted Videos - Download age-restricted and region-locked videos with cookies
- ✅ Multi-threading - Fast parallel downloads with multiple connections
- ✅ 100% API Compatible - Drop-in replacement for ytdl-core
- ✅ Production Ready - Stable and tested with YouTube 2025
Installation
npm install ytdl-core-enhancedQuick Start
Basic Download
const ytdl = require('ytdl-core-enhanced');
const fs = require('fs');
ytdl('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
.pipe(fs.createWriteStream('video.mp4'));Download with Quality Selection
const ytdl = require('ytdl-core-enhanced');
const fs = require('fs');
// Highest quality
ytdl('VIDEO_URL', { quality: 'highest' })
.pipe(fs.createWriteStream('video.mp4'));
// Specific format (1080p video)
ytdl('VIDEO_URL', { quality: 137 })
.pipe(fs.createWriteStream('video-1080p.mp4'));
// Audio only
ytdl('VIDEO_URL', { filter: 'audioonly' })
.pipe(fs.createWriteStream('audio.m4a'));Get Video Info
const ytdl = require('ytdl-core-enhanced');
ytdl.getInfo('VIDEO_URL').then(info => {
console.log('Title:', info.videoDetails.title);
console.log('Author:', info.videoDetails.author.name);
console.log('Duration:', info.videoDetails.lengthSeconds, 'seconds');
console.log('Formats:', info.formats.length);
});Downloading Restricted Videos
For age-restricted, region-locked, or member-only videos, you need to provide YouTube cookies from a logged-in account.
Method 1: Using Cookie Editor Extension (Recommended)
Install Cookie-Editor extension for your browser:
Go to YouTube and log in to your account
Click the Cookie-Editor extension icon
Click "Export" → "Header String" (this copies cookie string to clipboard)
Use the cookie string in your code:
const ytdl = require('ytdl-core-enhanced');
const fs = require('fs');
const cookieString = 'PASTE_YOUR_COOKIE_STRING_HERE';
ytdl('VIDEO_URL', {
requestOptions: {
headers: {
'Cookie': cookieString
}
}
}).pipe(fs.createWriteStream('video.mp4'));Method 2: Save Cookie to File
const ytdl = require('ytdl-core-enhanced');
const fs = require('fs');
// Save your cookie string to a file
fs.writeFileSync('.youtube-cookies.txt', 'YOUR_COOKIE_STRING');
// Read and use it
const cookieString = fs.readFileSync('.youtube-cookies.txt', 'utf8');
ytdl('VIDEO_URL', {
requestOptions: {
headers: {
'Cookie': cookieString
}
}
}).pipe(fs.createWriteStream('video.mp4'));Important Cookie Notes
⚠️ Security Warning: Cookie strings contain your authentication tokens. Treat them like passwords:
- Never commit cookies to git repositories
- Add
.youtube-cookies.txtto your.gitignore - Regenerate cookies if accidentally exposed (logout and login again)
💡 Cookie Lifespan: YouTube cookies typically last 1-2 weeks. If downloads start failing with 403 errors, refresh your cookies.
API Reference
ytdl(url, [options])
Downloads a video from YouTube.
Parameters:
url(string): Video URL or video IDoptions(object): Download options
Options:
quality: Quality preference (default: 'highest')'highest'- Best quality'lowest'- Lowest quality'highestaudio'- Best audio quality'lowestaudio'- Lowest audio quality- Number (itag) - Specific format (e.g., 137 for 1080p)
filter: Format filter function or preset'audioonly'- Audio only'videoonly'- Video only (no audio)'audioandvideo'- Combined video+audio- Function - Custom filter
(format) => boolean
requestOptions: HTTP request optionsheaders: Custom headers (e.g., cookies)
Returns: ReadableStream
Example:
ytdl('dQw4w9WgXcQ', {
quality: 'highest',
filter: 'audioandvideo',
requestOptions: {
headers: {
'Cookie': cookieString
}
}
}).pipe(fs.createWriteStream('video.mp4'));ytdl.getInfo(url, [options])
Gets video information without downloading.
Parameters:
url(string): Video URL or video IDoptions(object): Options (same as ytdl)
Returns: Promise
Response Object:
{
videoDetails: {
title: string,
author: { name: string },
lengthSeconds: number,
viewCount: number,
...
},
formats: [
{
itag: number,
url: string,
qualityLabel: string,
container: string,
hasVideo: boolean,
hasAudio: boolean,
...
}
]
}Common Format ITAGs
Video + Audio (Progressive)
- 18: 360p MP4
- 22: 720p MP4 (not always available)
Video Only (Adaptive)
- 137: 1080p MP4
- 136: 720p MP4
- 135: 480p MP4
- 134: 360p MP4
Audio Only (Adaptive)
- 139: 48kbps M4A (lowest)
- 140: 128kbps M4A (medium)
- 251: 160kbps WEBM (highest)
Events
The download stream emits standard Node.js stream events:
const video = ytdl('VIDEO_URL');
video.on('info', (info, format) => {
console.log('Downloading:', info.videoDetails.title);
console.log('Format:', format.qualityLabel);
});
video.on('data', (chunk) => {
console.log('Received', chunk.length, 'bytes');
});
video.on('end', () => {
console.log('Download complete!');
});
video.on('error', (error) => {
console.error('Error:', error.message);
});
video.pipe(fs.createWriteStream('video.mp4'));Troubleshooting
403 Forbidden Error
Problem: Download fails with HTTP 403 error
Solutions:
- Add cookies from a logged-in YouTube account (see "Downloading Restricted Videos")
- Check if video is region-locked or requires login
- Refresh your cookies if they expired
Format Not Found
Problem: Requested format/quality not available
Solution: Check available formats first:
ytdl.getInfo('VIDEO_URL').then(info => {
console.log('Available formats:');
info.formats.forEach(format => {
console.log(`${format.itag}: ${format.qualityLabel} (${format.container})`);
});
});Video Unavailable
Problem: "Video is unavailable" error
Possible Reasons:
- Video is private or deleted
- Video is region-locked (try with cookies from matching region)
- Video is live stream that ended
- Video is members-only (requires membership cookies)
Advanced Usage
Custom Filter Function
ytdl('VIDEO_URL', {
filter: format => {
return format.container === 'mp4' &&
format.hasAudio &&
format.qualityLabel === '720p';
}
}).pipe(fs.createWriteStream('video.mp4'));Download Progress Tracking
const ytdl = require('ytdl-core-enhanced');
const fs = require('fs');
ytdl.getInfo('VIDEO_URL').then(info => {
const format = ytdl.chooseFormat(info.formats, { quality: 'highest' });
const video = ytdl.downloadFromInfo(info, { format });
let downloaded = 0;
const total = parseInt(format.contentLength);
video.on('data', chunk => {
downloaded += chunk.length;
const percent = ((downloaded / total) * 100).toFixed(2);
console.log(`Progress: ${percent}%`);
});
video.pipe(fs.createWriteStream('video.mp4'));
});Differences from ytdl-core
This package is designed as a drop-in replacement for ytdl-core with these improvements:
✅ API Compatible - Same API as ytdl-core, just change the require statement ✅ More Reliable - Uses Android InnerTube client which works consistently ✅ Simpler - Removed complex multi-client fallback logic ✅ Cleaner - No browser automation or anti-bot detection needed
Migration from ytdl-core
// Before
const ytdl = require('ytdl-core');
// After
const ytdl = require('ytdl-core-enhanced');
// All your existing code works unchanged!Contributing
Issues and pull requests are welcome at GitHub.
License
MIT