# YouTube Search Scraper: Videos, Views & Channels by Keyword (`plainrows/youtube-search-scraper`) Actor

Get YouTube search results for any keyword: video title, URL, views, upload date, duration, channel, badges and position. Filters for date, length, Shorts and live. Only-new-videos mode for scheduled alerts. No browser, no API key. Pay per video found.

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

## Pricing

from $1.00 / 1,000 videos

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: Videos, Views & Channels by Keyword

Scrape YouTube search results for any keyword: **video title, URL, views, upload date, duration, channel, badges (4K, CC, New, LIVE), Shorts and live flags, and position in the results**. Up to about 200 videos per search, in 20 countries.

It calls a commercial search data API instead of driving a browser: **results in seconds, no YouTube API key, no quota, no proxies.** **You only pay for videos returned** (from October 23, 2026, plus a small check fee with **Only new videos**): searches with no result, channels, playlists, repeated videos and videos removed by your filters are free.

### Typical uses

- **Keyword and topic research for creators**: see which videos rank for a keyword, how many views they have and how old they are.
- **YouTube SEO and rank tracking**: schedule the same queries daily or weekly and track the `position` of your videos and your competitors'.
- **Monitoring new videos**: turn on **Only new videos** and schedule the run to get (and pay for) each new upload about a brand, product or topic once.
- **Influencer and channel discovery**: find the channels that publish on a topic, with their channel ID and URL.
- **Datasets for analysis and AI**: titles, descriptions, durations and view counts as clean JSON for spreadsheets, BI tools or LLM pipelines.

### What you get for each video

| Field | Description |
|---|---|
| `videoId`, `title`, `url` | Video ID, title and clean link (`youtube.com/watch?v=...` or `youtube.com/shorts/...`) |
| `channelName`, `channelId`, `channelUrl` | The channel that published it |
| `viewsCount` | Total views (`null` for a stream that is live now) |
| `liveViewers` | People watching now, for a stream that is live now |
| `publishedRelative` | Upload age as YouTube shows it, e.g. `"2 years ago"` (in the search language) |
| `publishedDateApprox` | Approximate upload date (`YYYY-MM-DD`) computed from that age; English results only, otherwise `null` |
| `durationText`, `durationSeconds` | Duration, e.g. `"11:53"` and `713` |
| `isShort`, `isLive`, `isMovie` | YouTube Short, live now, YouTube movie |
| `badges` | Badges shown in the results: `4K`, `CC`, `New`, `LIVE`, `5 products`... (in the search language) |
| `description` | Description snippet shown in the results (not the full description) |
| `thumbnailUrl` | Thumbnail image |
| `position` | Position among the videos on the results page (1 = first video; channels, playlists and repeats not counted) |
| `shelfName` | Results shelf the video was in, e.g. `"Latest from MrBeast"`; `null` in the main list |
| `searchQuery`, `searchCountry`, `languageCode`, `observedAt` | The query, country, language and fetch time (UTC) |

Missing values are always `null`, never guessed. Each video appears once per query, even when YouTube shows it twice.

**Channels and playlists** that appear in the results are skipped (they are counted in the run summary, not billed): this Actor returns one clean row per video.

### Input

```json
{
  "searchQueries": ["how to make sourdough bread", "sourdough starter"],
  "maxResultsPerQuery": 50,
  "country": "US",
  "sortBy": "relevance",
  "uploadDate": "any",
  "duration": "any",
  "includeShorts": true,
  "includeLive": true
}
```

