API Platform
YouTube API
YouTube search rankings, full video details, transcripts in any language with translation, and comments — for any video, without quotas.
YouTube search rankings as a real viewer sees them, full video details, transcripts (with translation) and comments for any public video. One endpoint serves four reports, selected with the type parameter. There are no daily quotas, and transcripts work for any video, not only your own.
Requests longer than 60 seconds
This endpoint runs requests as tasks. A request that runs longer than 60 seconds returns 202 with a task_id; collect the result from GET /v1/tasks/{task_id}. Every response, including a normal 200, carries the task id in the X-Task-Id header. Use ?wait= to change how long the request waits, and an Idempotency-Key header to retry safely.
Authentication
| Header | Type | Description |
|---|---|---|
SEMUST-API-USER | string | Your API user's username |
SEMUST-API-PASSWORD | string | Your API user's password |
Accept-Language | string | Optional. Send tr to receive error messages in Turkish |
Create API credentials from the API Access page.
SEMUST-API-USER: your_username
SEMUST-API-PASSWORD: your_password
Content-Type: application/jsonReport Types
type | Returns | Price |
|---|---|---|
search (default) | YouTube results for a keyword, in ranking order: videos, Shorts, playlists, channels and ads | $0.0022 per started block of 20 results |
video | One video's details: views, likes, comments, channel and subscribers, publish date, duration, category, tags, and which transcripts it has | $0.0066 |
transcript | One video's transcript as plain text plus timed segments, optionally translated | $0.0066 |
comments | A video's top comments with author, likes and reply counts | $0.0022 per started block of 20 comments |
{
"type": "search",
"keyword": "seo nedir",
"limit": 20
}{
"type": "transcript",
"video_id": "https://www.youtube.com/watch?v=CnQmoQD4xRM",
"translate_to": "en"
}Request Parameters
A parameter that does not apply to the chosen type is rejected rather than ignored, and a misspelled one is named in the error with a suggestion. A JSON null is treated as "not sent".
Body
typestringdefault: searchsearch, video, transcript or comments.
keywordstringsearch only, required. Up to 200 characters.
video_idstringvideo, transcript and comments, required. The 11-character ID (CnQmoQD4xRM) or any YouTube URL: watch?v=, youtu.be/, shorts/, embed/ or live/.
countrystringdefault: TRTwo-letter country code: where the search is run from, and the region a video is read in. See Markets below.
languagestringsearch only. Interface language of the search. Defaults to tr for TR and en elsewhere.
devicestringdefault: desktopsearch only. desktop or mobile.
limitintegerdefault: 20search and comments. Results to return, 1–200. Billed per started block of 20, so 20 and 40 are the economical sizes.
transcript_languagestringtranscript only. Which transcript to read, e.g. tr or en-GB. Defaults to tr for TR and en elsewhere. type: "video" lists the transcripts a video has.
translate_tostringtranscript only. Translate the transcript into this language, e.g. en.
idempotency_keystringOptional, up to 128 characters. Repeating a request with the same key returns the same task — its 202 while it runs, its stored result once it finishes — and it is charged once. The key is reserved until 72 hours after the task finishes. Same as the Idempotency-Key header; if you send both, this field wins.
Query
waitintegerdefault: 60Seconds to wait for the result, 0–80. If the request is still running after that, the response is 202 with a task_id. 0 answers 202 at once.
Headers
Idempotency-KeystringOptional. Works like idempotency_key above; if you send both, the body field wins.
GET /v1/youtube/markets lists every supported country and search language. It is free.
A request still running after 60 seconds returns 202. The call() helper on Tasks & Long-Running Requests polls until the result is ready.
curl -X POST https://data.semust.com/v1/youtube \
-H "SEMUST-API-USER: your_username" \
-H "SEMUST-API-PASSWORD: your_password" \
-H "Content-Type: application/json" \
-d '{"type": "transcript", "video_id": "https://youtu.be/CnQmoQD4xRM"}'import requests
response = requests.post(
"https://data.semust.com/v1/youtube",
headers={
"SEMUST-API-USER": "your_username",
"SEMUST-API-PASSWORD": "your_password",
},
json={"type": "search", "keyword": "seo nedir", "limit": 20},
timeout=90, # longer than ?wait= (60 seconds by default)
)
data = response.json()
if response.status_code == 202:
# Still running. Collect it later from data["poll_url"],
# or use the call() helper from the Tasks page.
raise SystemExit(f"Task {data['task_id']} is still running")
if response.status_code != 200:
raise SystemExit(f"{data['code']}: {data['error']} {data.get('hint', '')}")
for row in data["items"]:
print(row["position"], row["type"], row["title"], row["views"])Response
search and comments return rows in items; video and transcript return one data object. A value that does not exist or does not apply is null, never 0 — a playlist has "views": null.
URLs are canonical (https://www.youtube.com/watch?v=…, without tracking parameters) and dates are ISO 8601 in UTC. In search results published_at is approximate, because YouTube shows relative dates there ("5 years ago"); type: "video" gives the exact date. For search, total is the result count YouTube reports.
The examples below are real responses.
{
"success": true,
"type": "search",
"keyword": "seo nedir",
"country": "TR",
"language": "tr",
"device": "desktop",
"total": 628065,
"count": 2,
"limit": 2,
"items": [
{
"position": 1,
"type": "video",
"title": "SEO Nedir? | Webtures",
"url": "https://www.youtube.com/watch?v=CnQmoQD4xRM",
"video_id": "CnQmoQD4xRM",
"channel_name": "Webtures",
"channel_url": "https://www.youtube.com/@Webturescom",
"views": 241552,
"video_count": null,
"published_at": "2021-11-05T21:17:53Z",
"duration_seconds": 180,
"is_live": false
},
{
"position": 2,
"type": "playlist",
"title": "SEO Eğitimi Serisi - 2024 - Sıfırdan Uzmanlığa",
"url": "https://www.youtube.com/playlist?list=PLaqVtetWSaGhlXiU48bDd8511btrbx6T2",
"video_id": null,
"channel_name": "Mehmet Ali Yassı",
"channel_url": "https://www.youtube.com/@maliyassi",
"views": null,
"video_count": 20,
"published_at": null,
"duration_seconds": null,
"is_live": null
}
],
"cost": 0.0022,
"cached": false,
"request_id": "0b7e6f1a-3c2d-4e5f-9a8b-1c2d3e4f5a6b"
}{
"success": true,
"type": "video",
"video_id": "CnQmoQD4xRM",
"country": "TR",
"data": {
"video_id": "CnQmoQD4xRM",
"title": "SEO Nedir? | Webtures",
"url": "https://www.youtube.com/watch?v=CnQmoQD4xRM",
"description": "SEO Nedir? Açılımı “Arama Motoru Optimizasyonu” olan SEO, firmalara ait olan web sitelerin…",
"channel_name": "Webtures",
"channel_url": "https://www.youtube.com/channel/UCKSAxJxwfIyHrcgJP12CoSg",
"channel_subscribers": 2420,
"views": 241552,
"likes": 83,
"comments": 30,
"published_at": "2021-02-10T20:17:24Z",
"duration_seconds": 179,
"category": "Science & Technology",
"tags": ["seo", "seo nedir", "arama motoru optimizasyonu"],
"is_live": false,
"transcripts": [
{ "language": "en-GB", "auto_generated": false },
{ "language": "tr", "auto_generated": false },
{ "language": "tr", "auto_generated": true }
]
},
"cost": 0.0066,
"cached": false,
"request_id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"
}{
"success": true,
"type": "transcript",
"video_id": "CnQmoQD4xRM",
"country": "TR",
"data": {
"video_id": "CnQmoQD4xRM",
"title": "SEO Nedir? | Webtures",
"language": "tr",
"translated_to": null,
"text": "SEO’yu bir yerden duymuş ya da zaten biliyor olabilirsiniz. SEO’nun nasıl çalıştığınız ve ne gibi faydalar sağladığını anlatmaya çalışacağım. …",
"segments": [
{ "start": 0.603, "end": 3.89, "text": "SEO’yu bir yerden duymuş ya da zaten biliyor olabilirsiniz." },
{ "start": 3.887, "end": 8.24, "text": "SEO’nun nasıl çalıştığınız ve ne gibi faydalar sağladığını anlatmaya çalışacağım." }
]
},
"cost": 0.0066,
"cached": false,
"request_id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d"
}{
"success": true,
"type": "comments",
"video_id": "CnQmoQD4xRM",
"country": "TR",
"total": 30,
"count": 1,
"limit": 1,
"items": [
{
"author": "@metehanbas890",
"author_url": "https://www.youtube.com/@metehanbas890",
"text": "SEO nedir veya nasıl yapılır. Çok açık bir şekilde anlatmışsınız. Video çok iyi olmuş.",
"likes": 3,
"replies": 0,
"published_at": "2021-11-05T21:18:13Z"
}
],
"cost": 0.0022,
"cached": false,
"request_id": "1e2d3c4b-5a6f-4e7d-8c9b-0a1f2e3d4c5b"
}Response Fields Reference
search row
| Field | Type | Description |
|---|---|---|
position | integer | Rank on the results page |
type | string | video, short, playlist, channel or ad |
title, url | string | Title and canonical link |
video_id | string | null | For videos, Shorts and ads |
channel_name, channel_url | string | null | The channel |
views | integer | null | View count (videos) |
video_count | integer | null | Videos in the playlist or channel |
published_at | string | null | Approximate publish time, ISO 8601 |
duration_seconds | integer | null | Length (videos) |
is_live | boolean | null | Live stream (videos) |
video → data
video_id, title, url, description, channel_name, channel_url, channel_subscribers, views, likes, comments, published_at (exact), duration_seconds, category, tags (the uploader's tags), is_live, and transcripts — each {language, auto_generated}; pass a language as transcript_language.
transcript → data
| Field | Type | Description |
|---|---|---|
language | string | null | Language of the transcript read |
translated_to | string | null | Target language when translate_to was sent |
text | string | The whole transcript as one string |
segments | array | {start, end, text}, times in seconds |
comments row
author, author_url, text, likes, replies, published_at. total in the envelope is the video's comment count.
Errors
Every error carries a stable code, a readable error, and retryable; where it helps also field, hint and allowed. Send Accept-Language: tr for Turkish messages. You are never charged for an error. The full list, shared with the other APIs, is on Error Codes. Specific to this endpoint:
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 202 | — | Not an error: still running after wait seconds | Poll GET /v1/tasks/{task_id}; see Tasks |
| 400 | KEYWORD_REQUIRED | type: "search" without a keyword | Send keyword |
| 400 | VIDEO_ID_REQUIRED | A video report without video_id | Send the ID or URL |
| 400 | INVALID_VIDEO_ID | Not an 11-character ID or a YouTube video URL | Copy the ID from the video's address |
| 400 | UNSUPPORTED_MARKET | Unknown country or search language | GET /v1/youtube/markets |
| 404 | VIDEO_NOT_FOUND | No such video, or it is private, removed or blocked in that country | Check the ID |
| 404 | TRANSCRIPT_NOT_FOUND | The video has no transcript in that language | type: "video" lists the languages it has |
| 400 | INVALID_PARAMETER | e.g. a translate_to language YouTube cannot translate into; field names it | Use another language |
{
"error": "This video has no transcript in the requested language",
"code": "TRANSCRIPT_NOT_FOUND",
"hint": "type=video lists the transcript languages a video has. You were not charged",
"retryable": false,
"request_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}{
"error": "'limit' cannot be used with type=video",
"code": "PARAMETER_NOT_ALLOWED",
"field": "limit",
"hint": "Accepted by type: comments, search",
"retryable": false
}Credits & Limits
| Request | Cost |
|---|---|
search or comments, up to 20 results | $0.0022 |
search or comments, 21–40 results | $0.0044 |
search, 200 results (maximum) | $0.022 |
video | $0.0066 |
transcript | $0.0066 |
The balance hold is the cost of limit; anything not used is refunded immediately. A search or comment list with no results is a valid answer, billed at one block.
Results are cached — search, video details and comments for 24 hours, transcripts for 30 days. A cached answer is marked "cached": true and billed at the same price as a live one.
Per-minute and per-day limits are set on your account (429 RATE_LIMIT_EXCEEDED). At most 10 requests per API user run at the same time; more get 429 TOO_MANY_CONCURRENT_REQUESTS with Retry-After. A request that has returned 202 keeps its place until its task finishes. At most 100 tasks per API user can be unfinished at once (429 TOO_MANY_PENDING_TASKS). Polling has its own limit and does not count against any of these; see Tasks.
