# pytubefix: Python YouTube downloads with streams, playlists, and async access

> pytubefix is an MIT-licensed Python library for downloading YouTube videos and audio, with access to playlists, channels, captions, search, and metadata. Its synchronous stream model is easy to use, while `AsyncYouTube` still leaves the final `download()` call blocking.

**JuanBindez/pytubefix** — Python3 library for downloading YouTube Videos. 

- Repository: https://github.com/JuanBindez/pytubefix
- Website: https://pytubefix.readthedocs.io
- Stars: 1,647 · Forks: 211
- Language: Python
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/juanbindez-pytubefix

## What pytubefix handles for Python developers

pytubefix addresses the need to download YouTube material from Python without routing the request through a separate command in the application. Its intended audience is developers who need to select video or audio streams, collect metadata, process playlists and channels, retrieve captions, or integrate downloads into another program. The package metadata classifies it as a console-oriented library for developers and lists support for Python 3.7 through Python 3.14.

The public examples center on `YouTube`, `Playlist`, `Channel`, and `Search`. A `YouTube` instance exposes available streams and metadata such as title. `Playlist` represents a collection of videos. `Channel` provides channel information and an iterable collection of videos. `Search` accepts a query and returns results, with an optional filter object for upload date, content type, duration, features, and sort order.

This is more than a single function that saves one URL. However, its documented scope remains YouTube-specific. The repository description and README do not present it as a general media downloader for arbitrary websites. The `nodejs-wheel-binaries` dependency also shows that this is not merely a collection of basic HTTP helpers, although the README does not explain the library's internal use of those binaries.

## Stream selection and the pytubefix object model

The normal download path begins with a `YouTube` object and a URL. From that object, the caller accesses `yt.streams`, selects a stream through a method such as `get_highest_resolution()` or `get_audio_only()`, and calls `download()` on the selected stream. This structure exposes YouTube's available formats as objects rather than hiding format choice inside one fixed command.

The README distinguishes video and audio-only workflows. A video request selects the highest-resolution stream, while an audio request calls `get_audio_only()` and downloads the resulting stream. A specific asynchronous download instead uses `get_stream_by_itag(18)`, which the example identifies as a 360p MP4 progressive stream. This gives callers another route when selecting a known stream format instead of accepting the highest available resolution.

Progress reporting is attached when the object is created through `on_progress_callback=on_progress`. `on_progress` comes from `pytubefix.cli`. The asynchronous interface offers progress and completion callbacks through `register_on_progress_callback` and `register_on_complete_callback`, and the latter receives the saved file path.

Captions follow a related model. `yt.captions` presents available tracks, a track can be selected by key, and `generate_srt_captions()` returns SRT-formatted text while `save_captions()` writes to a file. Metadata access is broader in `AsyncYouTube`, whose documented methods include `title()`, `views()`, `likes()`, `author()`, `thumbnail_url()`, `chapters()`, and `key_moments()`.

## Installing pytubefix and downloading a first video

Install the released package from PyPI with the command documented by the project. The repository's `pyproject.toml` declares version 11.2.0, requires Python 3.7 or later, and depends on `aiohttp >=3.12.13` and `nodejs-wheel-binaries >= 22.20.0`.

```bash
pip install pytubefix
```

For a first video, replace the placeholder URL with a YouTube video URL. The example prints the title, selects the highest-resolution stream, and saves it in the current working directory because it does not provide `output_path`.

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

url = "url"

yt = YouTube(url, on_progress_callback=on_progress)
print(yt.title)

ys = yt.streams.get_highest_resolution()
ys.download()
```

The reader should see the video title followed by download progress from `on_progress`. To select audio-only `.m4a` instead, use the documented audio selector:

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

url = "url"

yt = YouTube(url, on_progress_callback=on_progress)
ys = yt.streams.get_audio_only()
ys.download()
```

The repository also installs a `pytubefix` command through the `pytubefix.cli:main` entry point, but the README does not document its command-line options, so its behavior cannot be specified from the repository entry point.

## Playlists, channels, search filters, and OAuth

Collection operations reuse the same stream API. A playlist is instantiated with `Playlist(url)`, and each item in `pl.videos` can provide an audio-only stream. A channel uses `Channel`, first exposing `channel_name` and then iterating over `c.videos`. This consistency means download selection does not require a separate collection-specific format, although it also places responsibility for rate, storage, and filtering decisions on the caller.

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

url = "url"

pl = Playlist(url)
for video in pl.videos:
    ys = video.streams.get_audio_only()
    ys.download()
