# YouTube API Alternative & Scraper — Videos, Channels | $1/1k (`glasswing/youtube-scraper`) Actor

Scrape YouTube without an API key: keyword search with filters, channel videos, Shorts and live streams, playlists and single videos. Exact views, likes, comment count, duration, upload date, description, hashtags, channel subscribers and channel profiles. $1 per 1,000 results.

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

## Pricing

from $1.00 / 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.

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

### What does YouTube Scraper do?

YouTube Scraper turns **YouTube searches, channels, playlists and videos into clean video data**: title, channel, subscribers, exact views, likes, comment count, duration, upload date, full description, hashtags and thumbnail. Type a keyword, paste a channel link, an @handle, a playlist or a video link, and a few seconds later you have one row per video as JSON, CSV or Excel.

It works as a **YouTube API alternative with no API key and no quota**: no Google Cloud project, no OAuth, no browser. The Actor reads the same public data the youtube.com web page shows to a logged-out visitor, so it is fast and cheap.

Four ways in, freely combined in one run:

- **Search YouTube** by keyword, with YouTube's own filters: upload date (last hour to this year), type (videos, Shorts, channels, playlists, movies), length (under 4, 4 to 20, over 20 minutes) and sort by relevance or view count. Each row keeps its `searchQuery` and `position`.
- **Scrape a channel**: its Videos, Shorts or Live tab, newest, most popular or oldest first, by @handle, channel link or channel ID. Optionally add one **channel profile row** with the About data: description, subscribers, total videos, total views, join date, country and the links the creator lists.
- **Scrape a playlist** by link or ID, in playlist order.
- **Look up single videos or Shorts** by link or video ID.

Typical use cases:

- **Influencer and creator research.** List a creator's latest or most popular videos with views, likes and comment counts, and compare channels by subscribers and output.
- **Competitor and content monitoring.** Track what a brand or competitor channel published this week and how each video performs, on a schedule.
- **Keyword and trend research.** See which videos rank for a keyword, how old they are and how many views they get; filter by upload date to catch new content.
- **Datasets for analytics and AI.** Titles, descriptions, hashtags, durations and engagement numbers for thousands of videos, ready for a spreadsheet, a BI tool or a model.
- **Tools for AI agents.** Give an agent a YouTube search and video lookup without an API key.

It reads video and channel metadata only. It does **not** collect comments, commenter names, e-mail addresses or any other data about individual viewers.

### Why use YouTube Scraper?

- **Cheap.** $1 per 1,000 results, Apify platform usage included, with no extra charge for video details, filters or channel profiles.
- **Fast.** No browser. The default run finishes in well under a minute on Apify (10 to 40 seconds in our tests); a run with 3 search terms, 2 channels and 1 playlist saved 583 fully detailed videos in under 4 minutes.
- **Complete rows by default.** Search, channel and playlist rows are opened one by one to add exact views, likes, comment count, upload date, full description, hashtags and the channel's subscribers (switch **Include video details** off for list data only).
- **Honest results.** Every row carries `status` (`ok`, `not_found`, `error`). A deleted video, an unknown @handle or a missing playlist is a free `not_found` row, and the run still ends successfully.
- **Built for agents and automation.** Call it with no input and it returns data; paste links, @handles or bare IDs; schedule it, call it from the API or connect it to Google Sheets, Slack, Zapier or Make.

### What data can YouTube Scraper extract?

| Field | Type | Description |
|---|---|---|
| `type` | string | `video`, `short`, `channel` or `playlist` |
| `source` | string | How the row was found: `search`, `channel`, `playlist` or `video` (a link or ID you gave) |
| `title` | string | Video, channel or playlist title |
| `videoId` | string | YouTube video ID |
| `url` | string | Link to the video, Short, channel or playlist |
| `channelName` | string | Channel name |
| `channelId` | string | Channel ID (`UC...`) |
| `channelHandle` | string | Channel @handle |
| `channelUrl` | string | Channel link |
| `channelVerified` | boolean | Channel shows a verified badge |
| `subscriberCount` | integer | Channel subscribers as YouTube shows them (YouTube rounds, e.g. 4.55M) |
| `viewCount` | integer | Views (exact with video details) |
| `likeCount` | integer | Likes (exact, with video details) |
| `commentCount` | integer | Comments as YouTube shows them (with video details) |
| `duration` | string | Length as shown, e.g. `13:38` |
| `durationSeconds` | integer | Length in seconds |
| `publishedAt` | string | Upload date `YYYY-MM-DD` (with video details, and for single videos) |
| `publishedTimeText` | string | Relative time as shown, e.g. `3 days ago`, `Streamed 5 months ago` |
| `description` | string | Full description with video details (a search snippet without) |
| `hashtags` | array | Hashtags above the title and in the description |
| `thumbnailUrl` | string | Thumbnail image |
| `isShort` | boolean | The video is a Short |
| `isLive` | boolean | Live right now |
| `wasLive` | boolean | A past live stream |
| `searchQuery` | string | The search term that found the row |
| `position` | integer | 1-based position in the search, channel list or playlist |
| `inputUrl` | string | The link, @handle or ID you gave |
| `status` | string | `ok`, `not_found` or `error` (see below) |
| `error` | string | Reason when `status` is not `ok` |
| `scrapedAt` | string | ISO 8601 time of extraction |

