# YouTube Video Scraper — Search & Channels ($1/1k) (`leadharbor/youtube-video-scraper`) Actor

Scrape YouTube by search query, channel or direct video URL: title, channel, views, likes, duration, description, thumbnail, publish date. No browser, plain HTTP against YouTube's own InnerTube API. $1 per 1,000 videos.

- **URL**: https://apify.com/leadharbor/youtube-video-scraper.md
- **Developed by:** [Mohammed Samaan](https://apify.com/leadharbor) (community)
- **Categories:** Social media, Videos, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 video scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## YouTube Video Scraper

Scrape YouTube by **search query**, **channel** or **direct video URL** — title, channel,
views, likes, duration, description, thumbnail, publish date. No browser: it talks
straight to YouTube's own InnerTube web API (the same JSON the youtube.com website
itself loads), so it's fast and cheap to run.

**Price: $1 per 1,000 videos.** Rows are de-duplicated by video ID across every
search query, channel and direct URL in one run — you never pay twice for the same
video.

### Who it's for

- Creator and competitor research — pull every upload from a channel with view counts
- Trend and niche research — scrape search results for a keyword, sorted by date or views
- Influencer discovery — search a niche term, get channels and view counts back
- Content calendars — track what a set of channels has published recently

### Inputs

At least one of the three lists below is required.

| Field | What it does |
|---|---|
| `searchQueries` | Search terms, one per line, e.g. `["dubai restaurant", "muscat cafe review"]` |
| `channelUrls` | `@handle`, `youtube.com/@handle`, `/channel/UC…`, or `/c/name` URLs |
| `videoUrls` | Direct video URLs — `watch?v=`, `youtu.be/…`, or `/shorts/…` |
| `maxResultsPerQuery` | Cap per search query or per channel (default 50, max 5000) |
| `sortBy` | `relevance` / `date` / `views` — search queries only |
| `uploadDate` | `any` / `hour` / `today` / `week` / `month` / `year` — search queries only |
| `locale` | Two-letter language code (default `en`) |

**Note:** `sortBy` and `uploadDate` are both applied through single YouTube filter
params. If you set both on the same run, `uploadDate` wins and `sortBy` is skipped for
search — YouTube encodes the two together as a format we don't attempt to build. Run
them as separate queries if you need both at once.

#### Example input

```json
{
  "searchQueries": ["dubai restaurant"],
  "channelUrls": ["https://www.youtube.com/@GoogleDevelopers"],
  "videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
  "maxResultsPerQuery": 100,
  "sortBy": "date"
}
```

### Output

One row per video:

```json
{
  "videoId": "9bZkp7q19f0",
  "url": "https://www.youtube.com/watch?v=9bZkp7q19f0",
  "title": "PSY - GANGNAM STYLE(강남스타일) M/V",
  "channelName": "officialpsy",
  "channelId": "UCrDkAvwZum-UTjHmzDI2iIw",
  "channelUrl": "https://www.youtube.com/channel/UCrDkAvwZum-UTjHmzDI2iIw",
  "publishedText": "2012-07-15T00:46:32-07:00",
  "publishedAt": "2012-07-15T07:46:32.000Z",
  "durationSeconds": 252,
  "viewCount": 6061897295,
  "likeCount": 32000000,
  "description": "PSY - 'I LUV IT' M/V ...",
  "thumbnailUrl": "https://i.ytimg.com/vi_webp/9bZkp7q19f0/maxresdefault.webp",
  "isLive": false,
  "isShort": false,
  "keywords": ["PSY", "싸이", "KPOP"],
  "searchQuery": null,
  "sourceChannel": null,
  "scrapedAt": "2026-09-14T18:43:07.475Z"
}
```

**Detail depth depends on the source.** A `videoUrls` row gets an exact view count,
ISO publish date, full description and (approximate) like count — it comes from
YouTube's own player + video-details endpoints. A row from `searchQueries` or
`channelUrls` gets an approximate view count, a relative published date ("3 months
ago" — YouTube's search/channel listings don't expose the exact date, so
`publishedAt` is `null` there), and a description snippet rather than the full text.
`likeCount` is only fetched for `videoUrls` rows and is read off YouTube's abbreviated
display count (e.g. "19M"), so it's an approximation, not an exact figure.

