← All articles

How to Scrape YouTube Channel Data as JSON

Open any YouTube channel and the numbers you see are rounded. A video shows “1.2M views,” a channel shows “340K subscribers,” and a comment count reads “4.5K.” Those are fine for a human glancing at a page. They are useless if you are building a dashboard, ranking a creator’s catalog, or tracking growth week over week. You need the exact figures, and you need them as structured data, not as text scraped out of a rendered page.

This guide walks through how to get a YouTube channel’s full video list with exact counts, video durations and publish dates as clean JSON. It covers the official YouTube Data API, where it gets in your way, and how to skip the setup entirely when you just want the data.

Why the Numbers on the Page Are Rounded

YouTube abbreviates public counts on purpose. The watch page and channel page are built for readability, so 1,234,567 becomes “1.2M.” Subscriber counts are rounded even harder: since 2019 YouTube publishes them to three significant figures, so “340K” could be anything from 340,000 to 340,999.

If you scrape those strings straight off the HTML, you inherit the rounding. Worse, you inherit it inconsistently. The same channel can render “1.2M” in one place and “1,234,567” in a tooltip, and the markup around those values changes often. Parsing abbreviated text into real integers (“2.4M” to 2,400,000) also throws away precision you can never get back.

The exact numbers do exist. They just are not in the human-facing text. To read them reliably you go to a data source built for machines.

Option 1: The YouTube Data API

Google publishes the YouTube Data API v3, and it is the correct starting point. It returns exact viewCount, likeCount and commentCount for videos, plus channel-level statistics. Here is the shape of the work.

Get an API Key

Create a project in the Google Cloud console, enable the YouTube Data API v3, and generate an API key. Read-only public data does not need OAuth, so a plain key is enough to start.

Resolve the Channel

You need the channel’s ID (it starts with UC...). If you only have a handle like @channelname, call channels.list with forHandle to resolve it. That same call returns the channel statistics you want:

import requests

API_KEY = "YOUR_KEY"
BASE = "https://www.googleapis.com/youtube/v3"

def get_channel(handle):
    r = requests.get(f"{BASE}/channels", params={
        "part": "snippet,statistics,contentDetails",
        "forHandle": handle,
        "key": API_KEY,
    })
    r.raise_for_status()
    item = r.json()["items"][0]
    stats = item["statistics"]
    uploads = item["contentDetails"]["relatedPlaylists"]["uploads"]
    return {
        "channelId": item["id"],
        "title": item["snippet"]["title"],
        "subscriberCount": int(stats.get("subscriberCount", 0)),
        "videoCount": int(stats["videoCount"]),
        "viewCount": int(stats["viewCount"]),
        "uploadsPlaylist": uploads,
    }

Note that subscriberCount comes back rounded even from the API. That is a Google policy, not a scraping limit. Video view counts, on the other hand, are exact.

Page Through the Uploads

Every channel has a hidden “uploads” playlist that holds every public video. Walk it with playlistItems.list, collect the video IDs, then batch them into videos.list (up to 50 per call) to read statistics and durations:

def get_video_ids(uploads_playlist, limit=200):
    ids, page = [], None
    while len(ids) < limit:
        r = requests.get(f"{BASE}/playlistItems", params={
            "part": "contentDetails",
            "playlistId": uploads_playlist,
            "maxResults": 50,
            "pageToken": page,
            "key": API_KEY,
        })
        data = r.json()
        ids += [i["contentDetails"]["videoId"] for i in data["items"]]
        page = data.get("nextPageToken")
        if not page:
            break
    return ids[:limit]

def get_videos(video_ids):
    out = []
    for i in range(0, len(video_ids), 50):
        chunk = video_ids[i:i + 50]
        r = requests.get(f"{BASE}/videos", params={
            "part": "snippet,statistics,contentDetails",
            "id": ",".join(chunk),
            "key": API_KEY,
        })
        for v in r.json()["items"]:
            s, c = v["statistics"], v["contentDetails"]
            out.append({
                "id": v["id"],
                "title": v["snippet"]["title"],
                "publishedAt": v["snippet"]["publishedAt"],
                "duration": c["duration"],            # ISO-8601, e.g. PT12M30S
                "viewCount": int(s.get("viewCount", 0)),
                "likeCount": int(s.get("likeCount", 0)),
                "commentCount": int(s.get("commentCount", 0)),
            })
    return out

