# YouTube Search Scraper – Videos, Channels & Playlists (`scrapingmonkey/youtube-search-scraper`) Actor

Search public YouTube videos, Shorts, channels, and playlists by keyword. Export result cards with titles, links, available metrics, query context, and pagination.

- **URL**: https://apify.com/scrapingmonkey/youtube-search-scraper.md
- **Developed by:** [ScrapingMonkey](https://apify.com/scrapingmonkey) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

Turn YouTube search phrases into a dataset of public videos, Shorts, channels, and playlists. **YouTube Search Scraper** retains the original query and saves one row per collected result, with the card details available for that result type.

Use it to discover content, compare search phrases, or build a shortlist for video and channel enrichment. Set a page budget for each query, then export or filter the mixed results by type.

| At a glance | Details |
|---|---|
| 📥 Input | Nonempty search keywords or phrases |
| 📤 Output | Video, Shorts, channel, and playlist cards with query context |
| 🔐 Login required | No YouTube credentials or cookies |
| ⚡ Processing | Up to 5 requests concurrently with automatic retries |
| 💾 Delivery | One row per collected result, with an input-specific position |

### What the YouTube search scraper extracts 🔎

The Actor follows YouTube's public search results. Different result types share one table; fields that do not apply to a type can remain null.

- Result ID, URL, type, original query, and collected position
- Video and Shorts titles, thumbnails, duration, view labels, and channel context
- Channel-card names, handles, descriptions, and available subscriber or video counts
- Playlist-card titles, thumbnail references, video counts, and an available first-video ID
- Public publication text, badges, and live or upcoming indicators when applicable
- Available author identity and image variants

### How to scrape YouTube search results 🚀

1. Enter search phrases such as `python tutorial` in `inputList`.
2. Set `pagesPerInput` for each query.
3. Start the Actor and use `type` to distinguish videos, Shorts, channels, and playlists.
4. Export the results or enrich the relevant links with a details Actor.

```json
{
  "inputList": [
    "python tutorial"
  ],
  "pagesPerInput": 2
}
```

### YouTube search results data fields and output 📦

| Field group | Included data |
|---|---|
| Search context | Original input, query, result type, and position |
| Identity | ID, URL, title or name, and available description |
| Video cards | Duration, views, publication text, badges, and author context |
| Channel and playlist cards | Available counts, handles, thumbnails, and first-video IDs |
| Images | Thumbnail and avatar URLs with matching dimensions |

Complete illustrative success item. The content and values below are fictional examples, not a live result:

```json
{
  "input": "forest hiking guide",
  "status": "success",
  "id": "ForestLoop1",
  "url": "https://www.youtube.com/watch?v=ForestLoop1",
  "type": "video",
  "title": "Planning a forest day hike",
  "description": "A practical route guide with water stops and a packing checklist.",
  "thumbnail_url": "https://example.com/forest-loop.jpg",
  "thumbnails.url": [
    "https://example.com/forest-loop-small.jpg",
    "https://example.com/forest-loop.jpg"
  ],
  "thumbnails.width": [
    640,
    1280
  ],
  "thumbnails.height": [
    360,
    720
  ],
  "duration_seconds": 250,
  "duration_text": "4:10",
  "views": 8200,
  "views_text": "8.2K views",
  "published_text": "3 days ago",
  "badges": [],
  "is_live": false,
  "is_upcoming": false,
  "is_premiere": false,
  "is_members_only": false,
  "stream_status": null,
  "scheduled_start_time": null,
  "accessibility_text": null,
  "author.id": "UCaaaaaaaaaaaaaaaaaaaaaa",
  "author.name": "Trail Journal",
  "author.handle": "@trailjournal",
  "author.url": "https://www.youtube.com/@trailjournal",
  "author.avatar_url": "https://example.com/trail-avatar.jpg",
  "author.avatar_thumbnails.url": [
    "https://example.com/trail-avatar-small.jpg",
    "https://example.com/trail-avatar.jpg"
  ],
  "author.avatar_thumbnails.width": [
    80,
    160
  ],
  "author.avatar_thumbnails.height": [
    80,
    160
  ],
  "author.is_verified": false,
  "videos_count": null,
  "videos_count_text": null,
  "first_video_id": null,
  "name": null,
  "handle": null,
  "avatar_url": null,
  "avatar_thumbnails.url": null,
  "avatar_thumbnails.width": null,
  "avatar_thumbnails.height": null,
  "subscribers": null,
  "subscribers_text": null,
  "is_verified": null,
  "query": "forest hiking guide",
  "position": 1
}
```

The complete example is a video result. Channel and playlist results use the same columns and populate the fields appropriate to their type. Table and JSON keys match, including literal dotted names. Thumbnail and avatar columns retain aligned lists within their own groups.

Missing optional fields can be `null`, empty strings, or empty lists. Some flags default to `false` when no signal is present. A failed row retains `input`, sets `status` to `failed`, and leaves the result-data fields null.

### Input requirements and coverage ⚙️

| Parameter | Type | Default | Rules |
|---|---|---|---|
| `inputList` | array of strings | Required | At least one nonempty search phrase. Enter keywords, not a search URL. |
| `pagesPerInput` | integer | `1` | Minimum 1, with no fixed upper limit. Limits result pages for each input; YouTube controls page size. |

Search phrases can contain spaces; surrounding whitespace is trimmed. A pasted search URL is treated as text, not decoded into filters. The current input has no separate language, country, duration, upload-date, result-type, or sort controls.

The Actor collects several result types in one run. Use `type` in the dataset when your workflow needs only videos, Shorts, channels, or playlists. `position` is the order of collected unique results within the input, not a guaranteed universal search rank.

Each input has its own collection order and duplicate tracking. Repeated results within that input are skipped; the same result may appear again under another input. Repeated input entries are processed separately.

The initial result page counts as page 1; each continuation uses another page. Collection ends at the budget or when YouTube stops providing a usable next page. If collection ends without any results, the Actor saves a failed row for that input. An empty end after saved results does not add a failure.

### YouTube search use cases 🎯

#### Content discovery

Find public videos and Shorts for a topic and retain their source queries for later review.

#### Channel research

Filter channel results and enrich a selected account list with public channel details.

#### Playlist discovery

Identify playlists around a subject before collecting their metadata or video entries.

#### Search-phrase comparisons

Compare the content returned for several phrases while preserving each query's separate result sequence.

### Pricing and billable result rows 💰

Check the Actor's **Pricing** tab for the current charging model and rate.

Under dataset-item pricing, each saved success or failed row can be billable. Automatic retries do not independently create extra rows. Repeated input entries can produce repeated billable results.

The page budget is not an exact item count. Each collected result is a row; media variants and source context stay inside it. Repeated results under different inputs can create separate rows.

### YouTube Search Scraper API and integrations 🔌

Use the Actor ID from the **API** tab as `$ACTOR_ID` and your Apify token as `$APIFY_TOKEN`.

```bash
curl -X POST "https://api.apify.com/v2/acts/$ACTOR_ID/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"inputList":["python tutorial"],"pagesPerInput":2}'
```

This request starts a run. Retrieve the default dataset after completion, or use schedules and webhooks to connect it to a recurring workflow. Export JSON, CSV, or Excel, or send selected fields to Google Sheets, Make, Zapier, or your own application.

### Reliability and limits ⚠️

Temporary request failures are retried. Invalid or unavailable targets produce failed rows while other inputs can continue. A later-page failure can add a failed row alongside results already saved for the same input.

Search results can change between runs and may contain fewer usable cards than expected. Public search can omit content, and the Actor does not promise exhaustive coverage or stable ranking.

Card descriptions and counts may be partial. Numeric counts parsed from labels such as 8.2K are approximate; preserve `views_text` or other source labels where available. Use a details Actor when you need full descriptions or additional metadata.

### Frequently asked questions ❓

#### Does it return only videos?

No. It can return videos, Shorts, channels, and playlists. Filter by `type` after collection.

#### Can I pass a search URL with filters?

Enter the search phrase instead. The Actor does not extract filter settings from a pasted URL.

#### Is position an exact search rank?

It is the order of collected unique results within that input. It does not count skipped cards and is not a universal ranking.

#### Will the same video appear under two queries?

It can. Duplicate tracking is separate for each input, preserving the query that produced each row.

#### Does it collect full video descriptions?

Search cards can contain only a snippet. Use Video Details Scraper for the available full description.

### Support, responsible use, and related actors 🛟

For a reproducible issue, share the run ID, a safe public input, and the field or behavior you expected through the Actor's support channel. Keep tokens and other credentials out of support messages.

Use public content in accordance with applicable privacy, copyright, contractual, and platform requirements.

# Actor input Schema

## `inputList` (type: `array`):

Add search keywords or phrases. Spaces are preserved.

## `pagesPerInput` (type: `integer`):

Number of result pages to collect for each input. YouTube controls the page size. Results are saved after each page; collection stops when the list ends. Bootstrap requests do not count as result pages.

## Actor input object example

```json
{
  "inputList": [
    "python tutorial"
  ],
  "pagesPerInput": 1
}
```

# Actor output Schema

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

Success and failed rows. Check the status column.

# 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 = {
    "inputList": [
        "python tutorial"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapingmonkey/youtube-search-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 = { "inputList": ["python tutorial"] }

# Run the Actor and wait for it to finish
run = client.actor("scrapingmonkey/youtube-search-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 '{
  "inputList": [
    "python tutorial"
  ]
}' |
apify call scrapingmonkey/youtube-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapingmonkey/youtube-search-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/eWTyjgB89e8SKKcWO/builds/Ikq4D7vItT7uSkwvC/openapi.json
