Try it
Run a live video search
One real call against the API, no signup and no key. The panel shows the result twice: as a video results page and as JSON.
The rendered view carries each video's thumbnail with its duration badge, the publisher, the view count and the description. The JSON beside it is the exact response your code receives.
Endpoints & Pricing
Three Ways to Get Video Data
The dedicated endpoint for the ranked video list, the video block inside a web result page, and the same video call submitted as a batch job. Pricing is per category, so the engine you pick never changes what a call costs.
/api/videos
- The ranked video list, with a
positionper row - Eleven fields on every row, always present
duration,resolution,freshnessandsafefilters- Targeting on 112 country codes, five engines
Videos in a web SERP
results.videoson a Deep Search callmetadata.hasVideossays whether the page carried one- Billed at the Web rate, not the Videos rate
- Tells you a video block ranked, not who ranked in it
Video jobs in bulk
serp_videositems onPOST /api/bulk/jobs- A single submission carries up to 200 items
- Same parameters and same body as the live call
GET /api/statuslists the job types live for your key
Growth unlocks at a single $100 deposit and Scale at a single $500 deposit. Free to start on eligible endpoints, with the allowance shared across them.
Video stats on ordinary organic rows
A video that ranks in the web results is still a video, and until you know its view count and its age you cannot tell whether it is a serious competitor or an old upload coasting on authority. Add include_video_stats=true to a /api/search or /api/search/quick call and every organic row ends with four more keys — views, publishedTime, duration and publisher — populated on video results and null on every other row. Paid plans, and it costs nothing extra: the call bills at its normal Web rate. Leave the flag off and the response is byte-for-byte what it was before the parameter existed.
{
"organic": [
{
"position": 3,
"url": "https://www.youtube.com/watch?v=…",
"views": 1240000,
"publishedTime": "2026-01-14",
"duration": "12:45",
"publisher": "Dev Tutorials"
}
]
}
Abbreviated — title, snippet and displayedUrl are on the row too. The four video keys come last.
Quick Start
Search Videos in One Request
One path, one header, one query parameter to change the engine. The response shape does not move between engines, so a second engine is a copy of the call you already have.
# The ranked video list for a keyword curl "https://apiserpent.com/api/videos?q=react+hooks+tutorial&engine=google&country=us&num=20" \ -H "X-API-Key: YOUR_API_KEY" # Long-form only, published in the last month, brand-safe curl "https://apiserpent.com/api/videos?q=react+hooks+tutorial&engine=ddg&duration=long&time=month&safe=strict" \ -H "X-API-Key: YOUR_API_KEY" # Just the ranking: position, title, url, duration and nothing else curl "https://apiserpent.com/api/videos?q=react+hooks+tutorial&engine=yahoo&resolution=720p&format=simple" \ -H "X-API-Key: YOUR_API_KEY"
{
"success": true,
"query": "react hooks tutorial",
"type": "videos",
"engine": "google",
"country": "us",
"results": {
"videos": [
{
"position": 1,
"title": "React Hooks — The Complete Guide",
"url": "https://www.youtube.com/watch?v=example123",
"duration": "12:45",
"source": "www.youtube.com",
"views": 1240000,
"thumbnail": "https://i.ytimg.com/vi/example123/hqdefault.jpg",
"description": "Every hook, in the order you should learn them.",
"publisher": "Dev Tutorials",
"embedUrl": "https://www.youtube.com/embed/example123",
"publishedTime": "2026-01-14"
}
],
"totalResults": 20
},
"meta": {
"totalVideos": 20,
"elapsed": "3800ms",
"timestamp": "2026-09-07T10:47:33.000Z"
}
}
Note the two values you would otherwise have written a parser for: views arrives as 1240000, not as the string "1.2M views", and publishedTime arrives as 2026-01-14, not as "8 months ago". Sorting by view count or bucketing by age is arithmetic, not string handling.
Data Fields
Every Field a Video Call Returns
Eleven keys per row, in a fixed order, on every engine. Nothing here needs a parser of your own, and nothing changes shape between calls.
results.videos[]
- position — integer
- title — string | null
- url — string | null
- duration — string | null
- source — string | null
- views — number | null
- thumbnail — string | null
- description — string | null
- publisher — string | null
- embedUrl — string | null
- publishedTime — string | null
- totalResults — integer
Request parameters
- q — the search query
- engine — google, yahoo, bing, ddg (default), brave
- country — 112 codes, default us
- num — a ceiling on the list returned
- duration — short, medium, long
- resolution — see the filter cards below
- freshness — h, d, w, m, y
- time — day, week, month, year
- safe — off, moderate, strict
- format — full or simple
- timeout — seconds you will wait
What the values mean
position is the 1-based rank inside the list you were handed and never skips a number, which is what makes a position log safe to diff week over week.
source is the host the video is served from, such as www.youtube.com, so you can measure how much of a query's video surface sits on one platform. publisher is the uploader's channel name, never the platform word: a row that names only the platform returns null, because the platform is already in source.
When a call comes back short
num is a ceiling, not a promise. It caps the list; what fills it is however many videos the result page ranks for that query.
When fewer rows arrive than you asked for, the response says so instead of leaving you to count. A top-level delivery block carries requested, returned, a short reason and a plain-English note, plus an async_endpoint pointer where the batch form can finish the job; meta.partialResults carries the same numbers. The field set never changes on a short answer.
Why video search data
What is video SERP data, and why teams use it
Video is the one search surface where your asset almost never lives on your own domain, so the questions you can ask of it are different — and so is the data you need to answer them.
Video results are their own ranking surface
A page can hold position 3 in web results and be absent from the video results for the same keyword. The two lists are filled by different assets, judged on different signals, and dominated by different names — usually channels, not domains.
That makes a web rank tracker blind to half your visibility on any query with video intent. /api/videos returns the video list itself, with position on every row, so you can track it the same way you track the blue links.
The numbers arrive as numbers
Video metadata is displayed for humans: 1.2M views, 8 months ago, Streamed 2 years ago. Every one of those is a parsing job, and every one of them is a place a rounding rule can quietly cost you a factor of a thousand.
Here views is 1240000 and publishedTime is 2026-01-14. "Median views in the top ten" and "median age of a ranking video" become one expression instead of a parser you have to maintain.
Eleven keys, always present, one order
Every row carries all eleven keys whether or not the result had a value for each. A missing value is null; it is never a missing key, and the order never changes between calls or between engines.
So you write one parser and point it at any engine, and a row that arrives thin cannot throw a KeyError in the middle of a nightly run. Adding a second engine to a working integration is a single query parameter.
Filters that match how video is judged
Runtime, upload date and safety are ranking-relevant on video in a way they are not on web search, so they are first-class request parameters: duration, resolution, freshness (or its time alias) and safe.
Run the same keyword at duration=short and again at duration=long and you can see which runtime the surface is actually rewarding before you brief a single edit.
Filters
Narrow the List Before You Pay for It
Six request parameters, all optional, all validated. A value outside the accepted set returns a 400 naming the parameter at fault rather than quietly serving you the unfiltered list.
duration
short, medium or long on ddg, yahoo and bing. The one filter that answers a content question directly: which runtime ranks for this keyword?
resolution
high or standard on ddg; 360p, 480p, 720p, hd or 1080p on yahoo and bing. A request filter, not a returned field.
freshness
Last hour, day, week, month or year: h, d, w, m, y, and the 1h, 1d, 7d, 1m, 1y spellings the other endpoints use.
time
An alias for freshness in words: day, week, month, year. Send both and freshness wins, because it is the finer-grained of the two.
safe
off, moderate or strict. Video is a user-generated surface, so this is the parameter that decides whether a feed is safe to render on your own site.
country
112 codes, default us. The ranked video set moves more between markets than the web list does, so a single locale is rarely the whole picture.
Use cases
What Teams Actually Pull Video Results For
Four jobs that account for most video search traffic, and the fields each one needs.
Video rank tracking for a channel
On video you track a name, not a domain, because your asset sits on someone else's host. Match on publisher across your keyword list and log the position it holds.
One call per keyword, at the flat Videos rate. Run it nightly and you have the same time series you keep for web rankings, on the surface a web rank tracker cannot see.
Share of the video surface
Group the rows for a keyword set by publisher and by source and you get two numbers that matter to a category owner: which channels hold the video results, and how much of the surface sits on one platform.
Both fields are on every row, so the whole analysis is one pass over the responses you already stored.
Content planning from what already ranks
Before commissioning a video, read the set that ranks today: the median views is the bar to clear, the spread of publishedTime says whether the query is churny or settled, and duration says what length is being rewarded.
Because views is a number and publishedTime is a date, those three answers are a single aggregation rather than a parsing project.
Video feeds and embeds in your own product
A results row carries everything a card needs: thumbnail, duration, title, publisher, views, publishedTime and an embedUrl for the player. No second lookup per video.
Pair it with safe=strict before anything renders on a page your customers see, and with freshness when the feed is meant to look current.
# One line per keyword: date, keyword, your channel's best video position (0 if unranked). # On video you match the channel name, not your domain — the video is not hosted by you. CHANNEL="Dev Tutorials" while IFS= read -r kw; do pos=$(curl -s -G "https://apiserpent.com/api/videos" \ --data-urlencode "q=$kw" \ -d "engine=google" -d "country=us" -d "num=30" \ -H "X-API-Key: $SERPENT_KEY" \ | jq -r --arg c "$CHANNEL" \ '[.results.videos[] | select(.publisher == $c)][0].position // 0') echo "$(date -u +%F),$kw,$pos" >> video-positions.csv done < keywords.txt
# The bar to clear for one keyword: median view count, oldest and newest upload, # and how many of the ranking videos come from one host. curl -s -G "https://apiserpent.com/api/videos" \ --data-urlencode "q=react hooks tutorial" \ -d "engine=google" -d "country=us" -d "num=20" \ -H "X-API-Key: $SERPENT_KEY" \ | jq '{ ranked: (.results.videos | length), median_views: ([.results.videos[].views | numbers] | sort | .[(length / 2) | floor]), oldest: ([.results.videos[].publishedTime | strings] | min), newest: ([.results.videos[].publishedTime | strings] | max), by_host: (.results.videos | group_by(.source) | map({(.[0].source // "unknown"): length}) | add) }'
Both snippets run against a live key and use only fields listed above. numbers and strings in the jq filters skip the rows where a value was null, which is why the always-present-key rule matters in practice.
FAQ
Video Search API Questions
position, title, url, duration, source, views, thumbnail, description, publisher, embedUrl and publishedTime. views is a number, not a display string. publishedTime is a date in YYYY-MM-DD form. source is the host the video is served from, such as www.youtube.com, and publisher is the uploader's channel name; a row that names only the platform returns null there, because the platform is already in source. Every key is always present, so a value the result did not carry comes back as null rather than as a missing key.
google, yahoo, bing, ddg and brave all bill at the Videos rate. Free to start on eligible endpoints, and video search is one of them.
num is a ceiling, not a promise. It caps the list you receive; what fills that list is however many videos the result page actually ranks for your query, and in measurement a single call has returned roughly 50 to 60 videos at the maximum. When fewer rows come back than you asked for, the response says so rather than leaving you to count: a top-level delivery block carries requested, returned, a short reason and a plain-English note, and meta.partialResults carries the same numbers. Nothing about the field set changes on a short answer.
duration takes short, medium or long on ddg, yahoo and bing. resolution takes high or standard on ddg, or 360p, 480p, 720p, hd and 1080p on yahoo and bing. freshness narrows to the last hour, day, week, month or year (h, d, w, m, y, and the 1h, 1d, 7d, 1m, 1y spellings), and time is an alias that accepts day, week, month and year; if both are sent, freshness wins because it is the finer-grained of the two. safe takes off, moderate or strict. A value outside the accepted set returns a 400 naming the parameter at fault. duration is also a returned field; resolution is a request filter only.
embedUrl is an embeddable player URL where the result carries one, and null where it does not, so you can render a player without a second lookup. thumbnail is a direct image URL: for a YouTube video it is always that video's own YouTube thumbnail, on every engine, so the same video gives you the same image whichever engine you asked; for any other video it is the thumbnail the result carries when there is one, and null otherwise. Rendering a card needs no extra call: title, duration, publisher, views and publishedTime are all on the same row.
country accepts 112 codes and defaults to us, which matters more on video than on web search because the ranked set shifts substantially between markets. language is not accepted on /api/videos: send it and it is ignored rather than rejected, so do not build a localisation strategy on it. Use country, and use the web, news or image endpoints when you need a language code.
Start using the Video Search API
free API calls, no card. Video search from $0.07 per 1,000 calls on Google, Yahoo, Bing, DuckDuckGo and Brave.
Try for Free

