đŦ Videos
Overview
The POST /api/videos endpoint is used to retrieve videos
from the given source. It contains information about the videos,
channels, and other relevant information.
Request
POST /api/videos
{
"query": "kittens",
"channel": "my-channel",
"channels": ["my-channel", "another-channel"], // Channels supporting multiple sites/channels
"sort": "new",
"page": 1,
"pageSize": 40,
"clientVersion": "2.2.7-38", // {version}â{build}, useful for feature availability
"blockedKeywords": ["example"],
"blockedUploaders": ["uploader-id-123"],
// Your server's custom parameters will be added here
"quality": "hd",
"duration": "short",
"flavor": "mint_chocolate_chip"
}
Request Parameters
| Field | Type | Default | Description |
|---|---|---|---|
query |
string |
"" |
Search query |
channel |
string |
â | Single channel identifier (as defined in your server's status response) |
channels |
string[] |
â | Multiple channel identifiers to search across (overrides channel) |
sort |
string |
"relevance" |
Sort option ID (as defined in your server's status response options) |
page |
number |
1 |
Page number for pagination |
pageSize |
number |
40 |
Results per page |
clientVersion |
string |
â | App version string (e.g., "2.2.7-38") |
blockedKeywords |
string[] |
[] |
Keywords to exclude from results |
blockedUploaders |
string[] |
[] |
Uploader IDs to exclude from results |
| (server options) | any |
â | Any option IDs defined in your server's status response are forwarded as-is |
Server-Defined Filter Options
Filter parameters beyond the core ones above (e.g., duration,
quality, content type, sexuality) are entirely defined by your server
via the options array in the Status endpoint response. Whatever id values you expose there will be sent back verbatim when the user selects them. Your /api/videos handler receives them as top-level keys in the request body.
Response
{
"pageInfo": {
"hasNextPage": true,
"recommendations": ["cats", "pets", "animals"],
"error": null, // e.g. "No results were found"
"message": null, // e.g. "Showing cached results" or "Some content filtered based on preferences"
"parameters": {
"totalResults": 1000
}
},
"items": [
{
"id": "c85017ca87477168d648727753c4ded8a35f173e22ef93743e707b296becb299",
"title": "20 Minutes of Adorable Kittens BEST Compilation",
"url": "https://www.example.com/watch?v=y0sF5xhGreA",
"duration": 110,
"channel": "my-channel",
"thumb": "https://i.example.com/vi/y0sF5xhGreA/hqdefault.jpg",
"views": 14622653,
"rating": 95,
"uploader": "Awesome Vids",
"uploaderUrl": "https://www.example.com/@awesomeVids",
"uploaderId": "awesomeVids",
"verified": false,
"isVR": false,
"tags": ["cats", "kittens", "pets"],
"categories": ["Animals", "Entertainment"],
"uploadedAt": "2025-01-03T10:15:54.000Z",
"preview": "https://example.com/preview.mp4",
"uploaderId": "petcollective",
"aspectRatio": 1.78,
"uploaderProfile": {
"id": "abc123",
"name": "Awesome Vids",
"avatar": "https://example.com/avatar.jpg",
"videoCount": 342,
"totalViews": 14500000
},
"formats": [
{
"url": "https://www.example.com/watch?v=y0sF5xhGreA",
"quality": 1080,
"format": "mp4",
"formatId": "mp4-1080",
"protocol": "m3u8_native",
"ext": "mp4",
"httpHeaders": {
"Referer": "https://www.example.com"
}
}
],
"embed": {
"source": "https://www.example.com/watch?v=y0sF5xhGreA",
"html": "<iframe src='...' width='560' height='315'></iframe>",
"width": 560,
"height": 315
}
}
]
}
Field Reference
Response Root Fields
| Field | Type | Description |
|---|---|---|
pageInfo |
PageInfo |
Pagination and status metadata |
items |
Video[] |
Array of video objects |
PageInfo Object Fields
| Field | Type | Required | Description |
|---|---|---|---|
hasNextPage |
boolean |
â | Whether more results are available |
recommendations |
string[] |
âĒ | Suggested search terms |
error |
string |
âĒ | Error message (e.g., "No results were found") |
message |
string |
âĒ | Informational message (e.g., "Showing cached results") |
parameters |
object |
âĒ | Additional metadata (e.g. "cursor": "abc123") |
Error vs Message
error: Use for actual errors that prevent normal operation (no results, API failure, invalid query)message: Use for informational notices that don't indicate failure (cached results, filtered content, rate limiting info, feature announcements)
Video Object Fields
| Field | Type | Required | Description |
|---|---|---|---|
title |
string |
â | Video title |
url |
string |
â | Video source URL |
duration |
number |
â | Video length in seconds |
channel |
string |
â | Source channel/platform identifier |
thumb |
string |
â | Thumbnail image URL |
id |
string |
âĒ | Unique video identifier (auto-generated if not provided) |
network |
string |
â | Alias for channel â added by the server on every response item |
isVR |
boolean |
â | true when VR content is detected from tags â added by the server |
uploaderProfile |
UploaderProfile |
â | Partial uploader profile card â added by the server when a profile exists |
views |
number |
âĒ | View count |
rating |
number |
âĒ | Video percent rating score |
uploader |
string |
âĒ | Content creator name |
uploaderUrl |
string |
âĒ | Creator's profile URL |
uploaderId |
string |
âĒ | Unique uploader identifier |
tags |
string[] |
âĒ | Array of content tags (ordering is up to your server) |
categories |
string[] |
âĒ | Array of content categories |
uploadedAt |
Date|String |
âĒ | Upload date (flexible format) |
preview |
string |
âĒ | Preview GIF/video URL |
formats |
Format[] |
âĒ | Video format array |
aspectRatio |
number |
âĒ | Video aspect ratio (e.g., 1.78 for 16:9) |
embed |
EmbedData |
âĒ | Embed data for Reddit-style content |
isLive |
boolean |
âĒ | true when the video is a live stream â replaces duration with a "LIVE" badge |
liveStatus |
string |
âĒ | yt-dlp live status: "live", "not_live", "was_live", "post_live" â used alongside isLive for badge and availability UI |
availability |
string |
âĒ | Content availability hint â "offline" shows an unavailable badge instead of duration |
Live & Availability Display
The app uses isLive and liveStatus together to determine how a video card renders:
- Live badge shown when
isLive == trueorliveStatus == "live"â the duration label is hidden and replaced with a "LIVE" indicator. - Unavailable badge shown when
availability == "offline", orliveStatusis"not_live"or"was_live"â again replacing the duration. - Normal duration shown otherwise.
During playback, the player also detects live streams from the HLS
stream itself (indefinite duration) and adjusts transport controls
accordingly â so isLive is not required for playback to behave correctly, but it ensures the video card UI is accurate before the stream is loaded.
UploaderProfile Object
Attached to each video item when a known uploader profile exists. Used to render the uploader row on video cards without a separate API call.
| Field | Type | Description |
|---|---|---|
id |
string |
Uploader identifier |
name |
string |
Display name |
avatar |
string \| null |
Avatar image URL (canonical) |
videoCount |
number |
Total indexed videos |
totalViews |
number |
Aggregated view count |
See JSON key names for camelCase vs snake_case and the legacy profile_picture_url avatar key.
Format Object Fields
| Field | Type | Required | Description |
|---|---|---|---|
url |
string |
â | Direct video stream URL |
formatId |
string |
Auto-generated | Format identifier (provided or auto-generated) |
ext |
string |
âĒ | File extension ("mp4", "webm") |
protocol |
string |
âĒ | Stream protocol ("https", "m3u8_native") - important for playback |
httpHeaders |
object |
âĒ (đ CDN) | Required headers for CDN authentication |
height |
number |
âĒ (đą UX) | Video height in pixels (240, 480, 720, 1080) - recommended for better format IDs |
width |
number |
âĒ | Video width in pixels |
resolution |
string |
âĒ | Resolution string ("720p" or "1280x720") |
format |
string |
âĒ | Format description |
fps |
number |
âĒ | Frames per second |
quality |
number |
âĒ | yt-dlp quality score (fallback for formatId generation) |
vcodec |
string |
âĒ | Video codec ("avc1.640020", "h264") |
acodec |
string |
âĒ | Audio codec ("mp4a.40.2", "aac") |
tbr |
number |
âĒ | Total bitrate |
abr |
number |
âĒ | Audio bitrate |
vbr |
number |
âĒ | Video bitrate |
dynamicRange |
string |
âĒ | Dynamic range ("SDR", "HDR") |
aspectRatio |
number |
âĒ | Video aspect ratio |
filesize |
number |
âĒ | File size in bytes |
language |
string |
âĒ | Audio language |
container |
string |
âĒ | Container format |
downloaderOptions |
object |
âĒ | Download configuration (defaults to 1MB chunks) |
CDN Authentication
Many premium/CDN streams require httpHeaders for authentication. Common headers include:
User-Agent- Required by most CDNsReferer- Required for hotlink protectionAccept,Accept-Language- For content negotiation
Format ID Generation
If formatId is not provided, it's auto-generated in this order:
{format}_{height}p(e.g., "mp4_720p"){format}_{resolution}(e.g., "mp4_1280x720"){format}_{quality}(e.g., "mp4_2.5"){format}only
Best Practices
- Only
urlis truly required - everything else is optional - Include
heightfor meaningful format IDs and better user experience - Add
httpHeadersfor CDN streams that need authentication - Providing
formatsbypasses yt-dlp extraction (faster response) - Providing
previewavoids on-device preview generation