Other Options:
• PayPal
• Ko-Fi
For extended features, enterprise integrations, or custom commercial licensing, please contact EchterAlsFakeBS@proton.me.
Installation
Install from PyPI using pip:
pip install unofficial-api-for-xnxx
For TS→MP4 remuxing support (recommended for HLS downloads), install with the optional av dependency:
pip install unofficial-api-for-xnxx[av]
eaf_base_api ≥ 4.0.0 is installed automatically as a dependency.
Quick Start
Every method in this API is asynchronous. You need to run your code inside an async function:
import asyncio
from xnxx_api import Client
async def main():
client = Client()
# Fetch a video
video = await client.get_video("https://www.xnxx.com/video-...")
# Access metadata
print(video.title)
print(video.length)
print(video.views)
# Download the video
from base_api import DownloadConfigHLS
config = DownloadConfigHLS(quality="best", path="./downloads")
await video.download(configuration=config)
asyncio.run(main())
Configuration
The API uses eaf_base_api ≥ 4.0.0. Configure its singular proxy, bounded request attempts, timeouts, and other runtime behavior through a custom BaseCore.
Please refer to the eaf_base_api Documentation for the complete reference on how to set up RuntimeConfig and properly integrate it with this API.
from base_api import BaseCore
from base_api.modules.config import RuntimeConfig
from xnxx_api import Client
my_config = RuntimeConfig()
my_config.proxy = "socks5://127.0.0.1:9050"
my_config.request_attempts = 3
core = BaseCore(configuration=my_config)
client = Client(core=core)
Client
The Client class is the entry point for all API requests. It initializes and manages sessions to retrieve videos, fetch user data, and execute paginated search queries.
from xnxx_api import Client
from base_api import BaseCore
client = Client()
# Or initialize with custom core config
client_custom = Client(core=BaseCore())
Constructor Parameters
- core BaseCore — Networking core instance (default:
BaseCore())
Methods
Fetch Video get_video()
Video object. Extracts inline JSON metadata and master HLS playlist files.Parameters
- url str — The full XNXX video URL
- load_html bool — If
True(default), fetches and parses the HTML page for metadata
Returns
→ VideoFetch User get_user()
User object. Simultaneously requests the profile page and the initial video JSON listing page to fetch totals.Parameters
- url str — The full XNXX user profile URL
- load_html bool — If
True(default), parses HTML pages
Returns
→ UserSearch Videos search_videos()
Parameters
- query str — Search keywords
- pages int — Number of pages to iterate
- mode Mode | str — Sort mode (e.g.
Mode.hits,Mode.random) - upload_time UploadTime | str — Upload age filter (e.g.
UploadTime.month) - length Length | str — Video duration category (e.g.
Length.X_10min_plus) - searching_quality SearchingQuality | str — Video quality category (e.g.
SearchingQuality.X_1080p_plus) - iterator_config IteratorConfig | None — Optional v4 concurrency, ordering, eager-source, retry, and error-handling policy. The package default eagerly loads the
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Video
dataclass Inherits from BaseMedia. Represents a single video with parsed metadata and HLS download streams.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | The video page URL |
title | str | None | Video title |
description | str | None | Video description metadata |
thumbnail | str | None | Thumbnail cover image URL |
publish_date | str | None | Upload / publish date string |
length | str | None | Duration string (e.g. PT15M42S) |
m3u8_base_url | str | None | Master HLS stream playlist URL |
views | str | None | Total view count |
author | str | None | Uploader name shown on the video page |
tags | list[str] | None | Keyword tags linked from the video page |
| Scraper Iterator Fallback Attributes | ||
video_id | str | None | Numeric video identifier |
video_eid | str | None | External unique string ID |
preview_video_url | str | None | Direct URL to the short trailer / preview video clip |
rating | str | None | Upvote percentage or ranking score |
max_quality | str | None | Maximum resolution tag badge |
Methods
Download Video download()
no_title=True on the config. Ordinary failures raise DownloadFailed with full diagnostic context and chained cause.Parameters
- configuration DownloadConfigHLS — HLS download options. See Downloading Options.
Returns
→ bool | DownloadReportUser
dataclass Inherits from BaseMedia. Represents an XNXX user profile containing upload statistics and video iterations.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | The user profile URL |
total_videos_count | int | None | Total uploaded videos |
total_pages_count | int | None | Total number of paginated video list pages |
total_videos_views | str | None | Total views across all uploads |
Methods
Get Uploaded Videos videos()
Parameters
- pages int — Max pages to fetch (will automatically cap to
total_pages_count) - iterator_config IteratorConfig | None — Optional v4 iterator policy. The default eagerly loads each video's
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Search & Filtering
XNXX video searches use customized StrEnums for constructing query filters. Import them from xnxx_api.modules.search_filters:
from xnxx_api.modules.search_filters import Length, UploadTime, SearchingQuality, Mode
async for result in client.search_videos(
query="college",
pages=3,
mode=Mode.hits,
length=Length.X_10min_plus,
searching_quality=SearchingQuality.X_1080p_plus,
upload_time=UploadTime.month
):
if result.succeeded:
video = result.unwrap()
print(video.title)
Filter Options
Sort Mode (Mode)
| Enum Member | Path Suffix | Description |
|---|---|---|
Mode.default | "" | Standard relevant sort |
Mode.hits | "/hits" | Sort by total hits / views |
Mode.random | "/random" | Randomized ordering |
Duration Length (Length)
| Enum Member | Path Suffix | Range |
|---|---|---|
Length.X_0_10min | "/0-10min" | Under 10 minutes |
Length.X_10min_plus | "/10min+" | 10 minutes and longer |
Length.X_10_20min | "/10-20min" | Between 10 and 20 minutes |
Length.X_20min_plus | "/20min+" | 20 minutes and longer |
Upload Time Age (UploadTime)
| Enum Member | Path Suffix | Timeline |
|---|---|---|
UploadTime.month | "/month" | Uploaded within this month |
UploadTime.year | "/year" | Uploaded within this year |
Quality Class (SearchingQuality)
| Enum Member | Path Suffix | Target Quality |
|---|---|---|
SearchingQuality.X_720p | "/hd-only" | HD resolutions (720p) |
SearchingQuality.X_1080p_plus | "/fullhd" | Full HD & UHD (1080p and higher) |
Downloading Options
XNXX video downloads are HLS-only. Configure stream downloads via DownloadConfigHLS:
from base_api import DownloadConfigHLS
config = DownloadConfigHLS(
quality="best", # "best", "half", "worst", or height int
path="./downloads", # Destination path
no_title=False, # If False, automatically appends title + ".mp4"
)
success = await video.download(configuration=config)
For full details on download options and setup configurations, see the eaf_base_api Documentation.
Pagination & Iterators
Page scraper lists (client.search_videos() and user.videos()) yield typed ScrapeResult[Video] values. Use succeeded to branch safely or unwrap() to return the item and raise its terminal error on failure:
async for result in client.search_videos("amateur", pages=2):
if result.succeeded:
video = result.unwrap()
print(video.title, video.url)
else:
print(result.stage, result.url, result.error)
ScrapeResult Properties
| Attribute | Type | Description |
|---|---|---|
stage | ScrapeStage | Whether the result came from the page or item stage |
url | str | The video item page URL |
page_index | int | Zero-based source page index |
item_index | int | None | Zero-based item index, or None for a page failure |
attempts | int | Number of attempts used by the yielding stage |
item | Video | None | Populated video on success |
error | ScrapeOperationError | None | Typed terminal page or item error on failure |
succeeded | bool | True when error is None |
IteratorConfig, bounded retries, and custom handlers
All iterator-only controls now live in one IteratorConfig. XNXX's package default uses ErrorMode.SKIP for terminal page failures; a supplied config replaces that behavior, and a bare IteratorConfig instead defaults to ErrorMode.YIELD. A retry policy's max_attempts includes the initial attempt, so this example makes at most three stage attempts per failed page or item. Each stage attempt may itself perform the request retries configured on BaseCore. Results need the html source for eager population.
Leave page_retry or item_retry as None to derive that stage's bounded policy from the active RuntimeConfig request-attempt and backoff settings; an explicit RetryPolicy overrides it per stage.
from base_api import ErrorAction, RetryPolicy, ScrapeErrorContext
from base_api.modules.config import IteratorConfig
async def handle_scrape_error(context: ScrapeErrorContext) -> ErrorAction:
if context.attempt < context.max_attempts:
return ErrorAction.RETRY
return ErrorAction.YIELD
retry = RetryPolicy(
max_attempts=3, base_delay=0.5, multiplier=2.0,
max_delay=4.0, jitter=0.2
)
iterator_config = IteratorConfig(
max_page_concurrency=2,
max_item_concurrency=8,
max_pending_items=16,
load_specific_sources=("html",),
page_retry=retry,
item_retry=retry,
page_error_handler=handle_scrape_error,
item_error_handler=handle_scrape_error,
)
async for result in client.search_videos(
"amateur", pages=2, iterator_config=iterator_config
):
if result.succeeded:
print(result.unwrap().title)
else:
print(result.stage, result.error)
ScrapeErrorContext supplies stage, url, error, attempt, max_attempts, page_index, and item_index. A handler returns ErrorAction.RETRY, RAISE, YIELD, or SKIP.
The core routes page-stage failures to page_error_handler and item-stage failures to item_error_handler. Assign the same callable to both fields only when both stages should use the same policy; otherwise configure either handler independently.
Error Handling
Source loaders translate request failures into exceptions from xnxx_api.modules.errors. Calls that load media expose ordinary loader failures through base_api.MediaLoadError (or MediaLoadErrors for several sources); inspect original_error/errors as shown. Operations outside media loading may still raise package or core exceptions directly.
Request and download failures are logged with the operation, target URL, and full original traceback. Translated exceptions retain the original error in __cause__. Download preparation failures (including metadata loading, quality selection, and output path setup) are also wrapped in DownloadFailed; inspect its cause when diagnosing a failure. The specific availability exceptions listed below remain supported. An explicit DownloadCancelled or asyncio.CancelledError propagates without being wrapped in DownloadFailed. Base downloader False and DownloadReport results remain supported; inspect the result as well as handling exceptions.
The common provider errors NotFound, NetworkError, BotDetection, ProxyError, UnknownNetworkError, and DownloadFailed are catchable through base_api.modules.errors. They derive from ScraperException, which now derives from BaseScraperError. Existing provider import paths remain valid.
RegionBlocked now derives from the shared ScraperException; its existing provider import and msg attribute remain available.
See Logging & Cleanup for application logging setup.
| Exception | Trigger Cause |
|---|---|
NotFound | Server returned HTTP 404 |
RegionBlocked | The base request raised AccessDeniedError (for example, HTTP 401 or 403). This does not by itself prove a geographic restriction. |
NetworkError | Request failed due to a network error, exhausted request retries, or a non-404 HTTPStatusError |
BotDetection | Bot-protection challenge block detected |
ProxyError | Proxy connection failed |
UnknownNetworkError | Unexpected network errors |
DownloadFailed | Download preparation or transfer failed; the video URL is included and __cause__ retains the original exception |
from base_api import MediaLoadError
from xnxx_api.modules.errors import RegionBlocked
try:
video = await client.get_video(url)
except MediaLoadError as error:
if isinstance(error.original_error, RegionBlocked):
print("Access to this URL was denied; inspect the original error.")
else:
raise
CLI Usage
The CLI entry point configures console logging at INFO level. Caught per-URL failures include the URL and full traceback; the default log format shows the logger, file, line, and function. Library applications should configure logging once at startup.
The XNXX API package includes a CLI tool executable directly from the terminal via xnxx_api or python -m xnxx_api:
# Download a single video to target folder
xnxx_api --download "https://www.xnxx.com/video-..." --quality best --output ./downloads --no-title False
# Batch download URLs from a line-separated text file
xnxx_api --file file_list.txt --quality best --output ./downloads --no-title False
CLI Parameters
| Flag | Description |
|---|---|
--download URL | Download video from the specified XNXX URL |
--file PATH | Read URLs from a text file (separated by newlines) and download them |
--quality QUALITY | Required. Set video download quality: best, half, worst |
--output DIR | Required. Destination file or directory path |
--no-title True/False | Required. Skip auto-appending video title to output filename (set to True if output path includes target filename) |
Changelog
2.4.1 — 2026-09-15
6857235/0ee8040— Adopted shared request and download error handling withbase_api.modules.provider(requiringeaf-base-api>=4.2.0). Failed downloads now raiseDownloadFailedwith complete context. Added layout anchor validations to detect page structure changes. Implemented robust fallback parsing for ld+json and HTML metadata (title, description, thumbnail, publish date, length, views, author, tags). Cleaned up log messages when paginating user videos.
2.4.1 — 2026-08-14
af53c16— Added HTML-backedVideo.authorandVideo.tagsfields.
2.4 — 2026-08-11
1d57554— Prefixed search-result links withhttps://xnxx.com, added genericScrapeResult[Video]typing and the PEP 561py.typedmarker, left iterator retry policies unset so they resolve fromRuntimeConfig, and released 2.4.
2.3 — 2026-08-08
45c4e90— ConsolidatedUser.videos()andClient.search_videos()pagination, concurrency, source loading, retry, ordering, and error controls intoIteratorConfig.
2.3 migration — 2026-08-07
0bf61e5— Migrated to the eaf_base_api v4 request and scraping model:fetch_text()/request(), structured exceptions, source-aware media loading, typed scrape streams/results, and bounded retries.
Supported Platforms
| Platform | Architecture | Status |
|---|---|---|
| Windows 11 | x64 | ✅ Tested |
| macOS Sequoia | x86_64 | ✅ Tested |
| Linux (Arch) | x86_64 | ✅ Tested |
| Android 16 | aarch64 | ✅ Tested |