@rodrigogs/xvideos
v3.2.2
Published
xvideos.com api implementation.
Maintainers
Readme
xvideos
A Node.js library for the xvideos.com API.
Requires Node.js 20+.
Installation
$ npm install @rodrigogs/xvideosUsage
import xvideos from '@rodrigogs/xvideos';const xvideos = require('@rodrigogs/xvideos');
(async () => {
// Retrieve fresh videos from the first page
const fresh = await xvideos.videos.fresh({ page: 1 });
// Log details of the retrieved videos
console.log(fresh.videos); // Array of video objects with properties like url, videoId, title, duration, durationSeconds, thumbnailUrl, profile, watchCount
console.log(fresh.pagination.page); // Current page number
console.log(fresh.pagination.pages); // Array of available page numbers
console.log(fresh.hasNext()); // Check if there is a next page
console.log(fresh.hasPrevious()); // Check if there is a previous page
// Retrieve the next page of fresh videos
const nextPage = await fresh.next();
// Log details of the next page
console.log(nextPage.pagination.page); // Updated current page number
console.log(nextPage.hasNext()); // Check if the next page exists
console.log(nextPage.hasPrevious()); // Check if the previous page exists
// Retrieve the previous page of fresh videos
const previousPage = await fresh.previous();
// Log details of the previous page
console.log(previousPage.pagination.page); // Updated current page number
console.log(previousPage.hasNext()); // Check if the next page exists
console.log(previousPage.hasPrevious()); // Check if the previous page exists
// Retrieve detailed information about a specific video
const detail = await xvideos.videos.details(fresh.videos[0]);
// Log details of the specific video
console.log(detail); // Detailed video object with properties like title, videoId, duration, durationSeconds, thumbnailUrls, watchCount, videoType, files, uploadDate, tags, categories
// Retrieve many detail pages with explicit crawl controls
const batch = await xvideos.videos.detailsMany(fresh.videos.slice(0, 3), {
concurrency: 2,
retries: 1,
minDelayMs: 250,
});
console.log(batch.successes); // Successful detail payloads in input order
console.log(batch.failures); // Failed inputs with their error
})();Crawl ergonomics
xvideos.configure({ minRequestIntervalMs, proxyUrl })
Configures process-wide request behavior. Applies to every request the library makes from this process (all videos.* methods, list and detail alike).
import xvideos from '@rodrigogs/xvideos';
xvideos.configure({
// Minimum spacing between request starts (milliseconds). Keeps the
// library polite against rate limiters and is shared across every
// concurrent client in the process.
minRequestIntervalMs: 250,
// Route requests through an HTTP(S) proxy — useful when running from a
// datacenter IP that XVIDEOS blocks (e.g. CI runners).
proxyUrl: 'http://user:[email protected]:8080',
});minRequestIntervalMs is shared process-wide: the largest configured interval across all clients wins and cannot be lowered afterwards (per-client options raise it further; resetSharedThrottle is exposed from base.ts for full reset). proxyUrl can also be passed per client via RequestOptions when you do not want a global proxy.
Note for CommonJS consumers: require('@rodrigogs/xvideos').configure(...) returns a Promise (the CJS entry loads the ESM build lazily) — await it or chain .then() before firing requests to guarantee the config is applied first.
Development
npm run build
npm run lint
npm run format
npm run test:unit
npm run test:integration
npm run coverage
npm testReal-HTML fixtures under test/fixtures/ pin the current site layout. If a fixture test fails after an XVIDEOS layout change, regenerate with scripts/refresh-fixtures.sh and commit the diff.
Migration Notes
Version 3.2 category browsing and crawl ergonomics
This release is additive:
videos.category({ category, page })— category video listings by slug (/c/<slug>), with 404 handling that surfaces an empty listing for unknown categoriesxvideos.configure({ minRequestIntervalMs, proxyUrl })— process-wide crawl ergonomics: a shared minimum interval between request starts (rate limiting, shared across all clients) and optional HTTP(S) proxy routing- retry backoff now uses exponential backoff with full jitter instead of a fixed linear delay
- real-HTML fixtures (
test/fixtures/) pin the current site layout — parser tests fail on layout changes instead of production code. Regenerate withscripts/refresh-fixtures.sh
Version 3.1 richer list results and crawl ergonomics
This release is additive:
- list items now include
durationSecondsandthumbnailUrl videos.detailsMany()adds ordered batch detail fetching withconcurrency,retries,retryDelayMs, andminDelayMs
Version 3.0 field normalization
Some fields were normalized to remove redundant data while keeping all information available:
| Previous field | New field | Notes |
|---|---|---|
| videos[].path | videos[].videoId | Use video.url if you need full link, or rebuild path with /${video.videoId} when required. |
| videos[].views | videos[].watchCount | Numeric form for sorting/filtering. |
| details.image | details.thumbnailUrls[0] | Primary thumbnail remains available as first item. |
| details.views | details.watchCount | Numeric form for analytics and ranking. |
New fields added
videos[].durationSecondsvideos[].thumbnailUrldetails.videoIddetails.durationSecondsdetails.thumbnailUrlsdetails.watchCountdetails.voteCountdetails.ratingPercentdetails.uploadDatedetails.descriptiondetails.contentUrldetails.tagsdetails.categories
These changes keep feature parity and add richer metadata from structured page data.
API
Retrieve Dashboard Videos
// Retrieve dashboard videos from the first page
const dashboardList = await xvideos.videos.dashboard({ page: 1 });
// Check if there is a next page of results
console.log(dashboardList.hasNext()); // Outputs: true or false
// Check if there is a previous page of results
console.log(dashboardList.hasPrevious()); // Outputs: true or false
// Refresh the current page of results to get updated data
const refreshedVideos = await dashboardList.refresh();
// Retrieve the next page of dashboard videos if available
const nextVideos = await dashboardList.next();
// Retrieve the previous page of dashboard videos if available
const previousVideos = await dashboardList.previous();Retrieve Fresh Videos
// Retrieve fresh videos from the first page
const freshList = await xvideos.videos.fresh({ page: 1 });
// Check if there is a next page of results
console.log(freshList.hasNext()); // Outputs: true or false
// Check if there is a previous page of results
console.log(freshList.hasPrevious()); // Outputs: true or false
// Refresh the current page of results to get updated data
const refreshedVideos = await freshList.refresh();
// Retrieve the next page of fresh videos if available
const nextVideos = await freshList.next();
// Retrieve the previous page of fresh videos if available
const previousVideos = await freshList.previous();Retrieve Best Videos
// Retrieve best videos for a specific year and month, starting from the first page
const bestList = await xvideos.videos.best({ year: '2018', month: '02', page: 1 });
// Check if there is a next page of results
console.log(bestList.hasNext()); // Outputs: true or false
// Check if there is a previous page of results
console.log(bestList.hasPrevious()); // Outputs: true or false
// Refresh the current page of results to get updated data
const refreshedVideos = await bestList.refresh();
// Retrieve the next page of best videos if available
const nextVideos = await bestList.next();
// Retrieve the previous page of best videos if available
const previousVideos = await bestList.previous();Retrieve Verified Videos
// Retrieve verified videos from the first page
const verifiedList = await xvideos.videos.verified({ page: 1 });
// Check if there is a next page of results
console.log(verifiedList.hasNext()); // Outputs: true or false
// Check if there is a previous page of results
console.log(verifiedList.hasPrevious()); // Outputs: true or false
// Refresh the current page of results to get updated data
const refreshedVideos = await verifiedList.refresh();
// Retrieve the next page of verified videos if available
const nextVideos = await verifiedList.next();
// Retrieve the previous page of verified videos if available
const previousVideos = await verifiedList.previous();Retrieve Category Videos
// Retrieve videos from a specific category, starting from the first page
const categoryList = await xvideos.videos.category({ category: 'AI-239' });
// Specify a page number
const categoryPage2 = await xvideos.videos.category({
category: 'Amateur-65',
page: 2,
});
// Check if there is a next page of results
console.log(categoryList.hasNext()); // Outputs: true or false
// Refresh / navigate like any other list result
const refreshed = await categoryList.refresh();
const nextVideos = await categoryList.next();The category option is the slug as it appears in category urls (/c/<category>), e.g. 'AI-239' or 'Amateur-65'. Unknown categories return an empty listing instead of throwing.
Retrieve Video Details
// Retrieve detailed information about a specific video using its URL
const details = await xvideos.videos.details({ url: 'https://www.xvideos.com/video36638661/chaturbate_lulacum69_30-05-2018' });
// Log detailed information about the video
console.log(details); // Detailed video object with properties like title, videoId, duration, durationSeconds, thumbnailUrls, watchCount, videoType, files, uploadDate, description, contentUrl, tags, categories, voteCount, ratingPercentRetrieve Many Video Details
const batch = await xvideos.videos.detailsMany(
[
{ url: 'https://www.xvideos.com/video123/example' },
{ url: 'https://www.xvideos.com/video456/example' },
],
{
concurrency: 3,
retries: 1,
retryDelayMs: 250,
minDelayMs: 500,
},
);
console.log(batch.items); // One entry per input, preserving order
console.log(batch.successes); // Successful detail payloads only
console.log(batch.failures); // Failed requests with input + errordetailsMany() is intended for enrichment and crawling flows where you want explicit control over throughput and retry behavior without making list methods heavy by default.
Filter Videos
// Search for videos using a keyword, and optionally specify a page number
const videos = await xvideos.videos.search({ k: 'threesome' });
// Example with a specific page number
// const videos = await xvideos.videos.search({ k: 'public', page: 5 });
// Check if there is a next page of results
console.log(videos.hasNext()); // Outputs: true or false
// Check if there is a previous page of results
console.log(videos.hasPrevious()); // Outputs: true or false
// Refresh the current page of results to get updated data
const refreshedVideos = await videos.refresh();
// Retrieve the next page of videos if available
const nextVideos = await videos.next();
// Retrieve the previous page of videos if available
const previousVideos = await videos.previous();
// Search for videos with specific parameters
const videos = await xvideos.videos.search({
page: 2,
k: 'threesome',
sort: 'rating',
datef: 'week',
durf: '3-10min',
quality: 'hd'
});
// Log the search results
console.log(videos); // Array of video objects with properties based on the search parametersParams explanation
| Parameter | Default | Options |
|-----------|----------------|------------------------------------------------------------------------------------------|
| page | 1 | (any positive integer) |
| k | "" | (any search keyword) |
| sort | "relevance" | "uploaddate", "rating", "length", "views", "random" |
| datef | "all" | "today", "week", "month", "3month", "6month", "all" |
| durf | "allduration"| "1-3min", "3-10min", "10min_more", "10-20min", "20min_more", "allduration" |
| quality | "all" | "hd", "1080P", "all" |
License
Licence © Rodrigo Gomes da Silva
