> ## Content Index
> Fetch the complete content index at: https://roundproxies.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# How to use Pytubefix: Download YouTube Videos with python
- URL: https://roundproxies.com/blog/pytubefix/
- Published: 2025-12-14T19:07:29.000Z
- Updated: 2026-09-23T13:04:22.000Z
- Description: Learn how to use pytubefix to download YouTube videos, audio, playlists, captions, and more with a maintained pytube fork.
- Author: Marius Bernard
- Tags: Video Download Automation, Web Scraping, #dated-693e027c26f439f88a95a554, YouTube Web Scraping

Pytubefix is the actively maintained fork of pytube, and it is the fastest way to download YouTube videos in Python: point it at a YouTube video URL, pick a stream, call download. It carries the fixes pytube stopped shipping when YouTube changed its player and cipher logic, and adds things pytube never had, including playlist and channel objects, search, chapters, caption tracks in SRT, PO token handling, and OAuth.

This guide covers installing the library, reading video metadata such as title, length, and thumbnail URL, choosing between progressive and DASH streams, downloading audio only, iterating over playlists and channels, saving captions, and the parts people usually hit last: proxies, output paths, progress and completion callbacks, and error handling.

One caveat before you install. Pytubefix is no longer dependency-free. Releases from the 10.9 line onward pull in **aiohttp** and **nodejs-wheel-binaries**, the latter bundling a Node.js runtime for JavaScript and cipher work. That changes install size and matters if you build slim containers or install offline.

**Pin your version and test playlist code separately.** On 10.9.0 there is a reported regression where a playlist reports the correct length while its videos and video\_urls lists come back empty, which breaks the standard loop-over-a-playlist pattern shown later in this guide.

## What is Pytubefix?

Pytubefix is a lightweight Python library for downloading YouTube videos, and it is the actively maintained fork of pytube. If you already have code written against pytube, you can swap the import and carry on: same `YouTube` object, same stream queries, same `download()` call. The difference is upkeep. YouTube changes its internal API and its signature ciphers regularly, and pytubefix ships patches for those breakages instead of leaving your script dead.

What comes in the box when you use pytubefix to download a YouTube video in Python:

- Progressive streams (video and audio muxed into one MP4) and DASH streams (separate, higher quality video and audio tracks)
- Progress and completion callbacks, so you can render a progress bar while a chunk downloads or kick off post-processing once the file lands
- Caption tracks, exportable to `.srt`
- Metadata without downloading a byte: title, author, length, publish date, thumbnail URL, chapters, keywords
- `Playlist`, `Channel` and `Search` objects for bulk work, plus OAuth for age-restricted videos
- A command-line utility, for the times you don't want to write a script at all

One claim to retire before you install: pytubefix was long described as dependency-free, and that stopped being accurate. Recent releases from 10.9.0 onward declare `aiohttp` and `nodejs-wheel-binaries` as requirements, the second of which bundles a Node.js runtime for the JavaScript and cipher work. Budget for it if you build slim containers or install on machines without network access.

Pin the version you tested against, too. Development is fast and regressions do reach PyPI: a report against 10.9.0 has `Playlist.length` returning the correct video count while `Playlist.videos` and `video_urls` come back empty, which quietly breaks playlist scripts that look like they ran fine.

## Installing Pytubefix

Installing pytubefix takes just one command. Open your terminal and run:

```bash
pip install pytubefix

```

Verify the installation by checking the version:

```bash
pip show pytubefix

```

You should see output showing version 10.3.6 or later. The library requires Python 3.7 or higher.

For development installations from source, you can clone the repository:

```bash
git clone https://github.com/JuanBindez/pytubefix.git
cd pytubefix
pip install -e .

```

## Downloading Your First Video

Downloading a YouTube video takes just a few lines of code. Start by importing the YouTube class and creating an instance with your video URL.

```python
from pytubefix import YouTube

# Create a YouTube object
yt = YouTube('https://www.youtube.com/watch?v=dQw4w9WgXcQ')

# Print video title
print(yt.title)

# Get highest resolution stream
stream = yt.streams.get_highest_resolution()

# Download the video
stream.download()

```

This code downloads the video in the highest available resolution to your current directory.

Let's break down what each line does:

- `YouTube()` creates an object representing the video
- `yt.title` accesses the video's metadata
- `streams.get_highest_resolution()` finds the best quality stream
- `download()` saves the file to disk

## Adding Progress Tracking

For larger videos, you'll want to see download progress. Pytubefix provides a built-in progress callback that displays a progress bar in your terminal.

