YouTube Scraper
Give it YouTube channels, playlists, search terms, hashtags or video links and it returns one JSON row per video or Short: title, channel, exact publish date, duration, views, likes, category, Shorts and live flags, tags, hashtags, description, thumbnail and caption languages. Shorts also get comment count and sound. $3.60 per 1,000 videos, or $1.17 in fast listing mode; you pay only for rows you get.
$3.60 per 1,000 videos on the Free plan, down to $2.16 on higher plans
Why this actor
- No extra charge for date ranges (the leading actor adds $1.30 per 1,000 on the free plan).
- Private, age-restricted, members-only and missing videos come back as free error rows that say why.
Drop-in input
Drop-in input. Input written for streamers/youtube-scraper works as it is (searchQueries, startUrls, maxResults, maxResultsShorts, oldestPostDate, sortVideosBy), as do the names of the other leading YouTube actors.
As stated in the actor’s README. The full list of accepted input names is on the Store page.
What you get
| Field | What it holds |
|---|---|
videoId, url, title | The video. Shorts are returned the same way. |
channelName, channelId, channelHandle, channelUrl | The channel that published it. |
publishDate, publishDateIsApprox, publishedText | Exact ISO 8601 date with YouTube's offset (full rows), or a date estimated from "3 months ago" in fast mode. |
durationSeconds, viewCount, likeCount, category | Length and stats at the time of the run. |
commentCount | Exact comment count. Always on Shorts; on regular videos with includeCommentCount. |
soundTitle, soundArtist | Shorts: the sound or song the Short uses, as YouTube's sound link shows it (null when the Short has none). |
isShort, isLive, isLiveContent, isUpcoming, isUnlisted, isFamilySafe | Format and status flags. |
keywords, hashtags, description | Tags, the #hashtags of the title and description, and the description (full or short); emails and phone numbers removed. |
thumbnailUrl, thumbnailMaxUrl | 480x360 thumbnail (always), and the largest one when the upload has it. |
captionLanguages, hasCaptions | Every caption track: code, name, isAutoGenerated. Pair it with our YouTube Transcripts actor to get the text. |
detailLevel | full or listing (fast mode). |
source, sourceType, position | Which channel tab, playlist, search term or hashtag the video came from, and its place in that list. |
scrapedAt | When the row was read. |
Sample row (from the README example; long text shortened, lists cut to two items):
{
"rowType": "video",
"platform": "youtube",
"videoId": "dQw4w9WgXcQ",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
"channelName": "Rick Astley",
"channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
"channelHandle": "@RickAstleyYT",
"channelUrl": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
"publishDate": "2009-10-24T23:57:33-07:00",
"publishDateIsApprox": false,
"publishedText": null,
"durationSeconds": 213,
"viewCount": 1829080503,
"likeCount": 19491607,
"commentCount": null,
"category": "Music",
"isShort": false,
"isLive": false,
"isLiveContent": false,
"isUpcoming": false,
"isUnlisted": false,
"isFamilySafe": true,
"keywords": [
"rick astley",
"Never Gonna Give You Up"
],
"hashtags": [
"rickastley"
],
"soundTitle": null,
"soundArtist": null,
"description": "The official video for “Never Gonna Give You Up” by Rick Astley. ...",
"thumbnailUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",
"thumbnailMaxUrl": "https://i.ytimg.com/vi_webp/dQw4w9WgXcQ/maxresdefault.webp",
"captionLanguages": [
{
"code": "en",
"name": "English",
"isAutoGenerated": false
},
{
"code": "en",
"name": "English",
"isAutoGenerated": true
}
],
"hasCaptions": true,
"detailLevel": "full",
"source": null,
"sourceType": "video",
"position": null,
"scrapedAt": "2026-10-22T08:00:00.000Z"
}
Price
Live Apify price on 2026-10-31, per 1,000 rows, by Apify plan. You pay only for rows delivered; error and summary rows marked free in the README cost nothing. Plus $0.001 per GB of memory when a run starts.
| Per 1,000 | Free | Bronze | Silver | Gold | Platinum | Diamond |
|---|---|---|---|---|---|---|
| Video (main) | $3.60 | $2.70 | $2.34 | $2.16 | $2.16 | $2.16 |
| Short | $3.60 | $2.70 | $2.34 | $2.16 | $2.16 | $2.16 |
| Video (fast listing mode) | $1.17 | $0.90 | $0.72 | $0.45 | $0.45 | $0.45 |
Use cases
- Channel tracking: every new video of your competitors' channels each day, with views and likes.
- Influencer research: recent output, average views and posting rhythm of a list of channels.
- Search monitoring: who ranks for your keywords on YouTube (
position), and how that changes. - Content analytics: categories, lengths, Shorts versus long videos, live streams.
- Shorts trends: which Shorts take off for a hashtag or a search term, and which sounds they use.
- Agents: "list the last N videos" before picking which ones to summarise (then use our YouTube Transcripts actor).
Run it from code or an AI agent
Actor ID arcadium/youtube-videos. Set APIFY_TOKEN to your Apify API token. The input below is the actor’s prefilled example; see the guide for every field.
curl
curl -X POST "https://api.apify.com/v2/acts/arcadium~youtube-videos/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"urls":["https://www.youtube.com/@kurzgesagt"],"searchQueries":[],"hashtags":[],"contentType":"videos","maxResults":10}'JavaScript
// npm install apify-client
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('arcadium/youtube-videos').call({
"urls": [
"https://www.youtube.com/@kurzgesagt"
],
"searchQueries": [],
"hashtags": [],
"contentType": "videos",
"maxResults": 10
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);Python
# pip install apify-client
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arcadium/youtube-videos").call(run_input={
"urls": ["https://www.youtube.com/@kurzgesagt"],
"searchQueries": [],
"hashtags": [],
"contentType": "videos",
"maxResults": 10,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)MCP
{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com/?tools=arcadium/youtube-videos",
"headers": {
"Authorization": "Bearer <APIFY_TOKEN>"
}
}
}
}LangChain
# pip install langchain-apify (reads APIFY_API_TOKEN from the environment)
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("arcadium/youtube-videos")
rows = tool.invoke({"run_input": {
"urls": ["https://www.youtube.com/@kurzgesagt"],
"searchQueries": [],
"hashtags": [],
"contentType": "videos",
"maxResults": 10,
}})
# or give `tool` to an agent: create_react_agent(llm, [tool])LlamaIndex
# pip install llama-index-readers-apify
import os
from llama_index.core import Document, VectorStoreIndex
from llama_index.readers.apify import ApifyActor
reader = ApifyActor(os.environ["APIFY_TOKEN"])
documents = reader.load_data(
actor_id="arcadium/youtube-videos",
run_input={
"urls": ["https://www.youtube.com/@kurzgesagt"],
"searchQueries": [],
"hashtags": [],
"contentType": "videos",
"maxResults": 10,
},
dataset_mapping_function=lambda item: Document(text=str(item.get("description") or ""), metadata={"url": item.get("url")}),
)
index = VectorStoreIndex.from_documents(documents)CrewAI
# pip install crewai crewai-tools langchain-apify (reads APIFY_API_TOKEN from the environment)
from crewai import Agent
from crewai_tools import ApifyActorsTool
tool = ApifyActorsTool(actor_name="arcadium/youtube-videos")
researcher = Agent(
role="Research analyst",
goal="Answer with data collected by the tool",
backstory="Uses public web data.",
tools=[tool],
)n8n
{
"nodes": [
{
"name": "Run arcadium/youtube-videos",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
0,
0
],
"parameters": {
"method": "POST",
"url": "https://api.apify.com/v2/acts/arcadium~youtube-videos/run-sync-get-dataset-items",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "{\"urls\":[\"https://www.youtube.com/@kurzgesagt\"],\"searchQueries\":[],\"hashtags\":[],\"contentType\":\"videos\",\"maxResults\":10}",
"options": {
"timeout": 300000
}
}
}
],
"connections": {}
}Google Sheets
// Extensions > Apps Script. Store your token once: Project Settings > Script properties > APIFY_TOKEN.
function importLastRun() {
const token = PropertiesService.getScriptProperties().getProperty('APIFY_TOKEN');
const url = 'https://api.apify.com/v2/acts/arcadium~youtube-videos/runs/last/dataset/items?status=SUCCEEDED&clean=true&format=json';
const res = UrlFetchApp.fetch(url, { headers: { Authorization: 'Bearer ' + token } });
const rows = JSON.parse(res.getContentText());
if (!rows.length) return;
const keys = Object.keys(rows[0]);
const values = rows.map((r) => keys.map((k) => (typeof r[k] === 'object' ? JSON.stringify(r[k]) : r[k])));
const sheet = SpreadsheetApp.getActiveSheet();
sheet.clearContents();
sheet.getRange(1, 1, 1, keys.length).setValues([keys]);
sheet.getRange(2, 1, values.length, keys.length).setValues(values);
}Limitations
- Public videos only. Private, age-restricted and members-only videos need a signed-in account and are skipped (free error row).
- Views and likes are read at run time; YouTube updates them with some delay. Likes are null when the creator hides them.
- Fast-mode dates are estimates ("2 years ago" can be off by up to a year); full rows have the exact date.
- YouTube's search filters (upload date, sort by date) are loose; use
publishedAfterfor an exact range. - Fast mode on a hashtag's Shorts tab gives only the video id and rounded views (YouTube shows no title there); full rows have everything.
- The sound is what YouTube's sound link shows ("Song · Artist"); Shorts with their original audio and no sound link have
soundTitlenull. - Comment counts only, no comment text; no video or audio download, no subscriber lists.
FAQ
Why are some dates marked approximate? In fast mode the listing only says "3 weeks ago". Turn fast mode off (the default) for exact ISO dates.
A channel returned nothing. Why? Look at its error row: not_found means the handle or playlist does not exist; a date range that matches no video gives no_match. These rows are free.
How fast is it? Full rows: about 2 to 4 videos per second. Fast mode: about 30 videos per request, a few hundred videos in under 10 seconds.
Something looks wrong in the output. Who do I tell? Open an issue on the actor page with the run link. We read them all.
Related actors
YouTube Transcript & Subtitles Scraper
YouTube transcripts and subtitles from $2.48 per 1,000 (pintostudio: $10); pintostudio, johnvc and starvibe inputs work as is.
$2.48 per 1,000 transcripts on the Free plan, down to $1.80 on higher plans