That gets you exact numbers. The catch is the duration field: it comes back as an ISO-8601 string like PT12M30S, not seconds. You convert it yourself with the isodate library or a small parser.

Watch the Quota

This is where the Data API bites. Every project gets 10,000 quota units per day by default. A videos.list or playlistItems.list call costs 1 unit, which sounds generous until you are paginating hundreds of channels. And search.list (which you might reach for to find channels) costs 100 units per call, so a few hundred searches drain the whole day.

For a single channel the free quota is plenty. For monitoring thousands of channels on a schedule, you either request a quota increase from Google (a form and a review) or you spread requests across days. Neither is fun when you have a deadline.

Option 2: Skip the Setup and Get JSON Directly

If you do not want a Google Cloud project, an API key, quota math, and your own pagination loop, you can hand a channel handle or URL to a scraping API and get the same structured data back in one call.

The ScrapeUnblocker youtube-channel endpoint reads a channel’s uploads and returns each video with exact viewCount, likeCount, commentCount, a duration in both ISO-8601 and a ready-to-use durationSeconds, the description, and a publishedAt timestamp. The channel summary carries subscriberCount, videoCount, total viewCount and the handle. A limit parameter (1 to 200) controls how far past the first batch you page.

import requests

resp = requests.post(
    "https://api.scrapeunblocker.com/content/youtube-channel",
    headers={"x-scrapeunblocker-key": "YOUR_KEY"},
    json={"channel": "@channelname", "limit": 100},
)
data = resp.json()

print(data["channel"]["subscriberCount"], "subscribers")
for v in data["videos"]:
    print(v["publishedAt"], v["durationSeconds"], v["viewCount"], v["title"])

You get one JSON payload with the channel stats and the video list already parsed, including durationSeconds so you skip the ISO-8601 conversion. There is no quota to budget and no key to provision with Google. Pick this when you would rather spend your time on the analysis than on API plumbing.

What to Do With the Data

Once you have exact per-video numbers as JSON, the useful work starts:

  • Rank a catalog. Sort by viewCount to find a channel’s real hits, or by views-per-day since publishedAt to spot videos that are still climbing.
  • Track growth. Store the channel viewCount and videoCount on a schedule and diff them to measure momentum, not vanity numbers.
  • Compute engagement rates. likeCount / viewCount and commentCount / viewCount are only meaningful with exact figures. Rounded counts make the ratios noise.
  • Study cadence and length. Bucket durationSeconds and publishedAt to see whether a creator’s longer or shorter videos perform better, and how often they ship.

FAQ

Are YouTube video view counts exact or rounded? Video viewCount, likeCount and commentCount from the Data API are exact integers. Only subscriberCount is rounded, to three significant figures, and that is a Google policy that applies to every method of reading it.

Is scraping public YouTube data allowed? Reading public, non-personal data such as public video statistics is generally lower risk than accessing private or personal information, but you are still bound by YouTube’s Terms of Service and by local law. Only collect public data, respect rate limits, and if you have any doubt about a specific use, get legal advice.

Why is the video duration returned as PT12M30S? That is ISO-8601 duration format, which the YouTube Data API uses for duration. PT12M30S means 12 minutes 30 seconds. Convert it to seconds with a library like isodate, or use a source that already returns a numeric durationSeconds.

How many videos can I pull from one channel? Every public video lives in the channel’s hidden “uploads” playlist, so there is no hard ceiling beyond how far you page. With the Data API you follow nextPageToken until it runs out; with a scraping endpoint you set a limit (up to 200 per request here) and page from there.

Getting Clean YouTube Data

The exact numbers you want are never in the rounded text on the page, so scraping the HTML is the wrong tool. Read them from a structured source instead: the YouTube Data API if you are happy to manage keys and quota, or a scraping API when you would rather get parsed JSON in a single call.

If you want to skip the Google Cloud setup and the ISO-8601 parsing, ScrapeUnblocker returns a channel’s videos with exact counts, durations in seconds and publish dates as clean JSON. See the documentation for the full response shape and the other data endpoints.

Try ScrapeUnblocker free

95%+ success rate · from 0.55€ per 1,000 calls · 500 free requests on signup.

Try it free → See pricing