```python
from pytubefix import YouTube
from pytubefix.cli import on_progress

url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

# Add the progress callback
yt = YouTube(url, on_progress_callback=on_progress)
print(f"Downloading: {yt.title}")

stream = yt.streams.get_highest_resolution()
stream.download()

print("Download complete!")

```

The `on_progress` callback displays percentage completion as chunks download. This visual feedback is essential when downloading long videos.

You can also create custom progress callbacks:

```python
def my_progress_callback(stream, chunk, bytes_remaining):
    total_size = stream.filesize
    bytes_downloaded = total_size - bytes_remaining
    percentage = (bytes_downloaded / total_size) * 100
    print(f"\rDownloaded: {percentage:.1f}%", end="")

yt = YouTube(url, on_progress_callback=my_progress_callback)

```

This gives you full control over how progress appears in your application.

## Downloading Audio Only

Extracting audio from YouTube videos is common for podcasts, music, and background listening. Pytubefix makes audio-only downloads straightforward.

```python
from pytubefix import YouTube
from pytubefix.cli import on_progress

url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

yt = YouTube(url, on_progress_callback=on_progress)
print(f"Extracting audio from: {yt.title}")

# Get audio-only stream
audio_stream = yt.streams.get_audio_only()

# Download as m4a
audio_stream.download()

```

The `get_audio_only()` method returns the highest quality audio stream without video. Files save in M4A format by default.

To download audio as MP3, you have two options. First, use the built-in mp3 parameter:

```python
audio_stream = yt.streams.get_audio_only()
audio_stream.download(mp3=True)

```

Alternatively, convert using an external library like moviepy:

```python
from moviepy.editor import VideoFileClip
import os

# Download audio
audio_path = audio_stream.download()

# Convert to MP3
video = VideoFileClip(audio_path)
video.audio.write_audiofile(audio_path.replace('.m4a', '.mp3'))

# Remove original m4a file
os.remove(audio_path)

```

## Working with Streams and Quality Selection

YouTube provides multiple streams for each video at different resolutions and formats. Understanding stream types helps you download exactly what you need.

### Listing Available Streams

```python
from pytubefix import YouTube

yt = YouTube('https://www.youtube.com/watch?v=dQw4w9WgXcQ')

# View all available streams
print(yt.streams)

```

This prints a list of Stream objects showing resolution, codec, and file type. You'll see progressive streams (video+audio combined) and adaptive streams (separate video and audio).

### Filtering Streams

Filter streams by specific attributes:

```python
# Get only MP4 streams
mp4_streams = yt.streams.filter(file_extension='mp4')

# Get only progressive streams (video + audio)
progressive = yt.streams.filter(progressive=True)

# Get only 1080p streams
hd_streams = yt.streams.filter(res='1080p')

# Get only audio streams
audio_only = yt.streams.filter(only_audio=True)

# Combine filters
result = yt.streams.filter(
    progressive=True,
    file_extension='mp4'
).order_by('resolution').desc()

```

### Progressive vs DASH Streams

Progressive streams contain both video and audio in one file. They're limited to 720p maximum but download in a single request.

DASH (Dynamic Adaptive Streaming over HTTP) streams separate video and audio. They offer higher resolutions like 1080p, 4K, and 8K but require downloading two files and merging them.

```python
# Get highest resolution progressive stream (max 720p)
stream = yt.streams.get_highest_resolution()

# Get adaptive streams for higher quality
video_stream = yt.streams.filter(
    adaptive=True, 
    file_extension='mp4',
    only_video=True
).order_by('resolution').desc().first()

audio_stream = yt.streams.filter(
    adaptive=True, 
    only_audio=True
).first()

```

For 1080p+ downloads, you need to merge video and audio using ffmpeg:

```bash
ffmpeg -i video.mp4 -i audio.m4a -c:v copy -c:a aac output.mp4

```

## Downloading Entire Playlists

Pytubefix handles YouTube playlists seamlessly. The Playlist class iterates through all videos in a playlist.

```python
from pytubefix import Playlist
from pytubefix.cli import on_progress

playlist_url = "https://www.youtube.com/playlist?list=PLxxxxxx"

pl = Playlist(playlist_url)

print(f"Playlist: {pl.title}")
print(f"Total videos: {len(pl.video_urls)}")

# Download all videos
for video in pl.videos:
    print(f"\nDownloading: {video.title}")
    stream = video.streams.get_highest_resolution()
    stream.download()

```

