# YouTube Data API v3 Client: Search & Comments (`datawharf-tools/youtube-data-api`) Actor

Bring your own Google API key. Query the official YouTube Data API v3: video search, channel uploads, video stats, comments, most popular by country, playlists and duration-filtered search. Not affiliated with or endorsed by YouTube or Google. Privacy policy in the README.

- **URL**: https://apify.com/datawharf-tools/youtube-data-api.md
- **Developed by:** [Datawharf Tools](https://apify.com/datawharf-tools) (community)
- **Categories:** Videos, Social media, Developer tools
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.40 / 1,000 result items

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 Data API v3 Client: Search, Comments, Channels, Playlists

Run **YouTube Data API v3** queries with **your own Google API key** and get structured rows you can export to JSON, CSV or Excel. It only calls documented API endpoints (no scraping, no proxies, no video downloads). You pay Apify for the results returned; Google quota is billed to your own Google Cloud project.

Google documents a default of 100 `search.list` calls per day plus 10,000 units per day for all other methods (source: developers.google.com/youtube/data/determine_quota_cost, checked 2026-11-04). Your project's quota page is authoritative and may differ.

**You must bring your own Google Cloud API key.** We never provide, share or pool API keys, and the key you enter is used only for your own run. Setup takes about 2 minutes and is free (steps below).

### Who is this for?

- **Researchers and analysts** who need a clean table of videos for a keyword, sorted and date-filtered.
- **Creators and marketers** tracking a channel's recent uploads, views, likes and subscriber count.
- **Community and brand teams** exporting the comments on a video.
- **Developers** who want the YouTube Data API behind a simple input form, schedule and dataset instead of writing their own client.

### What you get

| Mode | Returns | Quota cost (your Google project) |
|---|---|---|
| `searchVideos` | Videos matching a query, sorted and date-filtered, with views, likes, duration | 1 search call per 50 results (100/day default bucket) + 1 unit per 50 for stats |
| `channel` | Channel profile (subscribers, views, video count) plus latest uploads | about 1 unit per 50 uploads |
| `videoDetails` | Statistics and metadata for specific video IDs or URLs | 1 unit per 50 videos |
| `comments` | Top-level comments (and optional inline replies) of one video | 1 unit per 100 comments |
| `trending` | YouTube's "most popular" chart for a country (optional category), in the order YouTube returns it | 1 unit per 50 videos (YouTube serves about 200 per chart) |
| `playlist` | Every video of a playlist (ID or URL) with views, likes, duration and playlist position | 2 units per 50 videos |
| `searchByDuration` | Keyword search keeping only videos whose YouTube-reported duration is within your limit (60 s or 180 s) | 1 search call + 1 unit per 50 candidates |

**About duration filtering:** `searchByDuration` searches with YouTube's own `videoDuration=short` filter (under 4 minutes) and then keeps videos whose reported `durationSeconds` is at most your limit. It is a filter you choose. It does not label any video as a particular content type. Max results counts search candidates; with "Only return videos within the limit" on (default) the rest are dropped and not charged, so you may receive fewer items than requested.

Every run saves a `QUOTA_REPORT` (key-value store) with search calls and other units used, the Google-documented default limits for comparison, the fetch time, and the date by which to delete or refresh the data. Every row carries `fetchedAt`.

### How to get an API key (2 minutes, free)

1. Open Google Cloud Console and create a project.
2. APIs & Services > Library > enable **YouTube Data API v3**.
3. Credentials > Create credentials > API key.
4. Paste it into the `apiKey` field (stored as a secret).

### Quick test on one public video

Paste your key, then use this input to check your setup (costs about 1 quota unit):

```json
{ "mode": "videoDetails", "videoIds": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"], "maxResults": 1 }
```

### How to use it

1. Paste your API key.
2. Choose a **Mode** and fill in its field (query, channel, video ID, playlist ...).
3. Keep **Max results** small for your first run (the prefill is 10), then raise it.
4. Click **Start**, then open the **Overview** table or download the dataset.

Without an API key, a run returns a single `setup-required` row with setup steps and no data. Your own key is needed for real results. Apify's automatic start event may still be charged by the platform; this Actor charges no result events in that case.

### Example inputs

Search recent videos:

```json
{ "apiKey": "YOUR_KEY", "mode": "searchVideos", "query": "apify web scraping", "order": "date", "publishedAfter": "2026-01-01", "maxResults": 100 }
```

Channel profile and latest uploads:

```json
{ "apiKey": "YOUR_KEY", "mode": "channel", "channel": "@Apify", "maxResults": 51 }
```

Comments on a video, newest first:

```json
{ "apiKey": "YOUR_KEY", "mode": "comments", "videoId": "https://youtu.be/dQw4w9WgXcQ", "maxResults": 500, "commentOrder": "time" }
```

Most popular videos in Japan, Music category:

```json
{ "apiKey": "YOUR_KEY", "mode": "trending", "regionCode": "JP", "videoCategoryId": "10", "maxResults": 50 }
```

Every video of a playlist:

```json
{ "apiKey": "YOUR_KEY", "mode": "playlist", "playlist": "https://www.youtube.com/playlist?list=UUTgwcoeGGKmZ3zzCXN2qo_A", "maxResults": 200 }
```

Videos up to 60 seconds for a keyword:

```json
{ "apiKey": "YOUR_KEY", "mode": "searchByDuration", "query": "funny cats", "maxDurationSeconds": 60, "maxResults": 50 }
```

### Sample output (video)

| type | title | channelTitle | publishedAt | viewCount | likeCount | durationSeconds | url |
|---|---|---|---|---|---|---|---|
| video | ... | ... | 2009-10-25T06:57:33Z | 1500000000 | 17000000 | 213 | https://www.youtube.com/watch?v=dQw4w9WgXcQ |

```json
{ "type": "video", "videoId": "dQw4w9WgXcQ", "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "title": "...", "channelId": "UC...",
  "channelTitle": "...", "publishedAt": "2009-10-25T06:57:33Z", "durationSeconds": 213, "viewCount": 1500000000, "likeCount": 17000000,
  "commentCount": 2400000, "tags": [], "thumbnail": "https://i.ytimg.com/...", "fetchedAt": "..." }
```

Channel rows have `channelId`, `handle`, `subscriberCount`, `viewCount`, `videoCount`, `uploadsPlaylistId`. Comment rows have `commentId`, `videoId`, `author`, `text`, `likeCount`, `replyCount`, `isReply`, `parentId`. Extra fields by mode: `trending` adds `chartPosition`, `trendingRegion`, `trendingCategoryId`; `playlist` adds `playlistId`, `position`, `addedToPlaylistAt`; `searchByDuration` adds `withinMaxDuration` and `maxDurationSeconds`. All modes add `fetchedAt`.

### Use it from code (JavaScript and Python)

JavaScript (`npm install apify-client`):

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('datawharf-tools/youtube-data-api').call({ apiKey: process.env.YOUTUBE_API_KEY, mode: "searchVideos", query: "python tutorial", maxResults: 10 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, 'rows');
```

Python (`pip install "apify-client>=3"`):

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("datawharf-tools/youtube-data-api").call(run_input={"apiKey": os.environ["YOUTUBE_API_KEY"], "mode": "searchVideos", "query": "python tutorial", "maxResults": 10})
items = list(client.dataset(run.default_dataset_id).iterate_items())
print(len(items), "rows")
```

More examples: https://github.com/datawharf-tools/examples

### Pricing

Pay per result: **$0.0004 per result item, about $0.40 per 1,000 videos or comments**, plus standard Apify platform usage and a tiny per-run start fee. Your Google quota is free up to the limits of your project.

| What you run | Items | Approx. result cost |
|---|---|---|
| First test run (the prefill) | 10 | about $0.004 |
| Latest 100 videos for a keyword | 100 | about $0.04 |
| 500 comments on one video | 500 | about $0.20 |
| 1,000 playlist videos | 1,000 | about $0.40 |

Set the **maximum charge per run** to cap spend. An invalid key, a disabled API or an invalid input stops the run before any item is returned or charged.

### Limits

- YouTube search returns at most about 500 results per query. Use date ranges to go deeper.
- With Google's documented default of 100 search calls per day, you can fetch about 5,000 search results per day (50 per call). Other methods draw on a separate 10,000-unit pool.
- Comments: the API returns at most 5 inline replies per thread.
- A search with a large Max results uses many search calls: 1 per 50 results, so 300 results is 6 of your 100 daily calls. The Actor does not check your remaining quota in advance.
- If your daily quota runs out mid-run, the run stops and is marked failed with a message beginning "PARTIAL RESULT". Items already fetched are kept (and charged); the `QUOTA_REPORT` key-value record shows the calls and units used.
- Videos that are deleted or private are silently left out by YouTube; their IDs are listed in `QUOTA_REPORT` under `skippedVideoIds`. IDs that are not valid 11-character video IDs are listed there too and not sent to YouTube.
- Each run takes one search query, one channel or one video for comments, so one input cannot use up the budget of another. In videoDetails mode, if Max results is smaller than your list, only the first IDs (in the order given) are fetched.
- Trending: YouTube returns at most about 200 items per country/category chart, and some categories have no chart in some countries (the run stops with the API's message). An invalid region code stops the run before any charge.
- Playlist: private and deleted entries are skipped (IDs in `QUOTA_REPORT`). A malformed or unknown playlist ID stops the run with a clear message.
- Comments disabled on a video: the run stops with a "Comments are disabled" message.
- Statistics such as like counts can be missing (null) when the owner hides them.

### FAQ

**How do I export YouTube comments or search results to CSV with the official API?** Use `mode: "comments"` with a `videoId`, or `mode: "searchVideos"` with a `query`, then download the dataset as CSV. You need your own Google API key.

**Does it use scraping?** No. It calls the official YouTube Data API v3 only, and quota is billed to your own Google project.

**Why do I need my own key?** Quota belongs to the key owner. This keeps your costs predictable, and the key stays under your own Google project and terms.

**Is this scraping?** No. It only calls documented YouTube Data API endpoints.

**Does it download video files?** No.

**Does it fetch transcripts or subtitles?** No.

**Can I schedule it or call it from code?** Yes. Use Apify schedules, the Apify API, webhooks and integrations; the key is a secret input.

### Your key, your terms, your data

- **Your own key only.** Each user must use their OWN Google Cloud API key. We never provide or share keys, and you must not share yours. Do not use this Actor to resell or sublicense access to the YouTube API.
- **You are responsible for following the [YouTube API Services Terms of Service](https://developers.google.com/youtube/terms/api-services-terms-of-service) and Developer Policies**, including refreshing or deleting stored YouTube API data within 30 days.
- **The Actor keeps no data of its own.** It stores nothing beyond your run's own dataset and the `QUOTA_REPORT` record in your Apify account, and never writes your key to the dataset, the key-value store or the logs. The key is a secret input. Datasets and records are kept by Apify under your account's retention setting (unnamed storages beyond your most recent runs are deleted automatically; the period depends on your plan). To meet the 30-day rule, delete the run's dataset or lower the retention in your Apify billing settings; `QUOTA_REPORT.refreshOrDeleteBy` gives the date for each run.
- This Actor is not affiliated with or endorsed by YouTube or Google. YouTube and Google are trademarks of Google LLC.

**Source: YouTube Data API v3.** All YouTube data returned by this Actor comes from the YouTube Data API v3 (https://developers.google.com/youtube/v3).

### Related Actors

- [Research Papers, PubMed & Clinical Trials Search](https://apify.com/datawharf-tools/research-search) and [SEC EDGAR Filings & XBRL Data](https://apify.com/datawharf-tools/sec-edgar-api) for other official-API data in the same row format.

### Privacy policy

*Publisher: datawharf-tools. Contact: datawharf@gmail.com. Last updated 2026-11-04.*

This Actor uses YouTube API Services. By using it you also agree to be bound by the [YouTube Terms of Service](https://www.youtube.com/t/terms). Google's handling of data is described in the [Google Privacy Policy](http://www.google.com/policies/privacy).

- **What we process.** (1) Your own YouTube Data API key: Apify stores it encrypted as a secret input; the Actor uses it in memory for that run only, sends it only to Google's YouTube API, and never logs, stores or copies it anywhere else. (2) Public YouTube data (videos, channels, playlists, public comments) that the API returns. It goes straight into your own run's dataset. We do not ask for, access or store any private Google account data or user sign-in; the Actor uses an API key only.
- **What we keep.** Nothing. We keep no copy of your key, your inputs or the data returned, and the Actor has no analytics, tracking or third-party sharing.
- **Where your data lives.** Your run datasets, key-value records (such as `QUOTA_REPORT`) and logs live in your own Apify account under Apify's retention rules and [Apify's privacy policy](https://apify.com/privacy-policy). You control and can delete them at any time.
- **30-day rule (your responsibility).** YouTube's Developer Policies require that stored API data be deleted or refreshed within 30 calendar days. Because the data sits in your account, you are responsible for refreshing (re-running) or deleting it within that period.
- **Questions or deletion requests.** Write to datawharf@gmail.com.

# Actor input Schema

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

Free, takes 2 minutes: Google Cloud Console > APIs & Services > Credentials > Create API key (enable YouTube Data API v3 first). Your OWN API key from Google Cloud Console (APIs & Services > Credentials), with 'YouTube Data API v3' enabled. Do not share it. Leave empty and the run returns a single setup-required row (no data, no result charges). Stored as a secret and never written to the dataset or logs.

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

What to fetch. searchVideos = keyword search (1 call from your 100/day search.list quota per 50 results, plus 1 unit per 50 for stats). channel = channel profile plus recent uploads (about 1 unit per 50). videoDetails = stats for specific videos (1 unit per 50). comments = top-level comments of one video (1 unit per 100). trending = YouTube's most popular chart for a country (1 unit per 50, about 200 max). playlist = every video of a playlist with stats (2 units per 50). searchByDuration = keyword search keeping only videos whose reported duration is within your chosen limit (1 search call + 1 unit per 50 candidates).

## `query` (type: `string`):

searchVideos and searchByDuration modes: keywords to search for.

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

searchVideos and searchByDuration modes: result ordering.

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

searchVideos and searchByDuration modes: only videos published on/after this date. ISO format, e.g. 2026-01-01 or 2026-01-01T00:00:00Z.

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

searchVideos and searchByDuration modes: only videos published before this date (ISO format).

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

searchVideos and searchByDuration modes: ISO 3166-1 alpha-2 country code, e.g. US, BR, MX. In trending mode this selects the country chart (default US).

## `videoCategoryId` (type: `string`):

trending mode: optional numeric YouTube category ID to narrow the chart, e.g. 10 (Music), 20 (Gaming), 24 (Entertainment). Some categories have no chart in some countries and return an error.

## `maxDurationSeconds` (type: `string`):

searchByDuration mode: keep videos whose duration, as reported by YouTube, is at most this many seconds. This is a filter you choose; no content type is inferred.

## `onlyWithinMaxDuration` (type: `boolean`):

searchByDuration mode: drop search results longer than the limit (they are not charged). Turn off to keep all and get withinMaxDuration true/false on each. Max results counts search candidates, so you may get fewer items than Max results.

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

searchVideos and searchByDuration modes: ISO 639-1 language code, e.g. en, es, pt.

## `channel` (type: `string`):

channel mode: channel ID (UC...), @handle, or channel URL.

## `includeUploads` (type: `boolean`):

channel mode: also return the channel's latest uploads (up to Max results minus 1).

## `videoIds` (type: `array`):

videoDetails mode: list of video IDs or YouTube URLs (11-character IDs). Deleted or private videos are skipped and listed in the QUOTA_REPORT record.

## `videoId` (type: `string`):

comments mode: the video to fetch comments for.

## `playlist` (type: `string`):

playlist mode: a playlist ID (PL..., UU... for a channel uploads list) or a URL containing list=. Private and deleted entries are skipped and listed in the QUOTA_REPORT record.

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

comments mode: include replies shown inline with each thread (the API returns at most 5 replies per thread). Replies count toward Max results.

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

comments mode: relevance (top comments) or time (newest).

## `maxResults` (type: `integer`):

Maximum number of items to return (all modes). You are charged per item returned. Search modes use 1 search call per page of up to 50 candidates (your default is 100 search calls per day, so about 5,000 candidates per day), and YouTube returns at most about 500 results per query. Trending is limited to about 200 items per chart.

## Actor input object example

```json
{
  "mode": "searchVideos",
  "query": "web scraping tutorial",
  "order": "relevance",
  "maxDurationSeconds": "60",
  "onlyWithinMaxDuration": true,
  "channel": "@Apify",
  "includeUploads": true,
  "videoIds": [
    "dQw4w9WgXcQ"
  ],
  "playlist": "UUTgwcoeGGKmZ3zzCXN2qo_A",
  "includeReplies": false,
  "commentOrder": "relevance",
  "maxResults": 10
}
```

# Actor output Schema

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

All result items in the default dataset (table, CSV, JSON, Excel).

## `report` (type: `string`):

Summary of the run written to the default key-value store.

# 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 = {
    "query": "web scraping tutorial",
    "channel": "@Apify",
    "videoIds": [
        "dQw4w9WgXcQ"
    ],
    "playlist": "UUTgwcoeGGKmZ3zzCXN2qo_A",
    "maxResults": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("datawharf-tools/youtube-data-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 = {
    "query": "web scraping tutorial",
    "channel": "@Apify",
    "videoIds": ["dQw4w9WgXcQ"],
    "playlist": "UUTgwcoeGGKmZ3zzCXN2qo_A",
    "maxResults": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("datawharf-tools/youtube-data-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 '{
  "query": "web scraping tutorial",
  "channel": "@Apify",
  "videoIds": [
    "dQw4w9WgXcQ"
  ],
  "playlist": "UUTgwcoeGGKmZ3zzCXN2qo_A",
  "maxResults": 10
}' |
apify call datawharf-tools/youtube-data-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datawharf-tools/youtube-data-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/4EBJb2wZVeQgPMjAG/builds/McfVv4WPmvtoxNQEx/openapi.json
