yt-search-python v2.2.2
Search YouTube videos, playlists, mixes, channels, comments, transcripts, recommendations, suggestions, and stream metadata without the YouTube Data API v3.
Documentation
-
Python 3.9+
-
Sync API:
youtubesearchpython -
Async API:
youtubesearchpython.future -
httpx>=0.28.1 -
No YouTube Data API key or quota
Installation
pip install yt-search-python
Search
from youtubesearchpython import VideosSearch
search = VideosSearch("Arijit Singh", limit=10)
print(search.result())
search.next()
print(search.result())
Live-only search is optional and backward compatible:
live = VideosSearch("news", limit=10, is_live=True)
print(live.result())
Async search loads its first page on the first await next() call. The complete async guide is available in youtubesearchpython/future/README.md.
import asyncio
from youtubesearchpython.future import VideosSearch
async def main():
search = VideosSearch("Arijit Singh", limit=10)
first = await search.next()
print(first)
second = await search.next()
print(second)
asyncio.run(main())
Video
from youtubesearchpython import Video
info = Video.getInfo("pnxL4OOzPEc")
formats = Video.getFormats("pnxL4OOzPEc")
PO token and visitor data can be supplied when required by the selected YouTube client/session:
formats = Video.getFormats(
"pnxL4OOzPEc",
po_token="YOUR_PO_TOKEN",
visitor_data="YOUR_VISITOR_DATA",
)
ResultMode.dict and ResultMode.json are supported by video APIs.
BotGuard PO tokens
The existing imports and explicit po_token arguments remain supported. Optional local BotGuard generation is available through the companion provider:
pip install 'yt-search-python[botguard]'
from youtubesearchpython import BotGuard, Video
video_id = "pnxL4OOzPEc"
po_token = BotGuard.generate(video_id)
formats = Video.getFormats(video_id, po_token=po_token)
The async namespace exposes the same BotGuard class and await BotGuard.agenerate(video_id).
When the optional provider is installed, Video.get() and Video.getFormats() automatically detect YouTube's bot-confirmation player response, mint a fresh video-bound token, fetch visitor data, and retry the compatible WEB/MWEB clients. Normal successful requests do not start BotGuard. Explicit po_token and visitor_data values always take precedence.
formats = Video.getFormats(video_id)
Automatic fallback can be disabled per call:
formats = Video.getFormats(video_id, auto_po_token=False)
BotGuard.resolve(video_id) and await BotGuard.aresolve(video_id) return the provider's full token result when visitor data or cache metadata is needed.
Video and StreamURLFetcher can also read PO-token values from the environment when explicit arguments are not passed:
export YT_PO_TOKEN="..."
export YT_VISITOR_DATA="..."
YOUTUBE_PO_TOKEN and YOUTUBE_VISITOR_DATA are supported aliases. Explicit arguments take precedence.
StreamURLFetcher
StreamURLFetcher no longer uses yt-dlp. It can process a Video.getFormats() result or fetch the format data from a video ID/link itself. With the BotGuard extra installed, video ID/link input automatically resolves a video-bound token and applies it to returned stream URLs. PO-token generation and session-aware token caching are owned by the ytsp-po-token-provider.
from youtubesearchpython import StreamURLFetcher
fetcher = StreamURLFetcher(po_token="YOUR_PO_TOKEN", visitor_data="YOUR_VISITOR_DATA")
url = fetcher.get("pnxL4OOzPEc", 18)
all_streams = fetcher.getAll("pnxL4OOzPEc")
Existing dictionary input remains supported:
from youtubesearchpython import Video, StreamURLFetcher
formats = Video.getFormats("pnxL4OOzPEc")
result = StreamURLFetcher().getAll(formats)
print(result["streams"])
print(result["unresolved"])
Direct URLs and cipher entries that already contain a usable signature are returned without yt-dlp. Formats that still require YouTube's encrypted player-JavaScript signature deciphering are returned under unresolved instead of being presented as working URLs. URLs that still contain an n parameter are marked with throttled=True so callers can make an informed choice rather than silently receiving a falsely-deciphered URL.
Playlists
Regular playlists and YouTube Mix/Radio playlists (RD...) use YouTube's native Innertube endpoints.
from youtubesearchpython import Playlist
normal = Playlist.get("PLRBp0Fe2GpgmsW46rJyudVFlY6IYjFBIK")
mix = Playlist.get("https://youtube.com/playlist?list=RDpnxL4OOzPEc&playnext=1")
Mix results preserve YouTube's returned song order. Duplicate video IDs are removed without re-sorting the result. Generic comment/engagement continuation tokens from /next responses are not treated as playlist continuations.
For regular playlists, instantiate Playlist(link) and call getNextVideos() for continuation pages.
Mixes
Mixes accepts a video ID, video URL, or existing RD... mix ID and returns a direct list with the same item fields as Recommendations.
from youtubesearchpython import Mixes
mix = Mixes.get("pnxL4OOzPEc")
Async:
from youtubesearchpython.future import Mixes
mix = await Mixes.get("https://www.youtube.com/watch?v=pnxL4OOzPEc")
The list preserves YouTube's mix order and removes duplicate video IDs without re-sorting.
Recommendations
from youtubesearchpython import Recommendations
related = Recommendations.get("pnxL4OOzPEc")
Recommendation results preserve YouTube's response order, skip the source video, remove duplicate video IDs stably, and normalize thumbnails against each video's ID.
Suggestions
from youtubesearchpython import Suggestions
print(Suggestions.get("Guru Randhawa"))
YTS_PROXY and YTS_IDENTITY_TOKEN environment variables are supported by the suggestions transport.
Comments, transcripts, channels and hashtags
from youtubesearchpython import Comments, Transcript, Channel, Hashtag
comments = Comments.get("pnxL4OOzPEc")
transcript = Transcript.get("pnxL4OOzPEc", params="en")
channel = Channel.get("UC_x5XG1OV2P6uZZ5FSM9Ttw")
hashtag = Hashtag.get("music", limit=10)
Transcript retrieval first uses YouTube's native caption/player flow. The optional transcript extra keeps the legacy yt-dlp caption fallback available:
pip install 'yt-search-python[transcript]'
HTTP lifecycle
The library uses one canonical httpx transport layer. Idle keep-alive retention is disabled to avoid stale pooled sockets in long-running bots/services.
Sync shutdown:
# Optional forced teardown only
from youtubesearchpython import close_clients
close_clients()
Async shutdown:
# Optional forced teardown only
from youtubesearchpython.future import aclose_clients
await aclose_clients()
Proxy requests use scoped clients that are closed after each request. Temporary downloaded cookie files are also ownership-tracked and cleaned without deleting user-owned cookie files.
Main API
Search:
SearchVideosSearchChannelsSearchPlaylistsSearchCustomSearchChannelSearch
Content:
VideoPlaylistChannelCommentsTranscriptHashtagSuggestionsRecommendationsMixes
Streaming:
StreamURLFetcher
Utilities:
ResultModeSearchModeVideoUploadDateFilterVideoDurationFilterVideoSortOrderChannelRequestType
Python compatibility
- Python 3.9+
- Runtime-tested on Python 3.13.5
- Audited against Python 3.14 asyncio removals/deprecations; the library uses
asyncio.get_running_loop()and does not depend on the deprecated event-loop policy APIs. - HTTP transport uses the tested
httpx>=0.28.1,<1.0range.
HTTP clients are managed internally. Normal sync applications require no explicit shutdown call, and async clients are closed automatically when their owning event loop shuts down gracefully (including asyncio.run()). close_clients() and aclose_clients() remain available only for optional forced teardown, tests, or unusual lifecycle control.
Compatibility notes
youtubesearchpython.futureis the supported async namespace.- Legacy
SearchVideosandSearchPlaylistsimports remain available. - YouTube's internal response structures and anti-abuse requirements can change without notice.
- A PO token does not replace player JavaScript signature or
n-challenge transformation when YouTube requires those for a format.
Related project
For PO-token generation, refresh, session-aware caching, and external provider integration, see BillaSpace/ytsp-po-token-provider.
License
MIT. See LICENSE.
Current maintainer: Prakhar Shukla / BillaSpace. Original project by Hitesh Kumar Saini (alexmercerind).
Metadata
Release files for yt-search-python 2.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| yt_search_python-2.2.2.tar.gz | 276.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| yt_search_python-2.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 325.2 kB
Release files / yt_search_python-2.2.2.tar.gz
| Download URL | yt_search_python-2.2.2.tar.gz |
|---|---|
| Size | 276.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d3fdddde8a9fb376763a7116f02f853486c9efb73f56740f37a1adf661cbca0d
|
|
BLAKE2b-256 checksum How to use checksums |
db551688832455479bef393e392f22ecd796b4a5e0cb2034cb0e7e41fd2f9a9a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / yt_search_python-2.2.2-py3-none-any.whl
| Download URL | yt_search_python-2.2.2-py3-none-any.whl |
|---|---|
| Size | 48.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
57977a13bea89d03f18845bba7de29f0c845469012c503acd7f7c957ecb37b46
|
|
BLAKE2b-256 checksum How to use checksums |
685d2ab146c5643b023d87087fb393f615b3617d5f6e07f90cc2f7a8b50c1622
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|