For audio-only playlist downloads:

```python
for video in pl.videos:
    audio = video.streams.get_audio_only()
    audio.download(output_path="playlist_audio")

```

You can access playlist metadata:

```python
print(f"Owner: {pl.owner}")
print(f"Views: {pl.views}")
print(f"Last updated: {pl.last_updated}")

```

## Downloading Channel Videos

Download every video from a YouTube channel using the Channel class:

```python
from pytubefix import Channel

channel_url = "https://www.youtube.com/@ProgrammingKnowledge"

c = Channel(channel_url)

print(f"Channel: {c.channel_name}")
print(f"Total videos: {len(c.video_urls)}")

# Download all channel videos
for video in c.videos:
    print(f"Downloading: {video.title}")
    stream = video.streams.get_highest_resolution()
    stream.download(output_path="channel_videos")

```

This approach works for any public YouTube channel. Be mindful of storage space when downloading entire channels.

## Extracting and Saving Captions

YouTube videos often include captions that pytubefix can extract and save:

```python
from pytubefix import YouTube

yt = YouTube('https://www.youtube.com/watch?v=2lAe1cqCOXo')

# View available caption tracks
print(yt.captions)

```

The output shows language codes like `a.en` (auto-generated English) or `en` (manual English captions).

### Generating SRT Subtitles

```python
# Get English captions
caption = yt.captions['a.en']

# Generate SRT format
srt_content = caption.generate_srt_captions()
print(srt_content)

```

### Saving Captions to File

```python
# Save to text file
caption.save_captions("video_captions.txt")

```

Captions save in SRT format, compatible with most video players and subtitle editors.

## Using OAuth for Age-Restricted Content

Some YouTube videos require authentication to access. Pytubefix supports OAuth to handle age-restricted and members-only content.

```python
from pytubefix import YouTube
from pytubefix.cli import on_progress

url = "https://www.youtube.com/watch?v=restricted_video_id"

yt = YouTube(
    url,
    use_oauth=True,
    allow_oauth_cache=True,
    on_progress_callback=on_progress
)

stream = yt.streams.get_highest_resolution()
stream.download()

```

When you run this code the first time, it opens a browser window asking you to sign in to Google. After authentication, your credentials are cached locally, so future runs skip the login step.

The `allow_oauth_cache=True` parameter stores your token for subsequent downloads. This is essential for automated scripts.

## Specifying Output Directory and Filename

Control where files are saved and what they're named:

```python
from pytubefix import YouTube

yt = YouTube('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
stream = yt.streams.get_highest_resolution()

# Custom output directory
stream.download(output_path="/path/to/downloads")

# Custom filename
stream.download(filename="my_video.mp4")

# Both directory and filename
stream.download(
    output_path="/path/to/downloads",
    filename="custom_name.mp4"
)

```

If the output directory doesn't exist, pytubefix creates it automatically.

## Searching YouTube Videos

Find videos without leaving your script using the Search class:

```python
from pytubefix import Search

results = Search('Python tutorial')

for video in results.videos:
    print(f"Title: {video.title}")
    print(f"URL: {video.watch_url}")
    print(f"Duration: {video.length} seconds")
    print("---")

```

### Using Search Filters

Narrow results using the Filter class:

```python
from pytubefix.contrib.search import Search, Filter

filters = (
    Filter.create()
    .upload_date(Filter.UploadDate.TODAY)
    .type(Filter.Type.VIDEO)
    .duration(Filter.Duration.UNDER_4_MINUTES)
    .feature([Filter.Features.CREATIVE_COMMONS, Filter.Features._4K])
    .sort_by(Filter.SortBy.UPLOAD_DATE)
)

s = Search('programming', filters=filters)

for video in s.videos:
    print(video.watch_url)

```

Available filter options include upload date, video type, duration, features, and sort order.

## Async Downloads with AsyncYouTube

For applications requiring non-blocking downloads, pytubefix provides an async interface:

```python
import asyncio
from pytubefix import AsyncYouTube

async def main():
    url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    
    yt = AsyncYouTube(url, use_oauth=True, allow_oauth_cache=True)
    
    # Fetch streams asynchronously
    streams = await yt.streams()
    
    print("Available Streams:")
    for stream in streams:
        print(stream)
    
    # Get video metadata asynchronously
    title = await yt.title()
    views = await yt.views()
    
    print(f"Title: {title}")
    print(f"Views: {views}")

if __name__ == '__main__':
    asyncio.run(main())

```

### Async Download with Progress Callbacks

