curl --request POST \
--url https://api.vidnavigator.com/v1/transcript \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"video_url": "https://twitter.com/user/status/123456789",
"language": "en",
"metadata_only": false,
"fallback_to_metadata": false,
"transcript_text": false,
"include_usage": false
}
'import requests
url = "https://api.vidnavigator.com/v1/transcript"
payload = {
"video_url": "https://twitter.com/user/status/123456789",
"language": "en",
"metadata_only": False,
"fallback_to_metadata": False,
"transcript_text": False,
"include_usage": False
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
video_url: 'https://twitter.com/user/status/123456789',
language: 'en',
metadata_only: false,
fallback_to_metadata: false,
transcript_text: false,
include_usage: false
})
};
fetch('https://api.vidnavigator.com/v1/transcript', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.vidnavigator.com/v1/transcript",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'video_url' => 'https://twitter.com/user/status/123456789',
'language' => 'en',
'metadata_only' => false,
'fallback_to_metadata' => false,
'transcript_text' => false,
'include_usage' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.vidnavigator.com/v1/transcript"
payload := strings.NewReader("{\n \"video_url\": \"https://twitter.com/user/status/123456789\",\n \"language\": \"en\",\n \"metadata_only\": false,\n \"fallback_to_metadata\": false,\n \"transcript_text\": false,\n \"include_usage\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.vidnavigator.com/v1/transcript")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"video_url\": \"https://twitter.com/user/status/123456789\",\n \"language\": \"en\",\n \"metadata_only\": false,\n \"fallback_to_metadata\": false,\n \"transcript_text\": false,\n \"include_usage\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.vidnavigator.com/v1/transcript")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"video_url\": \"https://twitter.com/user/status/123456789\",\n \"language\": \"en\",\n \"metadata_only\": false,\n \"fallback_to_metadata\": false,\n \"transcript_text\": false,\n \"include_usage\": false\n}"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"video_info": {
"title": "<string>",
"description": "<string>",
"thumbnail": "<string>",
"url": "<string>",
"channel": "<string>",
"channel_url": "<string>",
"duration": 123,
"views": 123,
"likes": 123,
"published_date": "<string>",
"keywords": [
"<string>"
],
"category": "<string>",
"available_languages": [
"<string>"
],
"selected_language": "<string>",
"carousel_info": {
"total_items": 123,
"video_count": 123,
"image_count": 123,
"selected_index": 123
}
},
"transcript": [
{
"text": "<string>",
"start": 123,
"end": 123
}
]
},
"usage": {
"charges": [
{
"service_type": "standard_request",
"quantity": 123,
"credits": 123,
"waived": true,
"credits_saved": 123,
"tokens": {
"prompt_tokens": 123,
"completion_tokens": 123,
"total_tokens": 123
}
}
],
"total_credits": 123,
"waived": {
"credits_saved": 123
}
}
}{
"status": "error",
"error": "<string>",
"message": "<string>"
}{
"status": "error",
"error": "limit_exceeded",
"message": "<string>"
}{
"status": "error",
"error": "content_restricted",
"message": "<string>"
}{
"status": "error",
"error": "video_not_found",
"message": "<string>"
}{
"status": "error",
"error": "limit_exceeded",
"message": "<string>",
"usage": 123,
"limit": 123
}{
"status": "error",
"error": "geo_restricted",
"message": "<string>"
}{
"status": "error",
"error": "metadata_fetch_failed",
"message": "<string>"
}Get Video Transcript
Extract transcript from any supported online video (YouTube, Vimeo, Twitter/X, TikTok, Facebook, Dailymotion, Loom, etc.) with optional language selection. The endpoint auto-detects the platform from the URL and routes internally.
The URL inside video_url is what determines the upstream behavior.
Note: for Instagram videos, use /transcribe instead (speech-to-text).
Options:
transcript_text=true: Returns the transcript as a single plain-text string instead of an array of segments.metadata_only=true: Returns only video metadata (no transcript).fallback_to_metadata=true: If transcript is unavailable, returns video metadata with an empty transcript instead of a 404 error (ignored whenmetadata_only=true).
Billing depends on the URL:
- YouTube (full transcript OR
metadata_only=true) → 1×residential_request(the transcript fetch routes through the residential proxy) - Non-YouTube → 1×
standard_request(some platforms internally use residential and would be billed accordingly)
The charge applies whether or not a transcript is returned (mirrors the proxy hop we paid for). Set include_usage=true to receive a usage block in the response.
curl --request POST \
--url https://api.vidnavigator.com/v1/transcript \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"video_url": "https://twitter.com/user/status/123456789",
"language": "en",
"metadata_only": false,
"fallback_to_metadata": false,
"transcript_text": false,
"include_usage": false
}
'import requests
url = "https://api.vidnavigator.com/v1/transcript"
payload = {
"video_url": "https://twitter.com/user/status/123456789",
"language": "en",
"metadata_only": False,
"fallback_to_metadata": False,
"transcript_text": False,
"include_usage": False
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
video_url: 'https://twitter.com/user/status/123456789',
language: 'en',
metadata_only: false,
fallback_to_metadata: false,
transcript_text: false,
include_usage: false
})
};
fetch('https://api.vidnavigator.com/v1/transcript', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.vidnavigator.com/v1/transcript",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'video_url' => 'https://twitter.com/user/status/123456789',
'language' => 'en',
'metadata_only' => false,
'fallback_to_metadata' => false,
'transcript_text' => false,
'include_usage' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.vidnavigator.com/v1/transcript"
payload := strings.NewReader("{\n \"video_url\": \"https://twitter.com/user/status/123456789\",\n \"language\": \"en\",\n \"metadata_only\": false,\n \"fallback_to_metadata\": false,\n \"transcript_text\": false,\n \"include_usage\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.vidnavigator.com/v1/transcript")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"video_url\": \"https://twitter.com/user/status/123456789\",\n \"language\": \"en\",\n \"metadata_only\": false,\n \"fallback_to_metadata\": false,\n \"transcript_text\": false,\n \"include_usage\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.vidnavigator.com/v1/transcript")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"video_url\": \"https://twitter.com/user/status/123456789\",\n \"language\": \"en\",\n \"metadata_only\": false,\n \"fallback_to_metadata\": false,\n \"transcript_text\": false,\n \"include_usage\": false\n}"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"video_info": {
"title": "<string>",
"description": "<string>",
"thumbnail": "<string>",
"url": "<string>",
"channel": "<string>",
"channel_url": "<string>",
"duration": 123,
"views": 123,
"likes": 123,
"published_date": "<string>",
"keywords": [
"<string>"
],
"category": "<string>",
"available_languages": [
"<string>"
],
"selected_language": "<string>",
"carousel_info": {
"total_items": 123,
"video_count": 123,
"image_count": 123,
"selected_index": 123
}
},
"transcript": [
{
"text": "<string>",
"start": 123,
"end": 123
}
]
},
"usage": {
"charges": [
{
"service_type": "standard_request",
"quantity": 123,
"credits": 123,
"waived": true,
"credits_saved": 123,
"tokens": {
"prompt_tokens": 123,
"completion_tokens": 123,
"total_tokens": 123
}
}
],
"total_credits": 123,
"waived": {
"credits_saved": 123
}
}
}{
"status": "error",
"error": "<string>",
"message": "<string>"
}{
"status": "error",
"error": "limit_exceeded",
"message": "<string>"
}{
"status": "error",
"error": "content_restricted",
"message": "<string>"
}{
"status": "error",
"error": "video_not_found",
"message": "<string>"
}{
"status": "error",
"error": "limit_exceeded",
"message": "<string>",
"usage": 123,
"limit": 123
}{
"status": "error",
"error": "geo_restricted",
"message": "<string>"
}{
"status": "error",
"error": "metadata_fetch_failed",
"message": "<string>"
}video_url and routes internally. (The old /youtube/transcript endpoint has been merged into /transcript.)Billing
Billing depends on the URL:- YouTube (full transcript or
metadata_only: true) → 1×residential_request(the fetch routes through the residential proxy). - Non-YouTube → 1×
standard_request(some platforms internally require residential and are billed asresidential_requestaccordingly).
include_usage: true to receive a usage block in the response.
Overview
This endpoint automatically extracts rich video metadata and transcripts from online videos with high accuracy.Supported Platforms
VidNavigator can retrieve transcripts from a wide variety of sources. Below is the list of platforms currently supported by this endpoint:- YouTube (uses residential proxy infrastructure for reliable access)
- X / Twitter (just copy the tweet video link)
- Facebook (public videos only)
- TikTok
- Dailymotion
- Loom
- Vimeo
Use Cases
Content Analysis
Search & Discovery
Accessibility
Content Creation
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
video_url | string | Yes | URL of the video to retrieve the transcript for (YouTube or any other supported platform) |
language | string | No | ISO2 language code (e.g., “en”, “es”, “fr”) |
metadata_only | boolean | No | When true, returns only video metadata without fetching the transcript. Takes precedence over fallback_to_metadata. Usage is still recorded. |
fallback_to_metadata | boolean | No | When true, returns video metadata with an empty transcript if transcript is unavailable (returns 200 instead of 404). Ignored if metadata_only is true. |
transcript_text | boolean | No | When true, returns the transcript as a single plain-text string instead of an array of segments. |
include_usage | boolean | No | When true, the response includes a usage block listing every meter charged during this request, the total credits deducted, and the remaining balance. |
Example Usage
curl -X POST "https://api.vidnavigator.com/v1/transcript" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"language": "en"
}'
import requests
url = "https://api.vidnavigator.com/v1/transcript"
headers = {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
data = {
"video_url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"language": "en"
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
const response = await fetch('https://api.vidnavigator.com/v1/transcript', {
method: 'POST',
headers: {
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
video_url: 'https://youtube.com/watch?v=dQw4w9WgXcQ',
language: 'en'
})
});
const result = await response.json();
Transcript as Plain Text (transcript_text=true)
Use transcript_text=true to return the transcript as a single plain-text string instead of an array of { text, start, end } segments:
curl -X POST "https://api.vidnavigator.com/v1/transcript" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_url": "https://twitter.com/user/status/123456789",
"transcript_text": true
}'
Getting Metadata Only
If you only need video metadata without the transcript (faster and still counts as usage):curl -X POST "https://api.vidnavigator.com/v1/transcript" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_url": "https://www.tiktok.com/@user/video/123456789",
"metadata_only": true
}'
data = {
"video_url": "https://www.tiktok.com/@user/video/123456789",
"metadata_only": True
}
response = requests.post(url, headers=headers, json=data)
const result = await fetch('https://api.vidnavigator.com/v1/transcript', {
method: 'POST',
headers: {
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
video_url: 'https://www.tiktok.com/@user/video/123456789',
metadata_only: true
})
});
metadata_only: true still routes through the residential proxy and is billed as a residential_request.Getting Usage Disclosure (include_usage=true)
Set include_usage: true to receive a usage block describing exactly what was charged:
{
"status": "success",
"data": { "video_info": { ... }, "transcript": [ ... ] },
"usage": {
"charges": [
{ "service_type": "residential_request", "quantity": 1, "credits": 0.005 }
],
"total_credits": 0.005
}
}
Limitations
https://fb.watch/<video_id>format is not supported, use thehttps://www.facebook.com/watch/?v=<video_id>format instead.
Troubleshooting
- Invalid URL: Ensure the video URL is complete and valid. This endpoint supports direct links from YouTube, X (a tweet), Vimeo, TikTok, etc.
- Transcript Not Found: Please ensure that the video has subtitles available (either manually added or auto-generated). If no subtitles are present, the transcript cannot be extracted. Consider using
fallback_to_metadata: trueto get metadata even when transcript is unavailable. - Language Not Supported: Sometimes the selected subtitles language is not available. In which case, you will get a clear message stating that. Verify that the chosen language is available for the video. We recommend not using the language input if you are unsure.
- For Instagram videos: This endpoint does not transcribe Instagram. Please use the /transcribe endpoint instead.
Success Response (200 OK)
Returns avideo_info object and a transcript object.
{
"status": "success",
"data": {
"video_info": {
"title": "A Really Cool Video",
"description": "An example description for the video.",
"thumbnail": "https://example.com/thumbnail.jpg",
"url": "https://twitter.com/user/status/123456789",
"channel": "Example Creator",
"duration": 45.5,
"views": 123456,
"likes": 9876,
"published_date": "2024-01-15",
"keywords": ["example", "twitter", "video"],
"category": "Entertainment"
},
"transcript": [
{
"text": "This is the first sentence of the video.",
"start": 0.5,
"end": 3.2
},
{
"text": "And this is the second sentence.",
"start": 3.5,
"end": 5.1
}
]
}
}
Response with transcript_text: true
When you set transcript_text: true, the transcript is returned as a single string:
{
"status": "success",
"data": {
"video_info": { ... },
"transcript": "This is the first sentence of the video. And this is the second sentence."
}
}
Response with metadata_only: true
When you set metadata_only: true, only the video metadata is returned:
{
"status": "success",
"data": {
"video_info": {
"title": "A Really Cool Video",
"description": "An example description for the video.",
"thumbnail": "https://example.com/thumbnail.jpg",
"url": "https://twitter.com/user/status/123456789",
"channel": "Example Creator",
"duration": 45.5,
"views": 123456,
"likes": 9876,
"published_date": "2024-01-15"
}
}
}
Authorizations
API key authentication. Include your VidNavigator API key in the X-API-Key header.
Body
URL of the video to retrieve transcript for
"https://twitter.com/user/status/123456789"
ISO2 language code (optional)
2"en"
When true, returns only video metadata without transcript. Usage is still recorded.
When true, returns video metadata with an empty transcript if transcript is unavailable (200). Ignored if metadata_only is true.
When true, returns the transcript as a single plain-text string instead of an array of segments.
When true, the response includes a usage block listing every meter charged during this request, the total credits deducted, and the user's remaining balance.
Response
Transcript retrieved successfully
success Show child attributes
Show child attributes
Per-call usage disclosure. Returned only when the caller passes include_usage=true in the request body. Lists every meter that fired during this request and the credits actually deducted. Multiple charges of the same meter inside one request are consolidated into a single entry (their quantities and credits are summed). When a charge was waived through a cache-hit sponsorship (e.g. NGO), it carries waived: true + credits_saved, and a top-level waived.credits_saved summary appears.
For endpoints that involve LLM analysis (/extract/video, /extract/file, /analyze/video, /analyze/file, /youtube/search), the consolidated analysis_request charge entry carries a nested tokens object reporting the LLM input/output token tally for the request.
Show child attributes
Show child attributes

