YouTube Scraper API
View as MarkdownScrape YouTube search results, channels, playlists, and Shorts shelves as structured JSON — with up to 30 videos in a single request

The YouTube API is a specialized plugin that searches YouTube and returns structured JSON for the search result page: videos, channels, playlists, Shorts shelves, ads, and the "people also watched" / "related searches" rails. One HTTP call — and with the num parameter, one call can return up to 30 videos. No JavaScript rendering. No render fee.
Credit Usage: Each successful request costs 10 credits at the same flat rate even when num pages internally. Deeper browsing uses the sp continuation token that comes back in pagination.next_page_token.
Key Features
- Structured JSON Output: Typically 15–20 video results per page plus channels, playlists, Shorts shelves, ads, and discovery rails (
people_also_watched,from_related_searches,channels_new_to_you,explore_more). - Up to 30 Videos per Request: Set
num(1–30) and the plugin pages internally until it holds exactly that many videos — one call, one flat cost. - Result Type Filters:
sptokens for videos-only, channels-only, or playlists-only — switches the populated array. - Sort Modes: relevance (default), rating, upload date, view count.
- Duration Filters: under 4 minutes, 4–20 minutes, over 20 minutes.
- Feature Filters: 4K, HD, LIVE, closed captions.
- Upload Date Filters: last hour, today, this week, this month, this year.
- Localization:
hlcontrols UI language (published-date, duration, view-count strings);glinfluences ranking and shelf eligibility. - Device Emulation: Desktop or mobile layout via
device. - Pagination: Single
spparameter doubles as filter token and continuation cursor — the plugin routes them automatically. Or skip manual paging entirely withnum. - No Blocks or CAPTCHAs: Anti-bot is handled by Scrape.do.
Endpoint
GET https://api.scrape.do/plugin/google/youtubeRequest Parameters
Required
| Parameter | Type | Description |
|---|---|---|
token | string | Your Scrape.do API authentication token |
search_query | string | Search terms (e.g., best laptop 2025, macbook pro m3). Alias: q |
Localization
| Parameter | Type | Default | Description |
|---|---|---|---|
hl | string | en | Interface language (en, de, fr, ja, tr, es, …). Controls published_date, length, and views text. |
gl | string | us | Country code (us, gb, de, fr, jp, …). Influences ranking and which shelves appear. |
For the cleanest locale experience, match hl to gl (e.g., hl=de&gl=de).
Device
| Parameter | Type | Default | Description |
|---|---|---|---|
device | string | desktop | desktop or mobile. Mobile returns the mobile layout. |
Filters & Sort
| Parameter | Type | Default | Description |
|---|---|---|---|
sp | string | — | YouTube's opaque token. Short values control sort / result type / duration / features / upload date. Long values are continuation cursors emitted in pagination.next_page_token. The plugin routes both automatically. See Common sp Values. |
Pagination & Result Count
| Parameter | Type | Default | Description |
|---|---|---|---|
num | integer | — | How many video_results you want back from a single request (1–30). Without it, a request returns one page — typically 15–20 videos. With it, the plugin keeps reading further pages internally until it holds num videos, then trims to exactly that many. Cannot be combined with sp. |
Example Usage
Basic search
curl --location --request GET 'https://api.scrape.do/plugin/google/youtube?token=<SDO-token>&search_query=best+laptop+2025'import requests
import json
token = "<SDO-token>"
url = f"https://api.scrape.do/plugin/google/youtube?token={token}&search_query=best+laptop+2025"
response = requests.request("GET", url)
print(json.dumps(response.json(), indent=2))const axios = require('axios');
const token = "<SDO-token>";
const url = `https://api.scrape.do/plugin/google/youtube?token=${token}&search_query=best+laptop+2025`;
axios.get(url)
.then(response => {
console.log(JSON.stringify(response.data, null, 2));
})
.catch(error => {
console.error(error);
});package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
token := "<SDO-token>"
url := fmt.Sprintf(
"https://api.scrape.do/plugin/google/youtube?token=%s&search_query=best+laptop+2025",
token,
)
resp, err := http.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}require 'net/http'
require 'json'
token = "<SDO-token>"
url = URI("https://api.scrape.do/plugin/google/youtube?token=#{token}&search_query=best+laptop+2025")
response = Net::HTTP.get(url)
puts JSON.pretty_generate(JSON.parse(response))import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class YouTubeSearch {
public static void main(String[] args) throws Exception {
String token = "<SDO-token>";
String url = String.format(
"https://api.scrape.do/plugin/google/youtube?token=%s&search_query=best+laptop+2025",
token
);
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("GET");
BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream())
);
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
System.out.println(response.toString());
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
string token = "<SDO-token>";
string url = $"https://api.scrape.do/plugin/google/youtube?token={token}&search_query=best+laptop+2025";
using HttpClient client = new HttpClient();
string response = await client.GetStringAsync(url);
Console.WriteLine(response);
}
}<?php
$token = "<SDO-token>";
$url = "https://api.scrape.do/plugin/google/youtube?token={$token}&search_query=best+laptop+2025";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo json_encode(json_decode($response), JSON_PRETTY_PRINT);
?>curl "https://api.scrape.do/plugin/google/youtube?search_query=best+laptop+2025&token=YOUR_TOKEN"25 videos in one request
curl "https://api.scrape.do/plugin/google/youtube?search_query=best+laptop+2025&num=25&token=YOUR_TOKEN"The plugin reads YouTube's result feed internally until it holds 25 videos, then trims to exactly that many. See Result Count (num) for what changes on this path.
German locale
curl "https://api.scrape.do/plugin/google/youtube?search_query=beste+laptop+2025&hl=de&gl=de&token=YOUR_TOKEN"published_date, length, and view-count strings render in German.
Sort by view count
curl "https://api.scrape.do/plugin/google/youtube?search_query=best+laptop+2025&sp=CAM%3D&token=YOUR_TOKEN"Channels only
curl "https://api.scrape.do/plugin/google/youtube?search_query=tech+reviewer&sp=EgIQAg%3D%3D&token=YOUR_TOKEN"Populates channel_results[] instead of videos.
Playlists only
curl "https://api.scrape.do/plugin/google/youtube?search_query=learn+golang&sp=EgIQAw%3D%3D&token=YOUR_TOKEN"Populates playlist_results[].
Long-form videos (over 20 minutes)
curl "https://api.scrape.do/plugin/google/youtube?search_query=podcast+interview&sp=EgIYAg%3D%3D&token=YOUR_TOKEN"4K videos only
curl "https://api.scrape.do/plugin/google/youtube?search_query=nature+documentary&sp=EgJwAQ%3D%3D&token=YOUR_TOKEN"Live now
curl "https://api.scrape.do/plugin/google/youtube?search_query=formula+1&sp=EgJAAQ%3D%3D&token=YOUR_TOKEN"Mobile layout
curl "https://api.scrape.do/plugin/google/youtube?search_query=workout+videos&device=mobile&token=YOUR_TOKEN"Pagination
# Page 1
curl "https://api.scrape.do/plugin/google/youtube?search_query=best+laptop+2025&token=YOUR_TOKEN"
# → response includes pagination.next_page_token = "EqwDEhBiZXN0..."
# Page 2: pass that token as sp
curl "https://api.scrape.do/plugin/google/youtube?search_query=best+laptop+2025&sp=EqwDEhBiZXN0...&token=YOUR_TOKEN"The same sp parameter handles both filters and continuation tokens. Short values filter; long values paginate.
Response
Top-Level Structure
{
"search_parameters": { ... },
"search_information": { ... },
"ads_results": [ ... ],
"video_results": [ ... ],
"channel_results": [ ... ],
"playlist_results": [ ... ],
"shorts_results": [ ... ],
"people_also_watched": [ ... ],
"people_also_search_for": [ ... ],
"channels_new_to_you": [ ... ],
"from_related_searches": [ ... ],
"explore_more": [ ... ],
"related_searches": [ ... ],
"pagination": { ... }
}Collections that have no items for a given query are omitted. The one exception is video_results, which is always present — returns [] when empty.
search_parameters
Echo of the request.
{
"engine": "google_youtube",
"search_query": "best laptop 2025",
"gl": "us",
"hl": "en"
}sp and num appear only when set.
search_information
{ "total_results": 16406969 }| Field | Type | Description |
|---|---|---|
total_results | integer | YouTube's estimated total. May be 0 on some continuation pages. |
video_results_state | string | Status label (e.g., when YouTube auto-corrects spelling). Present only when set. |
video_results[]
Always present. Returns [] when no videos are found.
{
"position_on_page": 2,
"title": "The Best Laptops of 2025",
"link": "https://www.youtube.com/watch?v=PKshhTHyoZU",
"video_id": "PKshhTHyoZU",
"channel": {
"name": "Just Josh",
"link": "https://www.youtube.com/@JustJoshTech",
"verified": true,
"thumbnail": "https://yt3.ggpht.com/..."
},
"published_date": "4 months ago",
"views": 313829,
"length": "12:38",
"description": "Save BIG on Your Laptop: ...",
"extensions": ["4K"],
"thumbnail": {
"static": "https://i.ytimg.com/vi/PKshhTHyoZU/hqdefault.jpg",
"rich": "https://i.ytimg.com/an/PKshhTHyoZU/..."
},
"live": false
}| Field | Type | Always | Description |
|---|---|---|---|
position_on_page | integer | yes | 1-based position |
title | string | yes | Video title |
link | string | yes | Canonical watch URL |
video_id | string | yes | YouTube video id |
channel.name | string | Channel display name | |
channel.link | string | Channel URL | |
channel.verified | bool | true when the channel has a verified badge | |
channel.thumbnail | string | Channel avatar URL | |
published_date | string | Human-readable age, localized to hl ("4 months ago", "vor 4 Monaten") | |
views | integer | View count parsed to integer (47,427 → 47427, 1.2M → 1200000) | |
views_original | string | The view-count string exactly as YouTube rendered it. Present when YouTube reports an abbreviated count ("649K views") instead of an exact one — currently the num path | |
length | string | Duration ("12:38", "1:05:22") | |
description | string | Snippet text shown under the result | |
extensions | string[] | Badges ("4K", "LIVE", "New", "CC") | |
thumbnail.static | string | Static thumbnail URL | |
thumbnail.rich | string | Animated preview URL when YouTube provides one | |
live | bool | true when the video is a live stream |
channel_results[]
Populated when the query surfaces channel cards — most often with sp=EgIQAg== (Channels filter).
{
"position_on_page": 2,
"title": "Just Josh",
"link": "https://www.youtube.com/@JustJoshTech",
"verified": true,
"handle": "@JustJoshTech",
"subscribers": 379000,
"description": "Finding You The Best Laptop!",
"thumbnail": "https://yt3.ggpht.com/..."
}| Field | Type | Description |
|---|---|---|
position_on_page | integer | 1-based position |
title | string | Channel display name |
link | string | Channel URL |
verified | bool | Verified badge |
handle | string | @handle slug |
subscribers | integer | Subscriber count parsed to integer |
description | string | Channel description snippet |
thumbnail | string | Channel avatar URL |
playlist_results[]
Populated when the query surfaces playlist cards — most often with sp=EgIQAw== (Playlists filter).
{
"position_on_page": 2,
"title": "Best Gaming Laptops 2025",
"link": "https://www.youtube.com/playlist?list=PLFBbwFM8jIbOfpMghQOpdS8E8tJMweb3h",
"channel": {
"name": "Jarrod'sTech",
"link": "https://www.youtube.com/@JarrodsTech"
},
"videos": [
{ "link": "https://www.youtube.com/watch?v=zqjHX_WSyz8&list=PLFBbwFM8jIbOfpMghQOpdS8E8tJMweb3h" }
],
"video_count": 23,
"thumbnail": "https://i.ytimg.com/vi/zqjHX_WSyz8/hq720.jpg"
}| Field | Type | Description |
|---|---|---|
position_on_page | integer | 1-based position |
title | string | Playlist title |
link | string | Playlist URL |
channel.name | string | Uploader display name |
channel.link | string | Uploader channel URL |
videos | object[] | Preview videos. Each entry carries title, length, link when available |
video_count | integer | Total video count on the playlist badge |
thumbnail | string | Playlist cover thumbnail |
shorts_results[]
Array of Shorts shelves. Each shelf is a block that renders inline among regular video results.
{
"position_on_page": 5,
"shorts": [
{
"title": "Top 3 Laptops",
"link": "https://www.youtube.com/shorts/abc123",
"thumbnail": "https://i.ytimg.com/vi/abc123/oardefault.jpg",
"views_original": "2.1M",
"views": 2100000,
"video_id": "abc123"
}
]
}ads_results[]
Promoted entries that appeared on the page.
{
"position_on_page": 1,
"title": "Microsoft® Surface",
"link": "https://www.googleadservices.com/pagead/aclk?...",
"website": "https://www.googleadservices.com/pagead/aclk?...",
"channel": {
"name": "Microsoft",
"thumbnail": "https://lh3.googleusercontent.com/..."
},
"description": "Discover the new Surface lineup.",
"thumbnail": {
"static": "https://lh3.googleusercontent.com/..."
}
}Discovery Rails
Each rail is an array of the same shape as video_results[]. Present only when YouTube renders the corresponding shelf.
| Field | Renders when |
|---|---|
people_also_watched | "People also watched" shelf |
people_also_search_for | "People also search for" shelf (video items) |
channels_new_to_you | "Channels new to you" shelf |
from_related_searches | "From related searches" shelf |
explore_more | "Explore more" / "Latest from" shelf |
related_searches
Keyword refinement chips rendered above results.
[
{ "query": "best laptop 2025 under 1000" },
{ "query": "best gaming laptop 2025" }
]pagination
Present on every response that YouTube advertises a continuation for. Never returned when num is set — the plugin consumes the cursor internally.
{
"current": "https://www.youtube.com/results?gl=us&hl=en&search_query=best+laptop+2025",
"next": "https://www.youtube.com/results?gl=us&hl=en&search_query=best+laptop+2025&sp=EqwDEhBiZXN0...",
"next_page_token": "EqwDEhBiZXN0..."
}| Field | Type | Description |
|---|---|---|
current | string | The URL the plugin fetched for this page |
next | string | Ready-to-inspect URL for the next page |
next_page_token | string | Raw continuation token. Pass this back as sp on a new request |
Result Count (num)
Set num to pull up to 30 videos from a single request instead of one page. The plugin reads YouTube's result feed until it holds num videos, deduplicates them by video_id, and numbers position_on_page from 1 with no gaps.
What changes on the num path:
- Only videos come back.
shorts_results,channel_results,playlist_results, andads_resultsare not returned, and neither ispagination— the plugin consumes the continuation cursor internally. - Recommendation shelves don't count toward
num. Videos frompeople_also_watched,people_also_search_for,from_related_searches,channels_new_to_you, andexplore_morestill land in their own buckets and are never counted. - Lighter metadata. The wide result feed carries no
descriptionsnippet and reports view counts rounded:649K views→views: 649000, with the original string inviews_original. Omitnumwhen you need snippet text or exact view counts. - Truncation is flagged. If YouTube's feed runs dry or the internal page budget is reached first, you get fewer than
numvideos plus the response headerScrape.do-Auto-Page-Truncated: true. Re-issue the request withoutnumand page manually withspfrom there. - Some queries top out early. Queries YouTube answers mostly with music, mixes, or playlists (e.g.
lofi hip hop playlist) legitimately return only a handful of videos no matter how highnumis.
Common sp Values
sp is YouTube's opaque filter / sort / pagination token. Short values control filters and sort; long values are continuation cursors emitted in pagination.next_page_token. The plugin accepts both.
Sort Order
sp | Effect |
|---|---|
| (omit) | Relevance (default) |
CAE%3D | Sort by rating |
CAI%3D | Sort by upload date (newest first) |
CAM%3D | Sort by view count |
Result Type
sp | Effect |
|---|---|
EgIQAQ%3D%3D | Videos only |
EgIQAg%3D%3D | Channels only → populates channel_results |
EgIQAw%3D%3D | Playlists only → populates playlist_results |
Duration
sp | Effect |
|---|---|
EgIYAQ%3D%3D | Under 4 minutes |
EgIYAw%3D%3D | 4–20 minutes |
EgIYAg%3D%3D | Over 20 minutes |
Features
sp | Effect |
|---|---|
EgJwAQ%3D%3D | 4K |
EgIgAQ%3D%3D | HD |
EgJAAQ%3D%3D | Live now |
EgQQARgB | Subtitles / closed captions |
Upload Date
sp | Effect |
|---|---|
EgIIAQ%3D%3D | Last hour |
EgIIAg%3D%3D | Today |
EgIIAw%3D%3D | This week |
EgIIBA%3D%3D | This month |
EgIIBQ%3D%3D | This year |
These tokens are defined by YouTube and can change without notice. When a token is no longer accepted, YouTube returns an unfiltered result set.
Notes
- Organic variance. YouTube reorders search results continuously. Consecutive calls with identical parameters can return 60–95% overlap depending on the query. This is inherent to the surface, not the plugin.
- Shorts availability. Shorts shelves appear unpredictably. Expect 0, 1, or multiple
shorts_resultsentries depending on the query and locale. Absence doesn't mean failure. - Ads are best-effort. YouTube runs many layouts in parallel; unknown layouts are skipped rather than returned as partial objects.
- Locale fidelity.
hlcontrols metadata strings (published_date,length, view-count suffixes, shelf titles).glinfluences ranking and which shelves render. - Pagination depth. Continuation pagination is stable for tens of pages. Very deep pagination (>50 pages) may start returning empty
video_resultsas YouTube exhausts the feed.
Error Handling
{ "error": "error_code" }| Status | Error | Cause |
|---|---|---|
400 | token is required | token query parameter missing |
400 | search_query is required | Neither search_query nor q provided |
400 | device must be one of: desktop, mobile | Invalid device value |
400 | num must be an integer between 1 and 30 | num is not an integer, or is outside 1–30 |
400 | num cannot be combined with sp | Both num and sp were sent |
400 | failed to construct YouTube URL | Internal URL construction failed (rare — malformed inputs) |
401 | The API Token is inactive or incorrect. | Invalid API token |
500 | decompression failed | Response body decompression failed |
500 | internal server error | Unhandled exception. Report if persistent |
502 | upstream returned truncated page | YouTube returned a partial response. Retry |
502 | failed to parse search results | YouTube returned an unexpected payload shape. Retry; report if persistent |
502 | unexpected response | Upstream returned non-200. Retry |
502 | request failed | Network-level failure. Retry |