```python
import asyncio
from pytubefix import AsyncYouTube

async def main():
    url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    
    def on_progress(stream, chunk, bytes_remaining):
        total = stream.filesize
        percent = (1 - bytes_remaining / total) * 100
        print(f"\rProgress: {percent:.2f}%", end="")
    
    def on_complete(stream, file_path):
        print(f"\nDownload complete: {file_path}")
    
    yt = AsyncYouTube(url, use_oauth=True, allow_oauth_cache=True)
    
    yt.register_on_progress_callback(on_progress)
    yt.register_on_complete_callback(on_complete)
    
    # Get stream by itag (18 = 360p MP4)
    stream = await yt.get_stream_by_itag(18)
    
    print(f"Downloading: {await yt.title()}")
    stream.download(filename="async_video.mp4")

if __name__ == '__main__':
    asyncio.run(main())

```

The async interface is ideal for GUI applications or web servers where blocking operations cause poor user experience.

## Using Proxies for Scale

When downloading many videos, YouTube may rate limit your IP address. Using proxies helps distribute requests across multiple IPs.

```python
from pytubefix import YouTube

proxies = {
    'http': 'http://proxy_ip:port',
    'https': 'https://proxy_ip:port'
}

yt = YouTube(
    'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
    proxies=proxies
)

stream = yt.streams.get_highest_resolution()
stream.download()

```

For residential proxies that appear more like regular users, services like Roundproxies.com offer rotating residential, datacenter, ISP, and mobile proxies. These reduce the chance of detection when running automated downloads.

Rotate through multiple proxies for high-volume operations:

```python
import random

proxy_list = [
    {'http': 'http://proxy1:port', 'https': 'https://proxy1:port'},
    {'http': 'http://proxy2:port', 'https': 'https://proxy2:port'},
    {'http': 'http://proxy3:port', 'https': 'https://proxy3:port'},
]

def download_with_rotation(url):
    proxy = random.choice(proxy_list)
    yt = YouTube(url, proxies=proxy)
    return yt.streams.get_highest_resolution().download()

```

## Accessing Video Chapters and Key Moments

YouTube videos with chapters display timestamps in the progress bar. Pytubefix can extract this data:

```python
import asyncio
from pytubefix import AsyncYouTube

async def main():
    url = "https://www.youtube.com/watch?v=video_with_chapters"
    
    yt = AsyncYouTube(url)
    
    chapters = await yt.chapters()
    key_moments = await yt.key_moments()
    
    print("Chapters:", chapters)
    print("Key Moments:", key_moments)

asyncio.run(main())

```

Chapter data includes timestamps and titles, useful for splitting long videos into segments.

## Error Handling Best Practices

Production code needs proper error handling for network issues, unavailable videos, and other failures:

```python
from pytubefix import YouTube
from pytubefix.exceptions import (
    VideoUnavailable,
    RegexMatchError,
    AgeRestrictedError
)

def safe_download(url, output_path="."):
    try:
        yt = YouTube(url)
        stream = yt.streams.get_highest_resolution()
        stream.download(output_path=output_path)
        return True
        
    except VideoUnavailable:
        print(f"Video unavailable: {url}")
        return False
        
    except AgeRestrictedError:
        print("Age restricted - try OAuth authentication")
        return False
        
    except RegexMatchError:
        print("Failed to parse video data - YouTube may have changed")
        return False
        
    except Exception as e:
        print(f"Unexpected error: {e}")
        return False

```

Always wrap download operations in try-except blocks. YouTube frequently changes its internal APIs, which can break parsing temporarily.

## Command Line Interface

Pytubefix includes a CLI for quick downloads without writing code:

```bash
# Download video
python -m pytubefix https://www.youtube.com/watch?v=dQw4w9WgXcQ

# Download audio only
python -m pytubefix https://www.youtube.com/watch?v=dQw4w9WgXcQ --audio

# Specify output directory
python -m pytubefix https://www.youtube.com/watch?v=dQw4w9WgXcQ -o /downloads

```

The CLI is handy for one-off downloads or shell scripts.

## Migrating from Pytube to Pytubefix

Pytube users can switch to pytubefix with minimal changes. The API is nearly identical:

**Before (pytube):**

```python
from pytube import YouTube
yt = YouTube('url')

```

**After (pytubefix):**

```python
from pytubefix import YouTube
yt = YouTube('url')

```

Just change the import statement. All method names and parameters remain the same.

Pytubefix has several advantages over pytube:

