Skip to content

YouTube Shorts Scraper

Try for free

Scrape public YouTube Shorts from one or more channels: titles, view and like counts, comment counts, durations, publish dates, hashtags, and captions when YouTube provides them.

🎬 YouTube Shorts Scraper

Pull public Shorts from any YouTube channel into a clean dataset: the video, the counts YouTube shows, and the channel behind them.

Built for research, social, and competitive-intelligence teams who need Shorts in a spreadsheet or a pipeline without burning an official API quota.

✨ Features

  • 🎯 Pass one or many channels as a handle (nasa) or a channel URL (channels).
  • 🔢 Cap each channel with maxResultsShorts.
  • ↕️ Sort the channel Shorts tab the way the page does: NEWEST, POPULAR, or OLDEST (sortChannelShortsBy).
  • 📅 Keep Shorts published on or after a date, or a relative window such as 2 days (oldestPostDate). A date filter uses newest order.
  • 🎥 For each Short: title, url, id, thumbnailUrl, text, duration, date, viewCount, likes, commentsCount, and commentsTurnedOff.
  • 🏷️ hashtags when they appear in the title or caption, and descriptionLinks when the caption contains URLs.
  • 📝 subtitles when YouTube exposes caption tracks. Each track has language and type.
  • 💬 Optional caption text (includeCaptions): srt is filled for one track, English when YouTube offers it, and only when that download returns cues. Off by default.
  • 📺 Channel context on every row: channelName, channelUrl, channelId, channelUsername, channelDescription, channelJoinedDate, channelDescriptionLinks, channelAvatarUrl, channelBannerUrl, channelTotalVideos, channelTotalViews, numberOfSubscribers, and isChannelVerified.
  • 🔞 isAgeRestricted when the public metadata says so, and isMembersOnly when YouTube marks that video as members-only.
  • 🌍 location, collaborators, translatedTitle, and translatedText only when YouTube includes them.
  • 🧭 Each row records input, inputChannelUrl, fromYTUrl, fromChannelListPage, and order.
  • 🚫 A watch URL, a youtu.be link, a single Short URL, or any other value that is not a channel handle or channel link is rejected before the run starts.

Fields YouTube does not send are left off the item. A real 0 or false stays.

With includeCaptions on, the first subtitles track also carries the caption text:

"subtitles": [
  {
    "language": "en",
    "type": "asr",
    "srt": "1\n00:00:00,390 --> 00:00:11,919\n[Music]\n\n2\n00:00:12,080 --> 00:00:19,960\nUh-oh. Uh-oh.\n…"
  }
]

🚀 Why teams use this

  • ⚡ Request-based collection. The actor reads the public channel and Shorts documents directly, so a default run never waits on a browser.
  • 🏭 Made for production Scrapely runs: one input, a dataset, and the same field names on every row.
  • 📅 A date window that matches nothing finishes with an empty dataset. No Short is invented to fill the gap.
  • 🧹 No filler. Missing counts, links, and captions are omitted instead of stored as blanks.
  • 🔁 Date and sort options match the controls on a channel’s Shorts tab, including “only today’s posts” via 1 day.

💡 Use cases

  • Export a channel's Shorts with view counts, durations, and caption tracks.
  • Find the best-performing Shorts in a niche.
  • Turn on caption text and use Shorts transcripts as text data for research or AI tools.

🧪 Example input

{
  "channels": [
    "rainbowicecream9780"
  ],
  "maxResultsShorts": 10
}

🧾 Sample output

One item from a real run of the example input, shortened. Long text is cut and lists show their first entries.

