# YouTube Search Results Scraper (`automation-lab/youtube-search-results`) Actor

Search YouTube by keyword and export ranked public videos with titles, channels, visible views, duration, thumbnails, snippets, filters, and positions.

- **URL**: https://apify.com/automation-lab/youtube-search-results.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Videos, Social media
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.10 / 1,000 item extracteds

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

## YouTube Search Results Scraper

Search YouTube by keyword and export ranked public video results for content discovery, competitor research, and recurring topic monitoring. The Actor returns video IDs, titles, channels, URLs, thumbnails, duration, publish timing, visible views, snippets, the originating query, and result position without requiring a YouTube API key or account.

Use one query for a focused snapshot or submit several related queries in one run. Public YouTube filters let you sort by relevance, upload date, view count, or rating and narrow results by upload timing, duration, country, and language.

### What does this YouTube search scraper do?

The Actor reproduces public YouTube video search as structured dataset rows. It follows continuation pages until it reaches your limit or YouTube runs out of results. Every row keeps both its position within the query and its position across the full run, making repeated exports easy to compare.

It returns video results only. Channels, playlists, movies, private videos, account-specific history, and personalized signed-in recommendations are outside its scope.

### Who is it for?

- **Content strategists** finding topics, formats, and channels appearing for target keywords.
- **Creator teams** tracking which videos rank for recurring content themes.
- **SEO researchers** comparing public search positions, titles, snippets, and visible engagement.
- **Competitive intelligence teams** collecting consistent snapshots for change analysis.
- **Data teams** feeding YouTube search results into spreadsheets, warehouses, dashboards, or automation.
- **Developers and AI agents** that need normalized YouTube discovery data through an API or MCP.

### Why use this Actor?

- No Google API project, YouTube Data API key, cookies, or account is required.
- Multiple queries can be processed in one run with separate per-query ranks.
- Supported public search filters can be combined instead of encoded manually.
- Continuation pagination supports more than the first visible page.
- Rows include raw display text and parsed numeric values for views and duration.
- A lightweight HTTP implementation avoids browser startup and media downloads.
- Results are ready for JSON, CSV, Excel, API, webhook, and dataset integrations.

### What data can I extract?

| Field | Meaning |
| --- | --- |
| `query` | Search term that produced the result |
| `position` | One-based position across the complete run |
| `queryPosition` | One-based position within that query |
| `videoId` | Stable YouTube video ID |
| `title` | Public search-result title |
| `url` | Canonical YouTube watch URL |
| `channelName`, `channelId`, `channelUrl` | Channel identity when exposed |
| `thumbnailUrl` | Highest-resolution search-result thumbnail exposed |
| `durationText`, `durationSeconds` | Display duration and parsed seconds |
| `publishedTimeText` | Relative timing such as `2 weeks ago` |
| `viewCountText`, `viewCount` | Visible count text and parsed number |
| `snippet` | Description snippet when YouTube includes one |
| `badges` | Visible labels such as `New`, `4K`, or `Verified` |
| `sortBy`, `uploadDate`, `duration` | Filters applied to the row |
| `region`, `language` | Localization used for the query |
| `scrapedAt` | Collection timestamp in ISO 8601 format |

Fields that YouTube does not expose for a result are returned as `null` or an empty badge array. Visible counts are snapshots, not historical metrics.

### How to search YouTube and export results

1. Open the Actor input page.
2. Add one or more terms to **Search queries**.
3. Choose the total result limit and, if needed, a per-query limit.
4. Select a sort order, upload date, and duration filter.
5. Set the two-letter region and language used for public search.
6. Click **Start**.
7. Open the **Dataset** tab to preview or export the rows.

A small first run with 20 results is a good way to verify that the selected filters match your research question.

### Input parameters

| Input | Type | Default | Description |
| --- | --- | --- | --- |
| `queries` | string array | required | One to 20 non-empty search terms |
| `maxItems` | integer | `100` | Total saved rows across all queries, from 1 to 1,000 |
| `maxResultsPerQuery` | integer | `100` | Maximum rows for each query, from 1 to 1,000 |
| `sortBy` | string | `relevance` | `relevance`, `uploadDate`, `viewCount`, or `rating` |
| `uploadDate` | string | `any` | `any`, `hour`, `today`, `week`, `month`, or `year` |
| `duration` | string | `any` | `any`, `short`, `medium`, or `long` |
| `region` | string | `US` | Two-letter country code such as `US`, `GB`, `DE`, `IN`, or `BR` |
| `language` | string | `en` | Language code such as `en`, `de`, `es`, or `pt-br` |

YouTube defines short videos as under four minutes, medium videos as four to 20 minutes, and long videos as over 20 minutes.

### Example input