- **searchQueries**: up to 1,000 per run, exactly what you would type in YouTube.
- **maxResultsPerQuery**: 1 to 200 (default 50). YouTube itself shows about 200 videos per search at most.
- **country**: US, GB, CA, AU, IE, IN, DE, AT, CH, FR, BE, ES, MX, IT, NL, PT, BR, PL, SE, JP. **languageCode** (optional) sets the interface language of the results.
- **YouTube filters**: `sortBy` (`relevance`, `popularity`), `uploadDate` (`any`, `today`, `week`, `month`, `year`), `duration` (`any`, `short` under about 4 min, `medium` about 4-20 min, `long` over 20 min). They are applied by YouTube itself, like in the search page filters.
- **includeShorts** / **includeLive**: set to `false` to skip Shorts or live streams. Skipped videos are never billed.
- **onlyNewVideos** (optional, monitoring): return only videos never delivered to you before for the same query, country and language. See below.
- **monitorName** (optional): name of the key-value store in your account that remembers delivered videos (default `plainrows-youtube-monitor`).

### Monitor a topic: get only new videos

Turn on **Only new videos** (`"onlyNewVideos": true`) and add an Apify **schedule** (daily, for example). The first run returns every video it finds and remembers their IDs in a key-value store of your own Apify account; each later run returns **and bills only videos it has never delivered**. A query with nothing new gets a free row with `notFoundReason: "no-new-videos"`.

**Check fee in this mode (from October 23, 2026):** each block of 20 YouTube results checked costs one small `page-checked` event (about what the data source charges us), even when nothing new is found. It is never charged for a search the data source answered in an unexpected format (no results list): the run warns about it in the log and in its summary. Keep **maxResultsPerQuery** close to the number of new videos you expect per run. Runs without **Only new videos** never pay it.

- Combine it with `uploadDate: "week"` (or `"today"`) so the search focuses on recent uploads. Videos left out by `maxResultsPerQuery` or your run budget stay new for the next run.
- History is kept per query, country and language (sort and filters are ignored). Use a different **monitorName** per monitoring task to keep separate histories, or a new name to start over. Leave the option off for rank tracking, which needs the full list every time.

### Output example

Real row from a run on 2026-10-07 (query `how to make sourdough bread`, US):

```json
{
  "searchQuery": "how to make sourdough bread",
  "found": true,
  "position": 1,
  "videoId": "4gEoh3sk2AE",
  "title": "Bake the Perfect Sourdough Bread: A Step-by-Step Guide",
  "url": "https://www.youtube.com/watch?v=4gEoh3sk2AE",
  "channelName": "Natashas Kitchen",
  "channelId": "UC-pC1xsFPzcrL09DaW4jlBA",
  "channelUrl": "https://www.youtube.com/@Natashaskitchen",
  "viewsCount": 3339945,
  "liveViewers": null,
  "publishedRelative": "2 years ago",
  "publishedDateApprox": "2024-10-07",
  "durationText": "11:53",
  "durationSeconds": 713,
  "isShort": false,
  "isLive": false,
  "isMovie": false,
  "badges": [
    "5 products",
    "Earns commission"
  ],
  "description": "Learn how to bake sourdough bread with the perfect rise, ear, and texture—just like you've always dreamed of! This step-by-step ...",
  "thumbnailUrl": "https://i.ytimg.com/vi/4gEoh3sk2AE/hq720.jpg?sqp=-oaymwEnCNAFEJQDSFryq4qpAxkIARUAAIhCGAHYAQHiAQoIGBACGAY4AUAB&rs=AOn4CLASw7ts_TryRzlFrKiW0X28z04f7Q",
  "shelfName": null,
  "searchCountry": "US",
  "languageCode": "en",
  "observedAt": "2026-10-07T13:14:10.701Z",
  "schemaVersion": "1.0"
}
```

### Pricing

Pay per video returned, no subscription, no fee per run, no proxy costs. See the **Pricing** tab for current prices: one event per **video found**, cheaper on higher Apify plans. With **Only new videos**, each block of 20 results checked also costs a small `page-checked` event (from October 23, 2026). All fields and all filters are included in that price (no add-ons).

Price change on October 23, 2026: new `page-checked` event, $0.0025 (FREE) / $0.002 (BRONZE+) per block of 20 results checked, only with **Only new videos**. The video price does not change.

