HasData is an independent service and is not affiliated with, endorsed by, or sponsored by YouTube. YouTube is a trademark of its respective owner. This API works with publicly available data only.
Get Your API Key
Sign in at hasdata.com, go to your account settings, and copy your API key. All requests must include your key in thex-api-key header.
Request Cost and API Credits
Each request to the YouTube Search Scraper API consumes API Credits from your account balance.- Cost per request: 10 API Credits
- Credits are deducted only for successful requests.
- Your total available credits depend on your active plan.
You can use your credits across all HasData APIs. The same credit balance is shared platform-wide.
Unused credits do not roll over. Any remaining credits expire at the end of the current billing period.
Make Your First Request
curl --request GET -G \
--url 'https://api.hasdata.com/scrape/youtube/search' \
--data-urlencode 'q=BMW' \
--header 'Content-Type: application/json' \
--header 'x-api-key: <your-api-key>'
const axios = require('axios').default;
const options = {
method: 'GET',
url: 'https://api.hasdata.com/scrape/youtube/search',
params: {q: 'BMW'},
headers: {'Content-Type': 'application/json', 'x-api-key': '<your-api-key>'}
};
try {
const { data } = await axios.request(options);
console.log(data);
} catch (error) {
console.error(error);
}
import requests
url = "https://api.hasdata.com/scrape/youtube/search"
querystring = {"q":"BMW"}
headers = {
"Content-Type": "application/json",
"x-api-key": "<your-api-key>"
}
response = requests.get(url, headers=headers, params=querystring)
print(response.json())
<?php
$params = [
"q" => "BMW",
];
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.hasdata.com/scrape/youtube/search?" . http_build_query($params),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <your-api-key>",
],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
OkHttpClient client = new OkHttpClient();
HttpUrl url = HttpUrl.parse("https://api.hasdata.com/scrape/youtube/search")
.newBuilder()
.addQueryParameter("q", "BMW")
.build();
Request request = new Request.Builder()
.url(url)
.get()
.addHeader("Content-Type", "application/json")
.addHeader("x-api-key", "<your-api-key>")
.build();
Response response = client.newCall(request).execute();
using System.Net.Http;
using System.Web;
var client = new HttpClient();
var query = HttpUtility.ParseQueryString(string.Empty);
query["q"] = "BMW";
var url = $"https://api.hasdata.com/scrape/youtube/search?{query}";
var request = new HttpRequestMessage(new HttpMethod("GET"), url);
request.Headers.Add("x-api-key", "<your-api-key>");
using var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
require 'net/http'
require 'uri'
uri = URI("https://api.hasdata.com/scrape/youtube/search")
params = {
"q" => "BMW",
}
uri.query = URI.encode_www_form(params)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
request["Content-Type"] = 'application/json'
request["x-api-key"] = '<your-api-key>'
response = http.request(request)
puts response.read_body
use reqwest::blocking::Client;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let res = client
.get("https://api.hasdata.com/scrape/youtube/search")
.query(&[("q", "BMW")])
.header("Content-Type", "application/json")
.header("x-api-key", "<your-api-key>")
.send()?
.text()?;
println!("{}", res);
Ok(())
}
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
params := url.Values{}
params.Set("q", "BMW")
u := "https://api.hasdata.com/scrape/youtube/search?" + params.Encode()
req, _ := http.NewRequest("GET", u, nil)
req.Header.Add("Content-Type", "application/json")
req.Header.Add("x-api-key", "<your-api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}
API Parameters
| Parameter | Default Value | Required | Description |
|---|---|---|---|
q | BMW | Yes | Free-text search query, exactly as a user would type it into the YouTube search box. |
gl | - | No | The two-letter country code for the country you want to limit the search to. |
hl | - | No | The two-letter language code for the language you want to use for the search. |
deviceType | - | No | Device type for the request. |
sp | - | No | Raw YouTube sp filter token, copied verbatim from a YouTube search URL (e.g. EgIQAQ%253D%253D). When provided, it overrides sortBy, date, videoType, length, and filters[]. Use only if you need a YouTube-side filter that this API does not expose as a structured parameter. |
sortBy | - | No | Sort order applied to the results page. relevance (default) — best match for the query; date — newest first; views — most viewed first; rating — highest rated first; popularity — trending/most popular. |
date | - | No | Limit results to videos uploaded within this time window relative to now. |
videoType | - | No | Restrict results to a single YouTube content type — regular videos, Shorts, channels, playlists, or movies. |
length | - | No | Filter by video duration bucket: - under4 — under 4 minutes- between420 — 4 to 20 minutes- plus20 — over 20 minutes |
filters[] | - | No | Feature flags to require on results. Multiple values are combined with AND (every flag must apply). - hd — HD quality- k4 — 4K quality- hdr — HDR- subtitles — has subtitles/closed captions- cc — Creative Commons license- d3 — 3D video- d360 — 360° video- vr180 — VR180 video- live — currently live- bought — purchased/paid content- location — has a geographic location tag |
paginationToken | - | No | Token returned in the previous response to fetch the next page. |