```json
{
  "queries": [
    "creator economy news",
    "YouTube SEO 2026",
    "creator brand sponsorships"
  ],
  "maxItems": 60,
  "maxResultsPerQuery": 20,
  "sortBy": "uploadDate",
  "uploadDate": "month",
  "duration": "any",
  "region": "US",
  "language": "en"
}
```

This input creates three ranked groups in one dataset. Schedule it weekly and compare `videoId`, `queryPosition`, and `scrapedAt` in your own database to identify new entries or movement.

### Example output

```json
{
  "query": "AI coding tutorial",
  "position": 1,
  "queryPosition": 1,
  "videoId": "2FJlhoDYNPE",
  "title": "AI Coding Masterclass: From Beginner to Expert in 90 Minutes",
  "url": "https://www.youtube.com/watch?v=2FJlhoDYNPE",
  "channelName": "Riley Brown",
  "channelId": "UCMcoud_ZW7cfxeIugBflSBw",
  "channelUrl": "https://www.youtube.com/@rileybrownai",
  "thumbnailUrl": "https://i.ytimg.com/vi/2FJlhoDYNPE/hq720.jpg",
  "durationText": "1:36:02",
  "durationSeconds": 5762,
  "publishedTimeText": "11 months ago",
  "viewCountText": "239,411 views",
  "viewCount": 239411,
  "snippet": "Learn practical AI coding workflows from setup to deployment.",
  "badges": [],
  "sortBy": "relevance",
  "uploadDate": "any",
  "duration": "any",
  "region": "US",
  "language": "en",
  "scrapedAt": "2026-08-29T20:38:24.869Z"
}
```

The sample reflects the current output shape. Search rankings and public metadata can change between runs.

### How much does it cost to search YouTube videos?

The Actor uses pay-per-event pricing:

- a one-time **Run started** event of **$0.005** per run;
- one **Item extracted** event for each accepted video row.

The BRONZE item price is **$0.001832 per result**, with lower per-result rates on higher tiers. At that rate, a 20-result run is approximately $0.04164 including the start event, 100 results are approximately $0.1882, and 1,000 results are approximately $1.837. Your active Apify pricing tier determines the exact item rate shown before the run.

Failed, duplicate, and rejected renderers are not charged as items. Compute is included under the Actor's pay-per-event model where the platform indicates it.

### Recurring monitoring workflow

The Actor returns current snapshots rather than maintaining history inside the run. For repeat monitoring:

1. Create a saved Task with stable queries and filters.
2. Schedule it daily, weekly, or monthly in Apify Console.
3. Send completed-run data to a webhook, Google Sheets, a database, or cloud storage.
4. Compare rows by `query` plus `videoId`.
5. Use `queryPosition` to calculate rank movement and `scrapedAt` to identify the observation.

Keeping history outside the Actor avoids mixing old and new rows in a run's default dataset.

### Export and integration options

From the dataset you can download JSON, JSONL, CSV, XML, RSS, or Excel. Common workflows include:

- enriching an editorial calendar with currently ranked titles and channels;
- loading search snapshots into BigQuery, Snowflake, PostgreSQL, or a BI tool;
- triggering a webhook when a scheduled run completes;
- comparing competitor visibility by query and position;
- passing selected video URLs to a separate metadata, comments, or transcript workflow.

Apify integrations also connect runs to Zapier, Make, Slack, Google Drive, GitHub, and other services.

### Run through the API

Replace `YOUR_TOKEN` with an Apify API token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~youtube-search-results/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries":["OpenAI DevDay"],"maxItems":25,"sortBy":"uploadDate","uploadDate":"year"}'
```

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/youtube-search-results').call({
  queries: ['OpenAI DevDay'],
  maxItems: 25,
  sortBy: 'uploadDate',
  uploadDate: 'year',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient(token="YOUR_TOKEN")
run = client.actor("automation-lab/youtube-search-results").call(run_input={
    "queries": ["OpenAI DevDay"],
    "maxItems": 25,
    "sortBy": "uploadDate",
    "uploadDate": "year",
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### Use with MCP and AI agents

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/youtube-search-results"
```