```

Search can be narrow before download. `Search` accepts a query, while `pytubefix.contrib.search.Filter` offers `upload_date`, `type`, `duration`, `feature`, and `sort_by`. Enumerated values include `Filter.UploadDate.TODAY`, `Filter.Type.VIDEO`, `Filter.Duration.UNDER_4_MINUTES`, `Filter.Features.CREATIVE_COMMONS`, `Filter.Features._4K`, and `Filter.SortBy.UPLOAD_DATE`.

OAuth support is explicit through `use_oauth=True` and `allow_oauth_cache=True`. The README says authentication should occur once for subsequent downloads when cache is allowed. It does not document the credential file location, browser flow, token refresh behavior, or required OAuth scope. Those details must therefore be verified in the hosted documentation before an application depends on unattended authenticated downloads.

## AsyncYouTube concurrency and the blocking download boundary

`AsyncYouTube` is intended for applications that cannot let YouTube data requests block an event loop. Its documented metadata and stream operations are awaited, and `from_id` can construct an instance from a video ID. The interface also provides chapters and key moments. This is a meaningful distinction from the basic `YouTube` examples, but it should not be confused with asynchronous file transfer.

```python
import asyncio
from pytubefix import AsyncYouTube

URL = "YOUR_VIDEO_URL"

async def main():
    yt = AsyncYouTube(URL, use_oauth=True, allow_oauth_cache=True)
    streams = await yt.streams()
    print("Available Streams:")
    for stream in streams:
        print(stream)

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

The documented limitation appears in the specific-stream example: `stream.download(filename="my_video.mp4")` is labeled a blocking call by design. Consequently, an event-loop application still needs to account for transfer duration. The README does not specify an asynchronous download function, executor configuration, cancellation behavior, or resume support. Calling the API asynchronously does not remove that boundary.

There is also a maintenance consideration. The repository is not archived, and its last push was on 2026-10-16. Recent releases include v11.2.0 on 2026-09-30, v11.1.0 on 2026-09-07, and v10.11.0 on 2026-07-29. Users may still face compatibility work when YouTube changes its returned data or media formats, but the README and repository files do not provide a compatibility matrix.

## Operational limits, licensing, and an alternative path

The clearest operational risk is dependence on an external platform's behavior. pytubefix parses and downloads YouTube content, but the documentation does not promise that every URL, age-restricted item, region-limited item, stream, or authentication path will remain available. The dependency on specific minimum versions of `aiohttp` and `nodejs-wheel-binaries` also needs to fit the deployment platform. The MIT license permits reuse, modification, distribution, and sublicensing under its conditions, but applications should retain the required license notice and review the actual `LICENSE` file. The repository does not add commercial-use terms in `pyproject.toml`.

For a one-off download with no Python integration, a browser-based approach is a different option. pytubefix is more appropriate when the application needs `yt.streams`, playlist iteration, caption keys, search filters, custom output paths, or metadata access. The browser path is simpler when none of those capabilities are needed, but pytubefix does not claim that it can replace browser-managed downloads.

A second boundary is disk and destination handling. The README demonstrates `download(output_path="path/to/directory")`, but it does not document overwrite handling, filename sanitization, retry policy, resume behavior, or partial-file cleanup. Those are not minor details for automated batch jobs. Applications should verify them against their chosen videos and destination rules before processing a full playlist or channel.

## Conclusion

pytubefix fits developers who want direct Python access to YouTube stream selection, playlists, captions, channels, search, and metadata. It is a poor fit for environments that require fully nonblocking transfers because the documented `AsyncYouTube` example still calls the synchronous `download()` method. Before adoption, verify that your intended videos remain accessible with your chosen authentication and download approach, and test the required output path and stream format in your own Python environment.

## FAQ

### How do I install pytubefix?

Install it from PyPI with `pip install pytubefix`. The package declares `requires-python = ">=3.7"`.

### How do I download only the audio with pytubefix?

Create a `YouTube` instance, call `yt.streams.get_audio_only()`, and call `download()` on the returned stream. The README identifies this workflow as producing `.m4a` audio.

### Is pytubefix's AsyncYouTube download nonblocking?

No. Stream retrieval and metadata calls are asynchronous, but the README explicitly says `download()` remains a synchronous, blocking call by design.

## Sources

- [JuanBindez/pytubefix on GitHub](https://github.com/JuanBindez/pytubefix)
- [License: MIT](https://github.com/JuanBindez/pytubefix/blob/main/LICENSE)
- [Project website](https://pytubefix.readthedocs.io)
- [README](https://github.com/JuanBindez/pytubefix/blob/main/README.md)
- [Releases](https://github.com/JuanBindez/pytubefix/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/juanbindez-pytubefix
