# YouTube Search Scraper (Official API) — Videos by Keyword (`actor-forge/youtube-search-api`) Actor

Bring your own free YouTube API key. YouTube search by keyword with sort, date, region, language and length filters — every result enriched with views, likes, comments, duration and tags via the official YouTube Data API v3. No scraping, no blocks. $0.30 per 1,000 results.

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

## Pricing

from $0.30 / 1,000 video results

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?

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 (Official API) — Videos by Keyword

Bring your own free YouTube API key. YouTube search by keyword with sort, date, region, language and length filters — every result enriched with views, likes, comments, duration and tags via the official YouTube Data API v3. No scraping, no blocks. $0.30 per 1,000 results.

**Bring your own free YouTube API key** and run **YouTube search by keyword** through the **official YouTube Data API v3**, with no scraping, no proxies and no blocks. Type one or more search queries and get one row per result, in YouTube's own search order.

- **Every result is a full video row:** search query, **rank**, title, description, channel, published date, **duration in seconds**, **views, likes and comment count**, tags, category, default language, thumbnails, live status, made-for-kids flag and a Shorts flag. Many no-key YouTube search scrapers return only what the results page shows; here every row is enriched from `videos.list`.
- **The exact YouTube search filters:** sort by relevance, upload date, view count or rating; `publishedAfter` / `publishedBefore` dates; `regionCode` (country); `relevanceLanguage`; and video length (short under 4 min, medium 4–20 min, long over 20 min). Set `searchType` to channel to get channel rows with subscriber, video and view counts instead.
- **Up to about 500 results per query** (YouTube's own cap for search), 50 per page. Duplicates across queries are removed.

Use it for YouTube keyword research, trend and competitor tracking, influencer discovery, content gap analysis and feeding search results into Sheets, Make, n8n or Zapier. **$0.30 per 1,000 results plus $0.002 per page of 50** (about $0.34 per 1,000 all-in), roughly a third of the leading YouTube search scrapers. A free key covers **about 5,000 search results a day**. The same code also does video lookups, channels and comments through the `mode` field.

#### Get your free API key (about 60 seconds, no billing account)

1. Open the [Google Cloud Console](https://console.cloud.google.com/) and sign in with any Google account. Create a project (top bar → **New project**).
2. Go to **APIs & Services → Library**, search for **YouTube Data API v3** and click **Enable**.
3. Go to **APIs & Services → Credentials → Create credentials → API key** and copy the key (it starts with `AIza`).
4. Paste it into the **YouTube API key** field of this actor and run. The field is a secret input: Apify stores it encrypted, and the actor never logs it or writes it to the output.

You do not need to add a billing account. Each Google Cloud project gets **10,000 free quota units per day**, which reset at midnight Pacific Time. If you restrict the key, allow **YouTube Data API v3** and leave out HTTP-referrer or IP restrictions, because Apify runs on changing server IPs.

#### How far your free quota goes

| Mode | API calls | Quota units | Rows per day on 10,000 units |
| --- | --- | --- | --- |
| videos | `videos.list` (50 IDs per call) | 1 per 50 videos | about 500,000 videos |
| channel | `channels.list` + `playlistItems.list` + `videos.list` | 1 per channel + about 2 per 50 videos | about 250,000 videos |
| comments | `commentThreads.list` (100 per call), `comments.list` for long reply threads | 1 per 100 comments | about 1,000,000 comments |
| search | `search.list` (50 per page) + `videos.list` | **101 per page of 50** | about 100 pages (5,000 results) |

Search is the expensive call: YouTube charges 100 units per page. The run log shows an estimate before any call is made. If your key runs out (a `403 quotaExceeded` error), the actor **stops cleanly** with a clear message, keeps the rows already delivered, and does not charge for the failed call. It never retries against an exhausted quota.

#### Official API only, and your data stays yours

- All data comes from the official **YouTube Data API v3** (`https://www.googleapis.com/youtube/v3/`) using **your own key and quota**. Nothing is scraped from youtube.com, and there are no proxies, cookies or logins.
- We never hold, share or pool API keys, and no default key is built in. ActorForge sells the API client; the data is fetched under your key.
- ActorForge keeps no copy of API data after the run. Rows go only to your run's dataset, which belongs to you. YouTube's Developer Policies require stored API data to be **refreshed or deleted at least every 30 days**, so set a retention period on your datasets or re-run to refresh them. Statistics such as view counts change constantly anyway.
- By using this actor you also agree to the [YouTube Terms of Service](https://www.youtube.com/t/terms). Google's handling of API requests is covered by the [Google Privacy Policy](https://policies.google.com/privacy). You can review or revoke your key at any time in the Google Cloud Console, and revoke API access for your Google account at [Google security settings](https://myaccount.google.com/permissions).

*This actor uses YouTube API Services. It is not affiliated with or endorsed by YouTube or Google.*

📘 **Step-by-step guide:** [How to Get YouTube Data With the Official API (Free Key, No Code)](https://devtaonas.github.io/actorforge-site/guides/youtube-data-official-api/)

### What data does it return?

Every run outputs clean, schema-validated rows like these:

| searchQuery | searchRank | title | channelTitle | publishedAt | durationSec | viewCount | likeCount | commentCount | categoryId | isShort |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| web scraping tutorial | 1 | Beginners Guide To Web Scraping with Python - All You Need To Know | Tinkernut | 2021-11-27T13:00:24Z | 456 | 487354 | 13287 | 232 | 27 | false |
| web scraping tutorial | 2 | Learn Web Scraping in 5 Minutes (NO PRIOR KNOWLEDGE) | CodeHead | 2026-03-05T15:01:30Z | 293 | 178100 | 6749 | 96 | 27 | false |
| web scraping tutorial | 3 | Python Tutorial: Web Scraping with BeautifulSoup and Requests | Corey Schafer | 2017-11-08T17:30:00Z | 2748 | 1195647 | 25130 | 1140 | 27 | false |

### How much does it cost?

Transparent pay-per-event pricing — you only pay for what you get, and the
actor **always respects your run budget**: set a maximum total charge and it
stops cleanly at the cap instead of overrunning.

| Event | Price | Charged | Worked example |
| --- | --- | --- | --- |
| `video-result` | $0.0003 | per search result (video row with full details and stats) delivered | 1,000 results = $0.30 (grow_media: $1.00; api-ninja: $5.00 + start fee) |
| `search-page` | $0.002 | per search page of up to 50 results that returned rows (it costs 100 of your quota units) | 50 results = $0.002 + 50 × $0.0003 = $0.017 |
| `channel-result` | $0.0005 | per channel row delivered (searchType channel, or channel mode) | 100 channels = $0.05 |
| `comment-result` | $0.0005 | per comment or reply row delivered (comments mode; author fields stripped) | 10,000 comments = $5.00 |
| `apify-actor-start` | $0.00005 | per run per GB of memory (platform start fee) | One run at 256 MB = $0.0000125 |

### Input options

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `apiKey` | string | no | — | Required. Your own free YouTube Data API v3 key (starts with AIza). Get one in about a minute: console.cloud.google.com → create a project → APIs & Services → Library → enable "YouTube Data API v3" → Credentials → Create credentials → API key. No billing account is needed, and the free quota is 10,000 units per day. The key is stored encrypted by Apify, used only for this run's calls to googleapis.com, and never logged or written to the output. |
| `mode` | string | no | `"search"` | videos: details and stats for video URLs/IDs (1 quota unit per 50 videos). search: YouTube search results, enriched with full video details (100 units per page of 50). channel: channel stats plus every upload (about 2 units per 50 videos). comments: comments on videos, author names stripped (1 unit per 100 comments). |
| `searchQueries` | array | no | `[]` | One or more search terms. Each page of up to 50 results costs 100 of your 10,000 daily quota units (about 5,000 results per free key per day). YouTube returns at most about 500 results per query. |
| `maxResultsPerQuery` | integer | no | `50` | Search results per query. YouTube returns at most about 500 per query. Each 50 = one search page (100 quota units + 1 for video details). |
| `order` | string | no | `"relevance"` | search.list order (search mode). |
| `searchType` | string | no | `"video"` | video: video rows with full details. channel: channel rows with subscriber, video and view counts (search mode). |
| `publishedAfter` | string | no | `""` | Optional date (YYYY-MM-DD). In search mode, filters results; in channel mode, only uploads on or after it (and paging stops at older videos, saving quota). |
| `publishedBefore` | string | no | `""` | Optional date (YYYY-MM-DD) for search mode. |
| `regionCode` | string | no | `""` | Optional 2-letter country code (US, GB, DE …): search results available in that country (search mode). |
| `relevanceLanguage` | string | no | `""` | Optional ISO 639-1 language code (en, es, de …): results most relevant to that language (search mode). |
| `videoDuration` | string | no | `"any"` | Filter search results by duration (search mode, videos only). short < 4 min, medium 4–20 min, long > 20 min. |
| `videoUrls` | array | no | — | Videos for the videos and comments modes: watch URLs, youtu.be links, Shorts, embed or live URLs, or bare 11-character IDs. Duplicates are removed. videos.list takes 50 IDs per call. |
| `channels` | array | no | `[]` | Channel URLs (youtube.com/@handle, /channel/UC…, /user/name), @handles or channel IDs (UC…), for channel mode. Each gives one channel row plus its uploads. |
| `maxVideosPerChannel` | integer | no | `100` | Newest uploads per channel (channel mode). 0 = channel row only. Every 50 videos cost about 2 quota units. |
| `includeShorts` | boolean | no | `true` | Channel mode. The API does not flag Shorts, so this uses a heuristic (3 minutes or less, not live): turning it off also drops regular videos that short. |
| `maxCommentsPerVideo` | integer | no | `100` | Top-level comments per video (comments mode). Replies are not counted here; they are capped separately by Max replies per comment. 100 top-level comments per quota unit. |
| `includeReplies` | boolean | no | `false` | Also return replies (comments mode), up to Max replies per comment per thread. Each reply is its own comment-result row, linked by parentId. |
| `maxRepliesPerComment` | integer | no | `20` | With Include replies on: at most this many replies per top-level comment (comments mode), so one huge thread cannot eat the run. 0 = no replies. Up to 5 replies come free with the thread call; more cost 1 quota unit per 100. |
| `commentOrder` | string | no | `"time"` | time: newest first. relevance: YouTube's top comments. |
| `searchTerms` | string | no | `""` | Optional keyword filter applied by YouTube to the comments (comments mode). |

### Limits & honest notes

- **You need your own free YouTube Data API v3 key** (see the 4-step guide above). Without one the run stops at once with instructions, and nothing is charged.
- **Search is quota-hungry:** each search.list page of up to 50 results costs 100 of your 10,000 free daily units (plus 1 unit for the video details), so one free key gives **about 5,000 search results a day** (about 100 pages). Quota resets at midnight Pacific Time. A `quotaExceeded` error stops the run cleanly; rows already delivered are kept, and the failed call is free.
- **About 500 results per query at most.** That is YouTube's own cap on search depth, so `maxResultsPerQuery` goes up to 500. For more coverage, split a topic into several narrower queries or date ranges.
- Results and their order are YouTube's own search ranking for an API request (no personalisation, no ads). Results may differ slightly from what a logged-in user sees on youtube.com.
- Like counts that the creator hides come back as null. There are no dislike counts (removed by YouTube), no revenue and no watch time.
- `isShort` is a heuristic (3 minutes or less and not live), because the API does not flag Shorts. Use the video length filter `short` to get only videos under 4 minutes.
- Free rows (type error) cover failed queries and invalid inputs. Search pages that return no rows are not charged.
- You must refresh or delete stored API data within 30 days (YouTube Developer Policies III.E.4). We keep nothing after the run.
- The run's spend limit is respected: each page of rows is charged before it is delivered, and the run stops cleanly at the cap.

### Related ActorForge actors

- [YouTube Scraper (Official API) — Videos, Search & Stats](https://apify.com/actor-forge/youtube-api-scraper) — video details and stats by URL or ID with the same key (1 quota unit per 50 videos)
- [YouTube Channel Scraper (Official API) — All Videos & Stats](https://apify.com/actor-forge/youtube-channel-api) — channel stats plus every upload from @handles or channel URLs
- [YouTube Comments Scraper (Official API) — No Usernames](https://apify.com/actor-forge/youtube-comments-api) — comments and replies for any video, with commenter identities stripped
- **Learn more:** [How to Get YouTube Data With the Official API (Free Key, No Code)](https://devtaonas.github.io/actorforge-site/guides/youtube-data-official-api/)

### Changelog

- **2026-10-20** — Initial release: YouTube search by keyword via the official YouTube Data API v3 with your own key. Sort, date, region, language and length filters, every result enriched with full stats, rank per query, clean quota-exceeded stop, and pay-per-event billing.

***

*Built and maintained by **ActorForge**. Reliability first: every actor in the
portfolio is monitored by an automated nightly self-test, and breakages are
typically fixed the same day.*

# Actor input Schema

## `apiKey` (type: `string`):

Required. Your own free YouTube Data API v3 key (starts with AIza). Get one in about a minute: console.cloud.google.com → create a project → APIs & Services → Library → enable "YouTube Data API v3" → Credentials → Create credentials → API key. No billing account is needed, and the free quota is 10,000 units per day. The key is stored encrypted by Apify, used only for this run's calls to googleapis.com, and never logged or written to the output.

## `mode` (type: `string`):

videos: details and stats for video URLs/IDs (1 quota unit per 50 videos). search: YouTube search results, enriched with full video details (100 units per page of 50). channel: channel stats plus every upload (about 2 units per 50 videos). comments: comments on videos, author names stripped (1 unit per 100 comments).

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

One or more search terms. Each page of up to 50 results costs 100 of your 10,000 daily quota units (about 5,000 results per free key per day). YouTube returns at most about 500 results per query.

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

Search results per query. YouTube returns at most about 500 per query. Each 50 = one search page (100 quota units + 1 for video details).

## `order` (type: `string`):

search.list order (search mode).

## `searchType` (type: `string`):

video: video rows with full details. channel: channel rows with subscriber, video and view counts (search mode).

## `publishedAfter` (type: `string`):

Optional date (YYYY-MM-DD). In search mode, filters results; in channel mode, only uploads on or after it (and paging stops at older videos, saving quota).

## `publishedBefore` (type: `string`):

Optional date (YYYY-MM-DD) for search mode.

## `regionCode` (type: `string`):

Optional 2-letter country code (US, GB, DE …): search results available in that country (search mode).

## `relevanceLanguage` (type: `string`):

Optional ISO 639-1 language code (en, es, de …): results most relevant to that language (search mode).

## `videoDuration` (type: `string`):

Filter search results by duration (search mode, videos only). short < 4 min, medium 4–20 min, long > 20 min.

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

Videos for the videos and comments modes: watch URLs, youtu.be links, Shorts, embed or live URLs, or bare 11-character IDs. Duplicates are removed. videos.list takes 50 IDs per call.

## `channels` (type: `array`):

Channel URLs (youtube.com/@handle, /channel/UC…, /user/name), @handles or channel IDs (UC…), for channel mode. Each gives one channel row plus its uploads.

## `maxVideosPerChannel` (type: `integer`):

Newest uploads per channel (channel mode). 0 = channel row only. Every 50 videos cost about 2 quota units.

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

Channel mode. The API does not flag Shorts, so this uses a heuristic (3 minutes or less, not live): turning it off also drops regular videos that short.

## `maxCommentsPerVideo` (type: `integer`):

Top-level comments per video (comments mode). Replies are not counted here; they are capped separately by Max replies per comment. 100 top-level comments per quota unit.

## `includeReplies` (type: `boolean`):

Also return replies (comments mode), up to Max replies per comment per thread. Each reply is its own comment-result row, linked by parentId.

## `maxRepliesPerComment` (type: `integer`):

With Include replies on: at most this many replies per top-level comment (comments mode), so one huge thread cannot eat the run. 0 = no replies. Up to 5 replies come free with the thread call; more cost 1 quota unit per 100.

## `commentOrder` (type: `string`):

time: newest first. relevance: YouTube's top comments.

## `searchTerms` (type: `string`):

Optional keyword filter applied by YouTube to the comments (comments mode).

## Actor input object example

```json
{
  "mode": "search",
  "searchQueries": [
    "web scraping tutorial"
  ],
  "maxResultsPerQuery": 50,
  "order": "relevance",
  "searchType": "video",
  "publishedAfter": "",
  "publishedBefore": "",
  "regionCode": "",
  "relevanceLanguage": "",
  "videoDuration": "any",
  "channels": [],
  "maxVideosPerChannel": 100,
  "includeShorts": true,
  "maxCommentsPerVideo": 100,
  "includeReplies": false,
  "maxRepliesPerComment": 20,
  "commentOrder": "time",
  "searchTerms": ""
}
```

# Actor output Schema

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

Video rows (type video, charged) in search order: query, rank, title, channel, published date, duration, views, likes, comments, tags, category, thumbnails, live status, made-for-kids and topics.

## `channels` (type: `string`):

Channel rows (type channel, charged): title, handle, country, subscriber/video/view counts, created date, uploads playlist and thumbnails.

## `comments` (type: `string`):

Comment rows (type comment, charged): text, likes, reply count, dates and parent ID. Author names, channel IDs and avatars are stripped.

## `errors` (type: `string`):

Free rows (type error) for invalid, not-found or private inputs and videos with comments disabled.

# 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"
    ],
    "maxResultsPerQuery": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("actor-forge/youtube-search-api").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"],
    "maxResultsPerQuery": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("actor-forge/youtube-search-api").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"
  ],
  "maxResultsPerQuery": 50
}' |
apify call actor-forge/youtube-search-api --silent --output-dataset

```

## MCP server setup

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

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/jHVXme911zdpt9wXJ/builds/suuWdh8hhEBwZimgf/openapi.json