For **Claude Desktop**, add this server to the `mcpServers` object in its configuration. In **Cursor**, add it under Settings → Tools & MCP. In **VS Code**, add the same HTTP server through your MCP extension or workspace configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/youtube-search-results"
    }
  }
}
```

Example prompts:

- “Find the top 30 YouTube videos for `AI agent tutorial` in the US and summarize recurring channel names.”
- “Search these three creator economy topics, sort by upload date, and return videos from the last month.”
- “Compare query positions from this dataset with last week's export.”

### Limits and result behavior

- Results reflect public, logged-out YouTube search and may differ from a signed-in person's personalized page.
- YouTube can localize or reorder results over time even with identical inputs.
- Relative publish timing and compact visible views are whatever YouTube exposes in the search result.
- Some results omit snippets, channel URLs, duration, or parsed view counts; those fields are nullable.
- Live streams and upcoming videos may not expose a normal duration or numeric visible view count.
- The Actor caps a run at 20 queries and 1,000 rows.
- A valid query with no matching public videos succeeds with zero rows.
- Network failures, rate limits, or incompatible response changes fail the run rather than silently returning a false empty result.

### Reliability and troubleshooting

Requests use a lightweight logged-out YouTube data route with bounded retries for temporary network errors, HTTP 429, and server errors. Stable invalid requests are not retried.

**Why did I get fewer rows than requested?** YouTube may have fewer video results matching the combined filters, may stop offering a continuation, or may omit unsupported result cards. Try a broader query or less restrictive upload-date and duration filters.

**Why are the rankings different from my browser?** Signed-in history, cookies, experiments, location, and personalization affect the consumer website. This Actor uses the supplied public region and language in a logged-out context for repeatable collection.

**Why is `viewCount` null?** Upcoming streams and some result formats expose text that is not a numeric view total. Check `viewCountText` for the original visible value.

### Legality and responsible use

This Actor collects publicly visible search-result metadata. Use it for legitimate research and automation, respect YouTube's terms and applicable law, and avoid collecting or combining data in ways that infringe privacy, intellectual property, or contractual rights. You are responsible for your inputs, schedules, retention, and downstream use.

The Actor does not bypass authentication, access private videos, download media, or retrieve account-specific data.

### FAQ

**Does it need a YouTube Data API key?** No. It uses public logged-out YouTube search data.

**Can it search several keywords?** Yes. Supply up to 20 queries and control both the total and per-query limits.

**Can I filter to videos uploaded this week?** Yes. Set `uploadDate` to `week`.

**Can I export Shorts only?** Not currently. The Actor returns YouTube video search results and supports public duration filters, but it does not claim a Shorts-only mode.

**Does it preserve rank history?** Each row contains current positions and a timestamp. Store scheduled-run datasets in your own destination to calculate historical changes.

**Are visible views exact?** When YouTube exposes an exact count it is parsed. Compact counts are normalized approximately, and the original text remains in `viewCountText`.

### Related YouTube Actors

Use other `automation-lab` Actors when your workflow starts from a known entity rather than a search term:

- [YouTube Channel Videos Scraper](https://apify.com/automation-lab/youtube-channel-videos-scraper) for a channel's public video list.
- [YouTube Channel Search Scraper](https://apify.com/automation-lab/youtube-channel-search-scraper) for searching within a known channel.
- [YouTube Comments Scraper](https://apify.com/automation-lab/youtube-comments-scraper) for public comments on selected videos.
- [YouTube Transcript Scraper](https://apify.com/automation-lab/youtube-transcript) for transcript extraction after discovery.
- [YouTube Thumbnail Downloader](https://apify.com/automation-lab/youtube-thumbnail-downloader) for storing thumbnail assets from known video URLs.

# Actor input Schema

## `queries` (type: `array`):

One to 20 YouTube search terms. Duplicate and blank terms are ignored.

## `maxItems` (type: `integer`):

Maximum number of video rows saved across all queries.

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

Maximum video rows saved for each individual query.

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

Use YouTube's public relevance, upload date, view count, or rating order.

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

Restrict videos by YouTube's public upload-date filter.

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

Restrict videos by YouTube's public duration filter: short (under 4 minutes), medium (4–20 minutes), or long (over 20 minutes).

## `region` (type: `string`):

Two-letter country code used by YouTube to localize search results, for example US, GB, DE, IN, or BR.

## `language` (type: `string`):

Language code used by YouTube, for example en, de, es, or pt-br.

## Actor input object example

```json
{
  "queries": [
    "AI coding tutorial"
  ],
  "maxItems": 20,
  "maxResultsPerQuery": 20,
  "sortBy": "relevance",
  "uploadDate": "any",
  "duration": "any",
  "region": "US",
  "language": "en"
}
```

# Actor output Schema

## `overview` (type: `string`):

Default dataset view containing the ranked video rows produced by every query.

# 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 = {
    "queries": [
        "AI coding tutorial"
    ],
    "maxItems": 20,
    "maxResultsPerQuery": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/youtube-search-results").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 = {
    "queries": ["AI coding tutorial"],
    "maxItems": 20,
    "maxResultsPerQuery": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/youtube-search-results").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 '{
  "queries": [
    "AI coding tutorial"
  ],
  "maxItems": 20,
  "maxResultsPerQuery": 20
}' |
apify call automation-lab/youtube-search-results --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/youtube-search-results"
        }
    }
}

```

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/Gmeuyi7rl9zujqq7L/builds/OCsfRY1cjPOT7Mlxf/openapi.json