Channel profile rows (`type: channel`) add `videoCount`, `channelViewCount`, `joinedDate`, `country`, `links` (title and URL of each link on the About panel), `avatarUrl` and `bannerUrl`. Playlist search results (`type: playlist`) carry `playlistId` and `videoCount`. `detailsError` appears only when the extra video-details request failed; the row then keeps its list data. Optional fields are left out when YouTube does not show them.

#### Result status (tri-state output)

| `status` | Meaning | Billed? |
|---|---|---|
| `ok` | The video, channel or playlist was found and extracted. | Yes |
| `not_found` | YouTube answered, but the video, @handle, channel tab or playlist does not exist, or a search has no results. | No |
| `error` | YouTube could not be read after retries. `error` says why. | No |

### How to scrape YouTube with YouTube Scraper

1. Open the Actor in Apify Console and click **Try for free**.
2. Paste links, @handles or IDs into **YouTube URLs, handles or IDs**, and/or type keywords into **Search terms**.
3. Set **Max results per search, channel or playlist** and **Maximum results (total)**. Start with the defaults to see the output.
4. Optional: pick search filters (upload date, type, length, sort), the channel tab (Videos, Shorts, Live, About) and the channel order (Latest, Popular, Oldest).
5. Click **Start**. The default run takes well under a minute.
6. Open the **Output** tab or **Export** the dataset as JSON, CSV, Excel, XML or HTML.

To automate it, use the **API** tab (Node.js, Python, curl examples) or add a **Schedule**.

#### Which input finds what

| You give | You get |
|---|---|
| `web scraping tutorial` in Search terms | The top videos for that keyword, with `searchQuery` and `position` |
| `https://www.youtube.com/@TED`, `@TED`, `UCAuUUnT6oDeKwE6v1NGQxug` | TED's videos (or Shorts / Live with **Channel tab**) |
| `https://www.youtube.com/@veritasium/shorts` | That channel's Shorts |
| `https://www.youtube.com/@NASA/about` or Channel tab `about` | One channel profile row |
| `https://www.youtube.com/playlist?list=PL...` or `PL...` | The playlist's videos in order |
| `https://youtu.be/dQw4w9WgXcQ`, `dQw4w9WgXcQ`, a `/shorts/` link | That one video with full details |
| `https://www.youtube.com/results?search_query=...` | The same search, including its filters |

### How much does it cost to scrape YouTube?

This Actor uses **pay-per-event** pricing, with Apify platform usage included:

| Event | Price |
|---|---|
| Actor start | $0.005 per run |
| Result (`status: ok` row) | $0.001 per result |

Example: 1,000 videos with full details cost about $1.01. Rows with `status` `not_found` or `error` are never billed. The free Apify plan includes enough credit to try the Actor on a few thousand videos. You can cap spending per run with **Maximum results** and in the run's **Max total charge** option.

### Input

See the **Input** tab for the full schema. The main options:

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array of strings | `["https://www.youtube.com/@TED"]` | Video, Short, channel, @handle, playlist or search-result links, or bare IDs |
| `searchQueries` | array of strings | - | Keywords to search |
| `maxResultsPerSource` | integer | `10` | Cap per search term, channel and playlist |
| `maxItems` | integer | `20` | Cap for the whole run |
| `includeVideoDetails` | boolean | `true` | Open each video for exact views, likes, comments, date, description, hashtags |
| `includeChannelInfo` | boolean | `false` | Add one channel profile row per channel |
| `channelTab` | string | `videos` | `videos`, `shorts`, `streams` or `about` |
| `channelSort` | string | `newest` | `newest`, `popular` or `oldest` |
| `searchType` | string | `video` | `video`, `shorts`, `channel`, `playlist`, `movie` or `all` |
| `uploadDate` | string | `any` | `hour`, `today`, `week`, `month`, `year` |
| `videoDuration` | string | `any` | `short` (under 4 min), `medium` (4 to 20), `long` (over 20) |
| `sortBy` | string | `relevance` | `relevance` or `views` |
| `query` | string | - | A single search term (same as one entry in `searchQueries`) |
| `proxyConfiguration` | object | Apify Proxy on (datacenter) | Residential proxies are not needed |