### How it works

YouTube's own web client calls `https://www.youtube.com/youtubei/v1/{search,browse,next,player}`
with a plain JSON POST body — no API key, no login, no browser. This is the exact
same server-rendered payload the youtube.com website itself parses to draw the page.
Channel URLs are resolved by fetching the channel's `/videos` page HTML and reading
`ytInitialData`, then paginated further pages come through the same InnerTube
`/browse` continuation endpoint. Confirmed working 14 Sep 2026.

### How it compares

No browser means no Chromium to boot, no memory overhead, no proxy tax — just a
handful of HTTP requests per query. That's faster and materially cheaper to run than
a browser-based YouTube scraper for the same result set.

### FAQ

**Does it need my own API key?** No — it uses YouTube's public web endpoints, the
same ones your browser calls when you use youtube.com.

**Can I get Shorts specifically?** `isShort` is set `true` when duration ≤ 60s (for
`videoUrls`) or estimated from duration for search/channel rows — it isn't a
guaranteed YouTube-side flag, so treat it as a strong signal, not a certainty.

**Why is `publishedAt` sometimes null?** Only `videoUrls` rows carry YouTube's exact
ISO publish date. Search and channel listings only expose a relative string like
"3 months ago" — we pass that through as `publishedText` rather than guess a date.

**Does it use proxies?** No — plain outbound HTTP requests, no browser, no proxy
configuration needed or offered.

### Our other actors

- [Google Maps Verified Email Scraper](https://apify.com/leadharbor/google-maps-verified-email-scraper)
- [Bulk Email Verifier](https://apify.com/leadharbor/bulk-email-verifier)
- [Airbnb Listings Scraper](https://apify.com/leadharbor/airbnb-listings-scraper)
- [Website Contact Extractor](https://apify.com/leadharbor/website-contact-extractor)
- [Shopify Competitor Price & Restock Monitor](https://apify.com/leadharbor/ecommerce-price-restock-monitor)
- [App Store Review Monitor](https://apify.com/leadharbor/app-store-review-monitor)
- [Local Review Booster](https://apify.com/leadharbor/local-review-booster)

***

Using this actor? A quick review helps other buyers find it: [youtube-video-scraper](https://apify.com/leadharbor/youtube-video-scraper)

# Actor input Schema

## `searchQueries` (type: `array`):

Search terms, exactly as you'd type them into YouTube's search box. One per line.

## `channelUrls` (type: `array`):

Channel handles or URLs — @handle, youtube.com/@handle, /channel/UC…, or /c/name. One per line.

## `videoUrls` (type: `array`):

Direct video URLs (youtube.com/watch?v=…, youtu.be/…, or /shorts/…) for full detail (including like count and full description). One per line.

## `maxResultsPerQuery` (type: `integer`):

How many videos to collect per search query or per channel.

## `sortBy` (type: `string`):

Only affects search queries. Ignored for a query that also sets an upload date filter below (YouTube can't apply both at once through this API).

## `uploadDate` (type: `string`):

Only affects search queries. Restrict results to videos uploaded within this window.

## `locale` (type: `string`):

Two-letter language code for titles, descriptions and dates.

## Actor input object example

```json
{
  "searchQueries": [
    "dubai restaurant"
  ],
  "channelUrls": [],
  "videoUrls": [],
  "maxResultsPerQuery": 50,
  "sortBy": "relevance",
  "uploadDate": "any",
  "locale": "en"
}
```

# Actor output Schema

## `results` (type: `string`):

One row per video: title, channel, views, likes, duration, description, thumbnail.

## `resultsUi` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQueries": [
        "dubai restaurant"
    ],
    "channelUrls": [],
    "videoUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("leadharbor/youtube-video-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQueries": ["dubai restaurant"],
    "channelUrls": [],
    "videoUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("leadharbor/youtube-video-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "dubai restaurant"
  ],
  "channelUrls": [],
  "videoUrls": []
}' |
apify call leadharbor/youtube-video-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,leadharbor/youtube-video-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9gE91GNX55ZD4oc5U/builds/OHnKf2Ze1kkwXdib2/openapi.json