{
  "title": "ASRM Satisfying sounds #asmr #music #funny #animation #shortvideo #shorts #satisfying",
  "type": "shorts",
  "id": "HKs9NvVRi5s",
  "url": "https://www.youtube.com/shorts/HKs9NvVRi5s",
  "thumbnailUrl": "https://i.ytimg.com/…",
  "viewCount": 175239,
  "date": "2025-08-04T10:00:33.000Z",
  "likes": 1252,
  "isAgeRestricted": false,
  "duration": "00:00:51",
  "commentsCount": 0,
  "subtitles": [
    {
      "language": "en",
      "type": "asr"
    }
  ],
  "order": 0,
  "commentsTurnedOff": false,
  "hashtags": [
    "#asmr",
    "#music"
  ],
  "input": "rainbowicecream9780",
  "fromYTUrl": "https://www.youtube.com/@rainbowicecream9780/shorts",
  "fromChannelListPage": "shorts",
  "channelName": "Coco Creator Rainbow",
  "channelUrl": "https://www.youtube.com/channel/UC3N1VbltR6aREupzvJ8y-sw",
  "channelId": "UC3N1VbltR6aREupzvJ8y-sw",
  "channelUsername": "rainbowicecream9780",
  "channelDescription": "Thank you so much! I appreciate you all watching the videos.",
  "channelJoinedDate": "Aug 9, 2021",
  "channelLocation": "United States"
}

📥 Input

FieldWhat to send
channelsRequired. A handle (3–30 characters) or a channel link: https://www.youtube.com/@NASA, /channel/UC…, /c/…, or /user/…. Watch URLs are rejected before the run starts.
maxResultsShortsHow many Shorts to keep per channel. Default 10.
oldestPostDateAbsolute date (2024-01-01) or a relative window (1 day, 2 days, 3 weeks). Shorts on or after that moment are kept, and sorting is reset to newest.
sortChannelShortsByNEWEST, POPULAR, or OLDEST. Ignored when oldestPostDate is set.
includeCaptionstrue to also save caption text as SRT in subtitles[].srt. Default false: subtitles lists the caption tracks without the text.
{
  "channels": ["nasa", "https://www.youtube.com/@NASA"],
  "maxResultsShorts": 25,
  "sortChannelShortsBy": "NEWEST"
}

📤 Output

Successful rows are one Short each. type is shorts and fromChannelListPage is shorts. The JSON below is the field shape, not a measured sample.

{
  "title": "string",
  "type": "shorts",
  "id": "video id",
  "url": "https://www.youtube.com/shorts/…",
  "thumbnailUrl": "https://i.ytimg.com/…",
  "viewCount": 0,
  "date": "2026-01-15T12:00:00.000Z",
  "likes": 0,
  "channelName": "string",
  "channelUrl": "https://www.youtube.com/channel/UC…",
  "channelId": "UC…",
  "channelUsername": "handle",
  "numberOfSubscribers": 0,
  "isChannelVerified": false,
  "duration": "00:00:26",
  "commentsCount": 0,
  "commentsTurnedOff": false,
  "text": "caption",
  "order": 0,
  "input": "nasa",
  "fromYTUrl": "https://www.youtube.com/@NASA/shorts",
  "fromChannelListPage": "shorts"
}

aboutChannelInfo repeats the channel fields that were actually present. subtitles is an array of {language, type} when caption tracks exist; with includeCaptions one track also carries srt. channelDescriptionLinks and descriptionLinks are {text, url}.

Every dataset row is a Short. A channel that does not exist, has no Shorts, or could not be loaded is skipped and listed in the run's status message and in the OUTPUT record of the run's key-value store, never saved as a row:

{
  "saved": 3,
  "failedInputs": [
    {"input": "somechannel", "reason": "The channel has no shorts."}
  ]
}

A run that finds no Shorts saves no rows and ends with a status message that starts with No results:. The run fails only when no entry is a usable channel (none exists, or none is a handle or channel link) or when every channel page failed to load after retries.

💰 Pricing

Pay per event, plus platform usage:

  • Result: $0.0005 per saved Short ($0.50 per 1,000).
  • Caption (add-on, only with includeCaptions): $0.003 per saved Short whose caption text was returned ($3 per 1,000). Shorts without caption text are not charged this event.
  • Failed inputs (missing channels, channels without Shorts) are never charged.

Platform usage (compute and proxy traffic, plus remote browser time when caption text is read in the browser) is billed separately at standard platform rates. Example: 1,000 Shorts = $0.50 in event fees plus platform usage.

Related actors

G2
4.7/5
Excellent
Trustpilot

The internet is full of data.
Start owning yours.

Scrape.ly gives you the infrastructure, the tooling, and the team to extract, process, and operationalize web data at any scale. Setup takes minutes. The advantage lasts forever.

No credit card. No setup calls.