Example input:

```json
{
    "searchQueries": ["web scraping tutorial"],
    "uploadDate": "year",
    "startUrls": ["https://www.youtube.com/@TED/videos"],
    "channelSort": "popular",
    "maxResultsPerSource": 50,
    "maxItems": 100
}
```

### Output

You can download the dataset in various formats such as JSON, HTML, CSV or Excel. Example rows from a run on Apify (description shortened):

```json
[
    {
        "url": "https://www.youtube.com/watch?v=hHQlcnubuFI",
        "status": "ok",
        "scrapedAt": "2026-09-28T19:20:19.499Z",
        "type": "video",
        "source": "search",
        "searchQuery": "web scraping tutorial",
        "position": 2,
        "title": "Learn Web Scraping in 5 Minutes (NO PRIOR KNOWLEDGE)",
        "videoId": "hHQlcnubuFI",
        "channelName": "CodeHead",
        "channelId": "UCFVteOob_YXJHPaGTqlDV2Q",
        "channelHandle": "@codehead01",
        "channelUrl": "https://www.youtube.com/@codehead01",
        "viewCount": 168096,
        "duration": "4:53",
        "durationSeconds": 293,
        "publishedTimeText": "6 months ago",
        "wasLive": false,
        "isLive": false,
        "isShort": false,
        "description": "Get Rid of IP Blocking for just $1 with DataImpulse: https://dataimpulse.com/?utm_source=y... ...",
        "thumbnailUrl": "https://i.ytimg.com/vi/hHQlcnubuFI/hqdefault.jpg",
        "subscriberCount": 102000,
        "likeCount": 6647,
        "commentCount": 92,
        "publishedAt": "2026-03-05",
        "hashtags": ["#webdevelopment", "#programming", "#coding"]
    },
    {
        "url": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint=false&ytk=resolve&ytin=https%3A%2F%2Fwww.youtube.com%2F%40thisdoesnotexist12345xyz&yto=0&ytl=5",
        "status": "not_found",
        "error": "HTTP 404: page does not exist",
        "scrapedAt": "2026-09-28T18:56:51.746Z"
    }
]
```

The second row is what an unknown @handle returns: free, and the run still succeeds. For `not_found` and `error` rows, `url` is the request that answered, with the link you gave inside it.

### Tips

- Keep `maxItems` small while testing, then raise it.
- Put many search terms, channels and playlists into one run instead of many single runs; you pay the start fee once.
- Switch **Include video details** off when you only need titles, links, durations and rounded view counts: runs need one request per 20 videos instead of one per video (the price stays the same).
- For a channel's most viewed videos use **Channel sort order: Popular**; for new uploads keep **Latest** and schedule the run.

### Limitations

- Video tags (keywords), category and captions/transcripts are not included: YouTube only serves them to its video player, which refuses requests from cloud servers.
- Comments and commenter data are not collected.
- `subscriberCount` and `commentCount` are YouTube's rounded figures (e.g. 4.55M); likes and views are exact with video details on.
- Without video details, channel and playlist rows carry YouTube's rounded view counts and a relative upload time only; search rows carry exact views.
- YouTube search returns a few hundred results per keyword at most. Age-restricted, private and members-only videos are not available logged out.
- Results reflect YouTube at the time of the run. When YouTube changes its pages, rows come back as `error` and the Actor is updated quickly (report it in the **Issues** tab).

### FAQ

#### Do I need a YouTube API key or a Google account?

No. There is no API key, no quota and no login. The Actor reads the public data youtube.com shows to any logged-out visitor.

#### Is it legal to scrape YouTube?

Scraping publicly available data is generally legal, but you are responsible for how you use the output. Read the legal notice below and YouTube's terms of service, and do not collect personal data without a legitimate reason.

#### How do I get a channel's most popular videos?

Paste the channel link or @handle, set **Channel sort order** to **Popular** and **Max results per search, channel or playlist** to the number you want.

#### How do I get a channel's subscribers, total views and links?

Turn on **Add one channel profile row per channel**, or set **Channel tab** to **About** for the profile row only.

#### Can it scrape Shorts?

Yes: a channel's Shorts tab (a `/shorts` channel link or **Channel tab: Shorts**), Shorts in search (**Search result type: Shorts**) and single `/shorts/` links.

#### Why is a row `not_found`?

The video was removed or made private, the @handle does not exist, the channel has no Shorts or Live tab, or the search had no results. `not_found` rows are free.