- Active maintenance with regular updates
- Faster bug fixes when YouTube changes
- Additional features like async support
- Better OAuth handling for restricted content

## Common Issues and Solutions

**"Video unavailable" errors**: The video may be private, deleted, or region-locked. Try using a proxy from a different country.

**Download stalls or fails**: YouTube may be throttling. Add a delay between downloads:

```python
import time

for url in video_urls:
    download_video(url)
    time.sleep(2)  # Wait 2 seconds between downloads

```

**OAuth token expires**: Delete the cached token file and re-authenticate:

```bash
rm ~/.cache/pytubefix/tokens.json

```

**Cipher errors**: Update pytubefix to the latest version:

```bash
pip install --upgrade pytubefix

```

## Batch Downloading Multiple Videos

Download multiple videos efficiently by processing a list of URLs:

```python
from pytubefix import YouTube
from pytubefix.cli import on_progress
import time

video_urls = [
    "https://www.youtube.com/watch?v=video1",
    "https://www.youtube.com/watch?v=video2",
    "https://www.youtube.com/watch?v=video3",
]

def batch_download(urls, output_path="downloads"):
    successful = 0
    failed = []
    
    for i, url in enumerate(urls):
        try:
            print(f"\n[{i+1}/{len(urls)}] Processing...")
            
            yt = YouTube(url, on_progress_callback=on_progress)
            print(f"Title: {yt.title}")
            
            stream = yt.streams.get_highest_resolution()
            stream.download(output_path=output_path)
            
            successful += 1
            time.sleep(1)  # Rate limiting
            
        except Exception as e:
            print(f"Failed: {e}")
            failed.append(url)
    
    print(f"\nComplete: {successful} downloaded, {len(failed)} failed")
    return failed

# Run batch download
failed_urls = batch_download(video_urls)

```

This pattern handles failures gracefully and provides progress feedback for each video.

## Getting Video Metadata

Access rich metadata without downloading the video itself:

```python
from pytubefix import YouTube

yt = YouTube('https://www.youtube.com/watch?v=dQw4w9WgXcQ')

# Basic metadata
print(f"Title: {yt.title}")
print(f"Author: {yt.author}")
print(f"Length: {yt.length} seconds")
print(f"Views: {yt.views}")
print(f"Rating: {yt.rating}")
print(f"Description: {yt.description[:200]}...")

# Thumbnail URLs
print(f"Thumbnail: {yt.thumbnail_url}")

# Publish date
print(f"Published: {yt.publish_date}")

# Keywords/tags
print(f"Keywords: {yt.keywords}")

```

This metadata is useful for building video catalogs, checking content before downloading, or displaying information in applications.

## Frequently Asked Questions

### Is pytubefix legal to use?

Pytubefix is a legal Python library. However, downloading copyrighted content without permission may violate YouTube's Terms of Service and copyright laws. Use the library responsibly for content you have rights to download, like your own videos or Creative Commons licensed content.

### What's the difference between pytubefix and pytube?

Pytubefix is a maintained fork of pytube. When pytube stopped receiving updates and broke due to YouTube changes, pytubefix continued development. It fixes bugs faster, adds new features like async support, and maintains compatibility with YouTube's evolving API.

### Why does my download fail with cipher errors?

YouTube regularly changes how it protects video streams. When this happens, pytubefix needs an update to handle new encryption methods. Run `pip install --upgrade pytubefix` to get the latest version with current cipher fixes.

### Can I download 4K videos?

Yes, but 4K streams are DASH adaptive streams. You need to download video and audio separately, then merge them using ffmpeg. Progressive streams max out at 720p.

### How do I download private videos?

Private videos require OAuth authentication. Set `use_oauth=True` when creating the YouTube object and sign in with an account that has access to the video. The library caches your credentials for future downloads.

### Does pytubefix work with YouTube Shorts?

Yes, YouTube Shorts work the same as regular videos. Use the Shorts URL directly with the YouTube class. The download process is identical.

## Conclusion

Pytubefix provides a reliable way to download YouTube content programmatically. From simple single-video downloads to complex async operations with proxy rotation, the library handles it all.

Start with basic downloads, then add progress tracking and error handling. For production applications, implement OAuth authentication and proxy support to handle edge cases.

The library's active maintenance means bugs get fixed quickly when YouTube changes. Check the GitHub repository for updates and community discussions when you encounter issues.

Keep pytubefix updated regularly to ensure compatibility with YouTube's latest changes. The developer community actively monitors for breaking changes and releases fixes within days.