Searches with no result, channels, playlists, repeated videos, videos removed by your filters and input mistakes cost nothing. The run never spends more than the maximum cost you set. If many searches in a row return nothing billable (about $0.01 of data-provider calls), the run stops early and says so in its status; the searches not run are not charged.

**Free Apify plan:** each run returns up to 20 videos for up to 2 queries, so you can check the output. A paid Apify plan removes these limits.

### Use it from code, automations or AI agents

**API (one call, results returned directly):**

```bash
curl -X POST "https://api.apify.com/v2/acts/plainrows~youtube-search-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchQueries": ["how to make sourdough bread"], "maxResultsPerQuery": 50}'
```

**n8n, Make, Zapier:** use the Apify integration, pick `plainrows/youtube-search-scraper`, and send the dataset items to Google Sheets, Airtable, Notion or your database.

**AI agents (MCP):** add `https://mcp.apify.com?tools=plainrows/youtube-search-scraper` to Claude, Cursor or any MCP client. The agent gets a typed tool and pays per result.

### What this is not

- **No comments, no likes, no subscriber counts, no transcripts, no video downloads.** It returns what the YouTube search results page shows.
- The description is the snippet shown in search, not the full description.
- `publishedDateApprox` is derived from YouTube's rounded age ("2 years ago"), so it can be off by months for old videos.
- Not affiliated with YouTube or Google.

### Run summary

Each run stores a summary in the key-value store (`OUTPUT`): queries run, queries with no result, videos billed, videos removed by filters, repeated videos, channels and playlists skipped, duplicate and invalid queries, and anything skipped because of the free-plan or budget limit.

### FAQ

**How do I scrape YouTube search results?**
Enter what you would type in YouTube, one search per line, and run: one row per video with title, URL, views, upload date, duration, channel and position.

**How many videos per search?**
1 to 200 (**maxResultsPerQuery**); YouTube itself shows about 200 videos per search at most.

**Can I filter by upload date or duration?**
Yes: **uploadDate** (today, week, month, year), **duration** (short, medium, long) and **sortBy** (relevance, popularity) are YouTube's own filters. Set **includeShorts** or **includeLive** to `false` to skip them for free.

**Does it return comments, likes or transcripts?**
No: it returns what the YouTube search results page shows. No comments, likes, subscriber counts, transcripts or downloads.

**Do I need a YouTube API key?**
No. You pay per video returned, with no quota to manage.

### More PlainRows tools

Same pay-per-result pricing, same clean JSON, built to chain together in n8n, Make, Zapier or AI agents.