#### Can I use this Actor from an AI agent or MCP client?

Yes. Every row is self-describing (`status` + `error`), inputs are plain strings, links, @handles or IDs, and a call with no input returns data. Results can be read through the dataset API or the Apify MCP server.

#### Why did I get fewer rows than `maxItems`?

Each search term, channel and playlist stops at **Max results per search, channel or playlist**, a search can run out of results, or the run hit your **Max total charge** limit.

### Legal and data-protection notice

This Actor extracts only data that YouTube publishes publicly to logged-out visitors; it does not extract private user data such as e-mail addresses, phone numbers, gender or precise location, it does not collect comments or commenter names, and it does not log in or get around access controls. Channel names, @handles and the links a creator lists on their channel are public business information, but your results could still contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you are unsure whether your reason is legitimate, consult your lawyers. You are responsible for complying with YouTube's terms of service and applicable law when using the extracted data.

This Actor is an independent tool and is not affiliated with, endorsed by or sponsored by YouTube, Google or their owners. All trademarks belong to their respective owners.

# Changelog

This Actor's version history is a separate document: https://apify.com/glasswing/youtube-scraper/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

One per line. Accepted: video links (watch?v=, youtu.be, /shorts/, /live/), channel links (@handle, /channel/UC..., /c/, /user/, optionally ending in /videos, /shorts, /streams or /about), bare @handles, video IDs, channel IDs (UC...), playlist links or IDs (PL...), and youtube.com/results?search\_query=... pages. If you call the Actor with search terms only, the built-in example channel is skipped automatically.

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

Keywords to search on YouTube, one per line, exactly as you would type them in the YouTube search box. Each term returns up to 'Max results per search, channel or playlist' rows. A call that sends only search terms does not also scrape the built-in example channel.

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

Stop after this many rows have been saved in total. Each saved row with status `ok` is one billable result. Keep it small for test runs.

## `maxResultsPerSource` (type: `integer`):

Cap for each search term, each channel and each playlist. YouTube pages through about 20 results per request.

## `includeVideoDetails` (type: `boolean`):

For every video and Short found in a search, channel or playlist, also open the video to add the exact view count, like count, comment count, upload date, full description, hashtags and the channel's subscriber count. One extra request per video; the price per result stays the same.

## `includeChannelInfo` (type: `boolean`):

For each channel you give, also save one row with the channel's About data: description, subscribers, total videos, total views, join date, country, the links the creator lists, avatar and banner. The profile row is one result.

## `channelTab` (type: `string`):

Which list to read from a channel link that does not already end in /videos, /shorts, /streams or /about. 'about' returns only the channel profile row.

## `channelSort` (type: `string`):

Order of a channel's videos, Shorts or streams, the same chips YouTube shows on the channel page.

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

What a search returns. 'all' mixes videos, Shorts, channels and playlists as YouTube shows them.

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

Only videos uploaded within this period (YouTube's own filter).

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

YouTube's length filter: under 4 minutes, 4 to 20 minutes, or over 20 minutes.

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

Relevance (YouTube's default) or view count.

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

Same as one entry in 'Search terms', for callers that send a single string.

## `proxyConfiguration` (type: `object`):

Apify Proxy (datacenter, the default group) is on by default: YouTube starts refusing one server's requests after a few hundred video pages in a row, and spreading them over datacenter IPs keeps large runs clean. Residential proxies are not needed. Switch it off for small runs if you prefer.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.youtube.com/@TED/videos"
  ],
  "searchQueries": [
    "web scraping tutorial"
  ],
  "maxItems": 20,
  "maxResultsPerSource": 10,
  "includeVideoDetails": true,
  "includeChannelInfo": false,
  "channelTab": "videos",
  "channelSort": "newest",
  "searchType": "video",
  "uploadDate": "any",
  "videoDuration": "any",
  "sortBy": "relevance",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (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 = {
    "startUrls": [
        "https://www.youtube.com/@TED/videos"
    ],
    "searchQueries": [
        "web scraping tutorial"
    ],
    "maxItems": 20,
    "maxResultsPerSource": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("glasswing/youtube-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 = {
    "startUrls": ["https://www.youtube.com/@TED/videos"],
    "searchQueries": ["web scraping tutorial"],
    "maxItems": 20,
    "maxResultsPerSource": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("glasswing/youtube-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 '{
  "startUrls": [
    "https://www.youtube.com/@TED/videos"
  ],
  "searchQueries": [
    "web scraping tutorial"
  ],
  "maxItems": 20,
  "maxResultsPerSource": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call glasswing/youtube-scraper --silent --output-dataset

```

## MCP server setup

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