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-xhamster
For TS→MP4 remuxing support (recommended for HLS streams), install with the av dependency:
pip install unofficial-api-for-xhamster[av]
eaf_base_api ≥ 4.0.0, which is installed automatically.
Quick Start
Every operation in this wrapper is asynchronous. Run your code inside an async main function:
import asyncio
from xhamster_api import Client
from base_api import DownloadConfigHLS
async def main():
client = Client()
# Fetch video metadata
video = await client.get_video("https://xhamster.com/videos/example-video-123")
print(video.title)
print(video.uploader_name)
# Download video via HLS streaming
config = DownloadConfigHLS(quality="best", path="./downloads")
await video.download(configuration=config)
asyncio.run(main())
Configuration
Networking configurations (proxies, timeouts, limits) are defined via RuntimeConfig inside the BaseCore wrapper.
Please refer to the shared eaf_base_api Documentation for the complete reference.
from base_api import BaseCore
from base_api.modules.config import RuntimeConfig
from xhamster_api import Client
my_config = RuntimeConfig()
my_config.proxy = "socks5://127.0.0.1:9050"
my_config.request_attempts = 4
my_config.videos_concurrency = 8
my_config.pages_concurrency = 2
core = BaseCore(configuration=my_config)
client = Client(core=core)
Client
The entry point for retrieving all resources from xHamster.
from xhamster_api import Client
from base_api import BaseCore
from base_api.modules.config import RuntimeConfig
client = Client()
client_custom = Client(core=BaseCore(RuntimeConfig()))
Constructor Parameters
- core BaseCore — Networking core instance (default:
BaseCore(RuntimeConfig()))
Methods
Fetch Video get_video()
Video object.Parameters
- url str — xHamster video page URL
- load_html bool — If
True, pre-fetches and extracts page metadata immediately
Returns
→ VideoFetch Pornstar get_pornstar()
Parameters
- url str — The pornstar profile page URL
- load_html bool — Pre-load parsed properties
Returns
→ PornstarFetch Creator get_creator()
Creator object.Parameters
- url str — The content creator profile page URL
- load_html bool — Pre-load parsed properties
Returns
→ CreatorFetch Channel get_channel()
Parameters
- url str — The channel page URL
- load_html bool — Pre-load parsed properties
Returns
→ ChannelFetch Short get_short()
Short object.Parameters
- url str — The xHamster shorts URL
- load_html bool — Pre-load parsed properties
Returns
→ ShortSearch Videos search_videos()
Parameters
- query str — Search query words
- minimum_quality str — Minimum resolution limit (default:
"720p") - sort_by str — Sort criteria
- category str | list[str] — Category filters
- vr bool — Filter for VR videos
- full_length_only bool — Only include full-length movies
- min_duration str — Minimum duration limit in minutes
- date str — Upload age filter (e.g.
"weekly") - production str — Filter studio or creator-made uploads
- fps str — Framerate filter
- pages int — Number of search result index pages to scrape
- iterator_config IteratorConfig | None — Concurrency, ordering, source loading, retry, and terminal-error policy. The package default loads the
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Authenticate Account login()
Account instance. Validates API response payloads (extras.error / extras.result), raising LoginFailed when credentials are invalid or payload structure is unexpected. Supports cookie injection fallback.Parameters
- username str — Account username or email
- password str — Account password
- cookies dict | None — Dict of session cookies to bypass authorization steps
Returns
→ AccountVideo
dataclass Inherits from BaseMedia. Represents a standard video with metadata extracted from page source JSON elements.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | The video page URL |
video_id | str | None | Unique video key ID |
video_hash | str | None | Hashed slug associated with the video ID |
title | str | None | Video title |
description | str | None | Video description |
duration | int | None | Video duration in seconds |
views | int | None | Total view count |
comments_count | int | None | Total comment count |
created_timestamp | str | None | Creation timestamp supplied by the page data |
date_ago | str | None | Human-readable age of the upload |
rating_percentage | int | None | Like percentage value |
likes | int | None | Number of likes |
dislikes | int | None | Number of dislikes |
is_vr | bool | None | Whether the video is a VR video |
is_hd | bool | None | Whether the video is available in HD |
max_resolution | str | None | Highest resolution reported by the page data |
orientation | str | None | Content orientation label, such as "straight" or "gay" |
uploader_name | str | None | Uploader profile name |
uploader_subscribers | str | None | Uploader subscriber count |
tags | list[str] | None | List of tags |
categories | list[str] | None | List of category labels |
pornstars | list[str] | None | Pornstars starring in the video |
thumbnail | str | None | Thumbnail cover image URL |
preview_thumbnail | str | None | Preview sprite or animated thumbnail URL |
m3u8_base_url | str | None | HLS playlist URL |
preview_video | str | None | Preview media path |
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 configurations
Returns
→ bool | DownloadReportShort
dataclass Inherits from BaseMedia. Represents a mobile-style short-form video.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | The short URL |
title | str | None | Video title |
tags | list[str] | None | Associated tags |
thumbnail | str | None | Cover thumbnail URL |
video_id | str | None | Unique short video ID |
comment_count | str | None | Number of comments |
duration | str | None | Duration string |
created_at | str | None | Upload timestamp string |
poster_url | str | None | Poster photo URL |
author_link | str | None | Link to author profile |
author_logo | str | None | Author's avatar path |
m3u8_base_url | str | None | HLS playlist URL |
likes | str | None | Number of likes |
views | str | None | Number of views |
author_subscribers | str | None | Author's subscriber count |
author | str | None | Name of the author |
preview_video | str | None | Short preview clip path |
Methods
Download Short download()
Parameters
- configuration DownloadConfigHLS — HLS download configurations
Returns
→ bool | DownloadReportPornstar / Creator / Channel
Profiles representing models, creator users, and publisher studios share a common metadata hierarchy.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | Profile URL |
name | str | None | Display name |
subscribers_count | str | None | Number of subscribers |
videos_count | str | None | Total uploaded videos |
total_views_count | str | None | Sum of views across all videos |
avatar_url | str | None | Avatar profile image URL |
pornstar_information | dict | None | Biography sidebar parameters (only parsed for Pornstar and Creator models) |
Methods
Fetch Profile Videos videos()
Parameters
- pages int — Pages to fetch
- iterator_config IteratorConfig | None — Complete iterator policy. The package default loads the
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Fetch Profile Shorts get_shorts()
Pornstar or Creator. This method is not available on Channel or the shared Something base class.Parameters
- pages int — Pages to fetch
- iterator_config IteratorConfig | None — Complete iterator policy for page and
Shortitems.
Returns
→ AsyncGenerator[ScrapeResult[Short], None]Account
Provides authenticated scraper operations inside logged-in sessions.
Methods
Get Liked Videos get_liked_videos()
Parameters
- pages int — Pages to load
- iterator_config IteratorConfig | None — Complete iterator policy. The package default loads the
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Get Playlist Videos get_account_playlist()
Parameters
- url str — xHamster playlist URL (e.g.
https://xhamster.com/my/playlists/...) - pages int — Pages to load
- iterator_config IteratorConfig | None — Complete iterator policy. The package default loads the
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Downloading Options
xHamster serves videos and shorts via HLS streaming. Configure downloads using DownloadConfigHLS:
from base_api import DownloadConfigHLS
config = DownloadConfigHLS(
quality="best", # "best", "half", "worst", or height int (e.g. 720)
path="./downloads", # Output directory
no_title=False, # Auto-appends title + ".mp4" if False
return_report=True
)
report = await video.download(configuration=config)
For additional downloading properties, see eaf_base_api Documentation.
Scraping Results
Iterators accept one IteratorConfig policy and yield immutable ScrapeResult[Video] or ScrapeResult[Short] values. The package default loads html, skips terminal page failures, and resolves its unset retry policies from the active RuntimeConfig.request_* settings. A supplied configuration replaces that default, so preserve the HTML source and page error mode explicitly; the example below deliberately opts into yielding page failures.
The public configuration fields are max_page_concurrency, max_item_concurrency, max_pending_items, extract_in_thread, order, both *_error_mode, both *_retry, both *_error_handler, load_specific_fields, and load_specific_sources.
from base_api import ErrorAction, ErrorMode, ResultOrder, RetryPolicy, ScrapeErrorContext
from base_api.modules.config import IteratorConfig
async def handle_error(context: ScrapeErrorContext) -> ErrorAction:
if context.attempt < context.max_attempts:
return ErrorAction.RETRY
return ErrorAction.YIELD
iterator_config = IteratorConfig(
max_page_concurrency=2,
max_item_concurrency=8,
order=ResultOrder.ORIGINAL,
load_specific_sources=("html",),
page_retry=RetryPolicy(max_attempts=4, base_delay=0.5, jitter=0.25),
item_retry=RetryPolicy(max_attempts=4, base_delay=0.5, jitter=0.25),
page_error_mode=ErrorMode.YIELD,
item_error_mode=ErrorMode.YIELD,
page_error_handler=handle_error,
item_error_handler=handle_error,
)
async for result in client.search_videos(
"reality", pages=2, iterator_config=iterator_config
):
if result.succeeded:
video = result.unwrap()
print(video.title)
else:
print(result.stage, result.url, result.attempts, result.error)
ScrapeErrorContext(stage, url, error, attempt, max_attempts, page_index, item_index) and returns ErrorAction.RETRY, RAISE, YIELD, or SKIP. RetryPolicy exposes max_attempts, base_delay, multiplier, max_delay, jitter, and retry_for; attempts include the first call.
ScrapeResult Attributes
| Attribute | Type | Description |
|---|---|---|
stage | ScrapeStage | PAGE or ITEM |
url | str | The page or item target URL |
page_index | int | Zero-based source-page index |
item_index | int | None | Zero-based item index; None for page failures |
attempts | int | Number of attempts consumed |
item | Video | Short | None | The loaded item on success |
error | ScrapeOperationError | None | The typed terminal error on failure |
succeeded | bool | True when the result contains an item |
unwrap() | Video | Short | Returns the item or raises its terminal error |
Error Handling
Source loaders translate request failures into exceptions from xhamster_api.modules.errors. Calls that load media expose ordinary loader failures through base_api.MediaLoadError (or MediaLoadErrors for several sources); inspect original_error/errors. Operations outside media loading, such as login, 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.
LoginFailed 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 (e.g. video deleted) |
NetworkError | Request failed due to a network error, exhausted request retries, or a non-404 HTTPStatusError |
BotDetection | Bot-protection challenge block detected |
ProxyError | Proxy configuration failed or proxy is down |
UnknownNetworkError | Unexpected network errors |
DownloadFailed | Download preparation or transfer failed; the video URL is included and __cause__ retains the original exception |
LoginFailed | Sign-in credentials, API response error (e.g. invalid login or password in JSON response payload), or API challenge failed |
from xhamster_api.modules.errors import NotFound, LoginFailed
try:
account = await client.login(username, password)
except LoginFailed:
print("Login failed. Please verify credentials.")
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.
xHamster API includes a command-line interface accessible via xhamster_api or python -m xhamster_api:
# Download a single video
xhamster_api --download "https://xhamster.com/videos/sample-title-12345" --quality best --output ./downloads --no-title False
# Or invoke via python -m
python -m xhamster_api --download "https://xhamster.com/videos/sample-title-12345" --quality best --output ./downloads --no-title False
# Download from a line-separated file of URLs
xhamster_api --file urls.txt --quality best --output ./downloads --no-title False
CLI Options
| Flag | Description |
|---|---|
--download URL | Video URL to download |
--file FILE | Text file with URLs (separated by newlines) |
--quality QUALITY | Video quality: best, half, worst |
--output DIR | Destination directory or output file path |
--no-title True/False | Skip auto-appending video title to output filename (default: False) |
Supported Platforms
| Platform | Architecture | Status |
|---|---|---|
| Windows 11 | x64 | ✅ Tested |
| macOS Sequoia | x86_64 / arm64 | ✅ Tested |
| Linux (Arch) | x86_64 | ✅ Tested |
| Android 16 | aarch64 | ✅ Tested |
Changelog
| Date | Commit | Changes |
|---|---|---|
| 2026-09-17 | e452f99 / 79f61a7 | Released 2.6.2. Added validation for invalid credential error payloads in xHamster login API JSON responses (extras.error), raising LoginFailed when authentication fails rather than returning an invalid Account instance on HTTP 200 responses. |
| 2026-09-15 | a136ebe / 8030a56 | Adopted shared request and download error handling with base_api.modules.provider (requiring eaf-base-api>=4.2.0). Failed downloads now raise DownloadFailed with complete context. Added layout anchor validations to detect page structure changes. Implemented resilient fallback selectors for video and pornstar metadata. Enhanced download stream URL resolution and error handling. Added snippet-based unit tests for video and pornstar extraction. |
| 2026-08-24 | c640d89 / b7c302e | Adapted listing extraction to the site's new per-video data-video-id layout, searched all candidate result containers, deduplicated overlapping results, and mapped listing duration into the current duration field. |
| 2026-08-14 | 79224f5 | Released 2.6 with expanded Video metadata: hash, description, duration/views/comments, timestamps, VR/HD flags, maximum resolution, orientation, and preview thumbnail. |
| 2026-08-11 | d9714c3 | Released 2.5 with complete typing and py.typed; repaired selectors and fallbacks; implemented get_shorts() on Pornstar and Creator (not the shared base or Channel); and aligned retry defaults with RuntimeConfig. |
| 2026-08-08 | 5ce0a28 | Centralized concurrent scraping on IteratorConfig and forwarded package source/retry defaults. |
| 2026-08-07 | 706fd4f | Migrated source-aware media, explicit loading, bounded retries, and structured scrape results to eaf v4. |