- **SEO and keywords:** [Keyword Search Volume, CPC & Difficulty](https://apify.com/plainrows/keyword-search-volume) · [Keyword Ideas Generator](https://apify.com/plainrows/keyword-ideas-generator) · [Google Autocomplete & People Also Ask](https://apify.com/plainrows/google-autocomplete-questions) · [Google Trends Explorer](https://apify.com/plainrows/google-trends-explorer) · [Website Organic Traffic & Top Keywords](https://apify.com/plainrows/domain-seo-overview) · [Bulk Domain Authority Checker](https://apify.com/plainrows/domain-authority-checker) · [Backlink Checker](https://apify.com/plainrows/backlink-checker) · [Broken Link Checker](https://apify.com/plainrows/broken-link-checker) · [AI Search Visibility Tracker (ChatGPT, Gemini, AI Mode)](https://apify.com/plainrows/ai-search-brand-visibility) · [Google Maps Rank Tracker (Geo-Grid Local SEO)](https://apify.com/plainrows/google-maps-rank-tracker)
- **Leads and companies:** [Google Maps Scraper](https://apify.com/plainrows/google-maps-businesses) · [Website Technology Checker](https://apify.com/plainrows/website-tech-stack) · [ATS Jobs Scraper (Workday, Greenhouse, Lever, Ashby)](https://apify.com/plainrows/ats-job-postings) · [Google Jobs Scraper](https://apify.com/plainrows/google-jobs-scraper) · [Google Ads Scraper (Transparency Center)](https://apify.com/plainrows/google-ads-transparency) · [Company Registry Lookup (SIRENE, LEI, Brreg)](https://apify.com/plainrows/company-registry-lookup) · [Public Tenders Search (EU TED & UK)](https://apify.com/plainrows/public-tenders-search)
- **E-commerce and travel:** [Amazon Product Search Scraper](https://apify.com/plainrows/amazon-product-search) · [Google Shopping Prices Scraper](https://apify.com/plainrows/google-shopping-prices) · [Google Hotels Prices Scraper](https://apify.com/plainrows/google-hotels-prices) · [Tripadvisor Reviews Scraper](https://apify.com/plainrows/tripadvisor-reviews)
- **Content and media:** [Google News Scraper](https://apify.com/plainrows/google-news-scraper) · [YouTube Comments Scraper](https://apify.com/plainrows/youtube-comments-scraper) · [Google Images Scraper](https://apify.com/plainrows/google-images-scraper) · [Website Screenshot API](https://apify.com/plainrows/website-screenshot) · [Google Maps Reviews Scraper](https://apify.com/plainrows/google-maps-reviews) · [App Store & Google Play Reviews Scraper](https://apify.com/plainrows/app-reviews-scraper)

**Compared with other APIs:** [YouTube comments API without a Google Cloud project](https://nadaho.github.io/plainrows/youtube-comments-api/) · [YouTube search results with views and duration as JSON](https://nadaho.github.io/plainrows/youtube-search-results-with-views/)

### Support

Missing a field or found a bug? Open an issue on this page. Issues are read and answered.

# Actor input Schema

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

What you would type in the YouTube search box, one per line: "how to make sourdough bread", "iphone 17 review", "lofi hip hop". Up to 1,000 queries per run.

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

YouTube shows up to about 200 videos per search. Each video returned is billed; see Pricing.

## `country` (type: `string`):

Country whose YouTube results you want (YouTube ranks videos differently per country).

## `languageCode` (type: `string`):

Two-letter language code, e.g. "en" or "fr". Leave empty to use the country's main language (for example German for Switzerland, French for Belgium).

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

Same as YouTube's "Prioritize" filter.

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

Only videos uploaded in this period (YouTube's upload date filter). Useful to monitor new videos for a keyword.

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

YouTube's duration filter.

## `includeShorts` (type: `boolean`):

Turn off to get regular videos only (uses YouTube's "Videos" type filter). Shorts removed are not billed.

## `includeLive` (type: `boolean`):

Turn off to skip streams that are live right now. Skipped streams are not billed.

## `onlyNewVideos` (type: `boolean`):

Return only videos this tool has never delivered to you for the same query, country and language. The first run returns every video and remembers them; later runs (for example a daily schedule) return and bill only new videos.

## `monitorName` (type: `string`):

Name of the key-value store in your Apify account that remembers delivered videos (default "plainrows-youtube-monitor"). Use a different name per monitoring task to keep separate histories, or a new name to start over. Lowercase letters, digits and hyphens.

## Actor input object example

```json
{
  "searchQueries": [
    "how to make sourdough bread"
  ],
  "maxResultsPerQuery": 50,
  "country": "US",
  "sortBy": "relevance",
  "uploadDate": "any",
  "duration": "any",
  "includeShorts": true,
  "includeLive": true,
  "onlyNewVideos": false
}
```

# Actor output Schema

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

No description

## `summary` (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": [
        "how to make sourdough bread"
    ],
    "country": "US"
};

// Run the Actor and wait for it to finish
const run = await client.actor("plainrows/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": ["how to make sourdough bread"],
    "country": "US",
}

# Run the Actor and wait for it to finish
run = client.actor("plainrows/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": [
    "how to make sourdough bread"
  ],
  "country": "US"
}' |
apify call plainrows/youtube-search-scraper --silent --output-dataset

```

## MCP server setup

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