# YouTube Search Scraper (`muhammad_noman_riaz/youtube-search-scraper`) Actor

Video title, URL, channel, views, duration, publish time, badges and rank for every YouTube search result, with upload date, duration and feature filters. Pages past the first. No API key or login needed.

- **URL**: https://apify.com/muhammad_noman_riaz/youtube-search-scraper.md
- **Developed by:** [Muhammad Noman Riaz](https://apify.com/muhammad_noman_riaz) (community)
- **Categories:** Videos, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## YouTube Search Scraper

### What does YouTube Search Scraper do?

YouTube Search Scraper turns any YouTube search into a clean dataset with one record per video result, in the order YouTube ranks them. Type one or more search queries and choose how many results you want per query; the scraper keeps loading the next results pages until it reaches that number or YouTube runs out. Each record has the video ID, URL, title, channel name, channel ID and channel URL, view count as a number, published time, duration in seconds and as text, thumbnail, description snippet, badges such as 4K or CC, live and Shorts flags, the query and the rank. You can narrow results with YouTube's own upload date, duration and feature filters, sort by popularity, and pick the country and language YouTube ranks for. It needs no YouTube API key, no login and no cookies, which makes it a simple tool for keyword research, rank tracking and content discovery.

### What data can I extract from YouTube search results?

| Field | Example | Notes |
|---|---|---|
| `id` | `_9WBuCJMQs8` | Always an 11 character video ID |
| `url` | `https://www.youtube.com/watch?v=_9WBuCJMQs8` | `/shorts/` URL for Shorts |
| `title` | Video title | Always present |
| `channelName`, `channelId`, `channelUrl` | `Explore The World 4K` | |
| `viewCount` | `2360250` | Number. `null` for live streams |
| `publishedText` | `1 year ago` | As YouTube shows it, in the chosen language |
| `publishedDate` | `2026-10-14` | Only when the text is in days or less ("3 days ago"); otherwise `null` |
| `duration` | `531` | Seconds. `null` for live streams |
| `durationText` | `8:51` | |
| `thumbnail` | `https://i.ytimg.com/vi/<id>/hqdefault.jpg` | |
| `descriptionSnippet` | Short text under the title | |
| `isLive`, `isShort` | `false` | |
| `badges` | `["4K", "CC"]` | Labels YouTube shows on the result |
| `searchQuery` | `drone footage` | |
| `rank` | `1` | Position among the video results of that query |

### How do I use YouTube Search Scraper?

1. Enter one or more search queries.
2. Set Max results per query (default 50).
3. Optionally pick filters, sort, country and language.
4. Click Start and download the results as JSON, CSV, Excel or through the API.

#### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `searchQueries` | array of strings | | What to search on YouTube, one query per line |
| `maxResultsPerQuery` | integer | 50 | Videos per query (1 to 1000) |
| `uploadDate` | string | | `hour`, `today`, `week`, `month` or `year` |
| `duration` | string | | `under4`, `between4and20` or `plus20` (minutes) |
| `features` | array of strings | | Any of `live`, `4k`, `subtitles`, `360`, `vr180` |
| `sortBy` | string | `relevance` | `relevance` or `views` (YouTube's popularity order) |
| `gl` | string | `US` | Country code YouTube ranks results for |
| `hl` | string | `en` | Interface language code |
| `maxConcurrency` | integer | 5 | Queries processed at the same time |
| `maxRequestRetries` | integer | 5 | Attempts per results page, each on a new proxy IP |
| `proxy` | object | Apify residential | Proxy settings |

```json
{
    "searchQueries": ["drone footage"],
    "maxResultsPerQuery": 60,
    "duration": "between4and20",
    "features": ["4k"],
    "gl": "US",
    "hl": "en",
    "proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

#### Output example

A real record from the test run with the input above (October 2026). That run returned 60 videos from several results pages, and every one of them was 4 to 20 minutes long and carried the 4K badge:

```json
{
    "id": "_9WBuCJMQs8",
    "url": "https://www.youtube.com/watch?v=_9WBuCJMQs8",
    "title": "Madeira 4K - Portugal's Paradise | Cinematic Drone Footage",
    "channelName": "Explore The World 4K",
    "channelId": "UCNQVrgPYmkm4KGElhWkepLg",
    "channelUrl": "https://www.youtube.com/@exploretheworld4k",
    "viewCount": 2360250,
    "publishedText": "1 year ago",
    "publishedDate": null,
    "duration": 531,
    "durationText": "8:51",
    "thumbnail": "https://i.ytimg.com/vi/_9WBuCJMQs8/hqdefault.jpg",
    "descriptionSnippet": "Experience the breathtaking beauty of Madeira, Portugal in stunning 4K drone footage! Soar over lush green mountains, dramatic ...",
    "isLive": false,
    "isShort": false,
    "badges": ["4K"],
    "searchQuery": "drone footage",
    "rank": 1
}
```

### FAQ

#### Do I need a YouTube API key?

No. The scraper reads the same public search results a logged-out visitor sees, so there is no API quota and nothing to log in to.

#### Can I get more than the first page of results?

Yes. YouTube shows about 20 results per page. The scraper follows YouTube's continuation pages until it has Max results per query videos or YouTube has no more results.

#### Which filters are supported?

Upload date (last hour, today, this week, this month, this year), duration (under 4 minutes, 4 to 20 minutes, over 20 minutes) and the features Live, 4K, Subtitles/CC, 360 degrees and VR180. Filters can be combined. Each one was checked against live YouTube results before it was added.

#### Is sorting by view count exact?

No. YouTube's popularity order puts the most viewed videos first but is not strictly sorted by views. Sort the dataset by `viewCount` yourself if you need a strict order.

#### Are playlists and channels in the results included?

No. Only video results are returned. Playlists, mixes, channel cards, ads and shelves such as "People also watched" are skipped, and `rank` counts videos only.

#### What happens when a page fails?

Each results page is retried on a fresh proxy IP up to Max request retries times. Videos already collected for the query are kept. Queries that stop early or return nothing are listed in the `FAILED_ITEMS` record of the run's key-value store.

### Known limits

- YouTube decides how many results a query has; very narrow filters can return fewer videos than requested.
- `publishedDate` is derived from relative text and is only filled for English text in seconds, minutes, hours or days.
- Live streams have no view count or duration in search results, so both are `null`.
- Sorting by upload date and by rating, plus the HD, HDR, 3D, Creative Commons, location, purchased and movie filters, are not offered because their effect could not be confirmed.
- The same video is returned once per query even if YouTube repeats it on a later page.

### Related YouTube scrapers

- [YouTube Scraper](https://apify.com/muhammad_noman_riaz/youtube-super-scraper): full video details such as likes, comment count and channel stats.
- [YouTube Transcript Scraper](https://apify.com/muhammad_noman_riaz/youtube-video-transcript-super-scraper): timestamped transcripts in any language.
- [YouTube Comments Scraper](https://apify.com/muhammad_noman_riaz/youtube-comments-super-scraper): comments and replies from any video.

# Actor input Schema

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

What to search on YouTube, one query per line. Each query returns up to Max results per query videos, in YouTube's order.

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

How many videos to return for each query. Pages past the first are loaded automatically until this number is reached or YouTube has no more results.

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

Keep only videos uploaded within this period.

## `duration` (type: `string`):

Keep only videos of this length.

## `features` (type: `array`):

Keep only videos with all of these features.

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

Relevance is YouTube's default order. Popularity is YouTube's own popularity order: mostly highest view count first, but not strictly sorted.

## `gl` (type: `string`):

Two-letter country code YouTube ranks results for, such as US, GB or DE.

## `hl` (type: `string`):

Interface language code, such as en or de. Published text follows this language; publishedDate is only filled for English.

## `maxConcurrency` (type: `integer`):

Maximum number of queries processed at the same time.

## `maxRequestRetries` (type: `integer`):

How many times a results page is tried, each time on a new proxy IP, before the query stops.

## `proxy` (type: `object`):

Proxy used for requests to YouTube. Residential proxies are recommended; YouTube often blocks datacenter IPs.

## Actor input object example

```json
{
  "searchQueries": [
    "web scraping tutorial"
  ],
  "maxResultsPerQuery": 50,
  "sortBy": "relevance",
  "gl": "US",
  "hl": "en",
  "maxConcurrency": 5,
  "maxRequestRetries": 5,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `videos` (type: `string`):

One item per video in the search results, with its rank, channel, views, duration and badges

# 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": [
        "web scraping tutorial"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammad_noman_riaz/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 = {
    "searchQueries": ["web scraping tutorial"],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("muhammad_noman_riaz/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 '{
  "searchQueries": [
    "web scraping tutorial"
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call muhammad_noman_riaz/youtube-search-scraper --silent --output-dataset

```

## MCP server setup

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