logo

YouTube Scraper API

View as Markdown

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

YouTube API

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: sp tokens 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: hl controls UI language (published-date, duration, view-count strings); gl influences ranking and shelf eligibility.
  • Device Emulation: Desktop or mobile layout via device.
  • Pagination: Single sp parameter doubles as filter token and continuation cursor — the plugin routes them automatically. Or skip manual paging entirely with num.
  • No Blocks or CAPTCHAs: Anti-bot is handled by Scrape.do.

Endpoint

GET https://api.scrape.do/plugin/google/youtube

Request Parameters

Required

ParameterTypeDescription
tokenstringYour Scrape.do API authentication token
search_querystringSearch terms (e.g., best laptop 2025, macbook pro m3). Alias: q

Localization

ParameterTypeDefaultDescription
hlstringenInterface language (en, de, fr, ja, tr, es, …). Controls published_date, length, and views text.
glstringusCountry 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

ParameterTypeDefaultDescription
devicestringdesktopdesktop or mobile. Mobile returns the mobile layout.

Filters & Sort

ParameterTypeDefaultDescription
spstring—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

ParameterTypeDefaultDescription
numinteger—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

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 }
FieldTypeDescription
total_resultsintegerYouTube's estimated total. May be 0 on some continuation pages.
video_results_statestringStatus 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
}
FieldTypeAlwaysDescription
position_on_pageintegeryes1-based position
titlestringyesVideo title
linkstringyesCanonical watch URL
video_idstringyesYouTube video id
channel.namestringChannel display name
channel.linkstringChannel URL
channel.verifiedbooltrue when the channel has a verified badge
channel.thumbnailstringChannel avatar URL
published_datestringHuman-readable age, localized to hl ("4 months ago", "vor 4 Monaten")
viewsintegerView count parsed to integer (47,427 → 47427, 1.2M → 1200000)
views_originalstringThe 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
lengthstringDuration ("12:38", "1:05:22")
descriptionstringSnippet text shown under the result
extensionsstring[]Badges ("4K", "LIVE", "New", "CC")
thumbnail.staticstringStatic thumbnail URL
thumbnail.richstringAnimated preview URL when YouTube provides one
livebooltrue 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/..."
}
FieldTypeDescription
position_on_pageinteger1-based position
titlestringChannel display name
linkstringChannel URL
verifiedboolVerified badge
handlestring@handle slug
subscribersintegerSubscriber count parsed to integer
descriptionstringChannel description snippet
thumbnailstringChannel 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"
}
FieldTypeDescription
position_on_pageinteger1-based position
titlestringPlaylist title
linkstringPlaylist URL
channel.namestringUploader display name
channel.linkstringUploader channel URL
videosobject[]Preview videos. Each entry carries title, length, link when available
video_countintegerTotal video count on the playlist badge
thumbnailstringPlaylist 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.

FieldRenders 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

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..."
}
FieldTypeDescription
currentstringThe URL the plugin fetched for this page
nextstringReady-to-inspect URL for the next page
next_page_tokenstringRaw 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, and ads_results are not returned, and neither is pagination — the plugin consumes the continuation cursor internally.
  • Recommendation shelves don't count toward num. Videos from people_also_watched, people_also_search_for, from_related_searches, channels_new_to_you, and explore_more still land in their own buckets and are never counted.
  • Lighter metadata. The wide result feed carries no description snippet and reports view counts rounded: 649K views → views: 649000, with the original string in views_original. Omit num when 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 num videos plus the response header Scrape.do-Auto-Page-Truncated: true. Re-issue the request without num and page manually with sp from 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 high num is.

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

spEffect
(omit)Relevance (default)
CAE%3DSort by rating
CAI%3DSort by upload date (newest first)
CAM%3DSort by view count

Result Type

spEffect
EgIQAQ%3D%3DVideos only
EgIQAg%3D%3DChannels only → populates channel_results
EgIQAw%3D%3DPlaylists only → populates playlist_results

Duration

spEffect
EgIYAQ%3D%3DUnder 4 minutes
EgIYAw%3D%3D4–20 minutes
EgIYAg%3D%3DOver 20 minutes

Features

spEffect
EgJwAQ%3D%3D4K
EgIgAQ%3D%3DHD
EgJAAQ%3D%3DLive now
EgQQARgBSubtitles / closed captions

Upload Date

spEffect
EgIIAQ%3D%3DLast hour
EgIIAg%3D%3DToday
EgIIAw%3D%3DThis week
EgIIBA%3D%3DThis month
EgIIBQ%3D%3DThis 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_results entries 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. hl controls metadata strings (published_date, length, view-count suffixes, shelf titles). gl influences 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_results as YouTube exhausts the feed.

Error Handling

{ "error": "error_code" }
StatusErrorCause
400token is requiredtoken query parameter missing
400search_query is requiredNeither search_query nor q provided
400device must be one of: desktop, mobileInvalid device value
400num must be an integer between 1 and 30num is not an integer, or is outside 1–30
400num cannot be combined with spBoth num and sp were sent
400failed to construct YouTube URLInternal URL construction failed (rare — malformed inputs)
401The API Token is inactive or incorrect.Invalid API token
500decompression failedResponse body decompression failed
500internal server errorUnhandled exception. Report if persistent
502upstream returned truncated pageYouTube returned a partial response. Retry
502failed to parse search resultsYouTube returned an unexpected payload shape. Retry; report if persistent
502unexpected responseUpstream returned non-200. Retry
502request failedNetwork-level failure. Retry

On this page