YouTube Channel Stats Extractor - Subscribers by Domain
Pricing
from $2.45 / 1,000 company checkeds
YouTube Channel Stats Extractor - Subscribers by Domain
Resolves a company domain or a YouTube handle to the channel and returns the subscriber count, stable channel id, creation date and description. No API key. Flat, Clay ready, one row per company. Transcript pulling is included and is currently gated by YouTube.
Pricing
from $2.45 / 1,000 company checkeds
Rating
0.0
(0)
Developer
Mamba Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 hours ago
Last modified
Categories
Share
🔎 What can YouTube Channel Stats Extractor do?
Give it a company domain or a YouTube handle and it returns that company's YouTube channel: subscriber count, the stable channel id, when the channel was created, and its description. One flat row per company, no API key, no login.
Transcript pulling is included as an optional extra and is currently gated by YouTube. Read the Known limits section before you turn it on, and note that you are never charged for a transcript that did not arrive.
💡 Why use YouTube Channel Stats Extractor?
Channel stats are the reliable half and they work today. Subscriber, video and view counts, channel id, creation date and description, resolved from a domain with no API key.
Transcripts are shipped but currently gated by YouTube, and this listing says so rather than letting you find out. Measured 2026-08-22: the caption track LIST is reachable, and the caption CONTENT endpoint answers HTTP 200 with an empty body unless the request carries a proof of origin token minted by YouTube's own player. So on most videos today you will get transcript_status: "not_extractable", which means the video has captions and we could not read them. You are not charged for those. The transcript event fires only on text actually returned.
It starts from a domain. YouTube tools take a channel URL. If you hold a domain list, the channel URL is what you are missing, and YouTube is the easiest platform in this family to resolve: 14 of 14 measured B2B homepages declare their channel.
It tells you the count is rounded, and it parses the rounding correctly. YouTube renders "902 thousand subscribers". A parser that only understands K, M and B reads that as 902, a thousandfold undercount, and that exact bug has shipped on real actors. This one converts long scale words first and has a test that would fail if it stopped doing so.
🧭 Why this scrapes rather than using the YouTube API
Decided per field, not as a preference:
- Channel stats: scraped. The API needs a key and a daily quota and rounds subscribers exactly the same way the page does, so it buys nothing.
- Transcripts: scraped, because there is no alternative. The YouTube Data API does not serve transcript text, and its captions download route requires OAuth as the channel owner, which no third party has.
- Exact subscriber counts: unavailable from either. YouTube rounds above about a thousand subscribers on the page and in the API.
So the actor needs no API key, and that is a consequence of the field by field answer rather than a design goal.
📋 What data can YouTube Channel Stats Extractor extract?
| Field | Type | Meaning |
|---|---|---|
degraded | boolean | True when this row could not be produced normally, for example the company site was unreachable and no discovery could run. A degraded row is never charged. |
degradation_reason | string | null | Why the row is degraded, in plain words. Null on a normal row. |
company_domain | string | null | The company domain this row is about, normalized. Null when only a handle or a name was supplied. This is the join key across the whole Mamba Labs fleet. |
company_name | string | null | The company name as supplied or derived. Improves search accuracy and is what the identity gate matches against. |
row_type | string | channel for the channel summary row, transcript for a per video transcript row. Filter on this before reading any other field: the two row types populate different columns. |
youtube_url | string | null | Canonical YouTube channel URL. |
youtube_handle | string | null | The channel handle, without the leading at sign. |
youtube_channel_id | string | null | The stable UC channel id. A handle can be changed by its owner; this cannot, so store this if you are tracking a channel over time. |
youtube_channel_name | string | null | The channel name as set by its owner. |
youtube_subscribers | integer | null | Subscriber count expanded from what YouTube renders. YouTube rounds every channel above about 1,000 subscribers, so read youtube_subscribers_exact before summing. |
youtube_subscribers_display | string | null | Exactly what YouTube rendered, for example "902K". Kept beside the expanded number so the precision is always visible. |
youtube_subscribers_exact | boolean | null | True only below YouTube's rounding floor. False for essentially every real brand channel, because YouTube rounds and there is no exact figure on the page or in its API. |
youtube_video_count | integer | null | Number of public videos on the channel, where the layout declares it. Frequently null: as of 2026-08-22 YouTube's channel layout carries per playlist video counts rather than a channel level one, and reporting a playlist count here would be a wrong number rather than a missing one. |
youtube_total_views | integer | null | Lifetime channel views, where the layout declares them. Frequently null for the same reason as video count: the only view figure on the current layout belongs to one featured video, not to the channel. |
youtube_joined_date | string | null | When the channel was created, as YouTube renders it. |
youtube_description | string | null | The channel about text. |
youtube_discovery | string | null | How the channel was found: input_handle, homepage_sameas, homepage_link, search or pattern_guess. YouTube is declared on 14 of 14 measured B2B homepages, so this is usually a direct read of the company site. |
youtube_status | string | ok, not_found, not_extractable, blocked, identity_mismatch, auth_failed or skipped. not_extractable means the channel loaded and its subscriber count is hidden, which is a real and common owner setting. |
video_id | string | null | On a transcript row, the YouTube video id. Null on a channel row. |
video_url | string | null | On a transcript row, the video watch URL. Null on a channel row. |
video_title | string | null | On a transcript row, the video title. |
transcript_text | string | null | On a transcript row, the full transcript as plain text with no timestamps. This is the field to feed an LLM. |
transcript_timestamped | string | null | On a transcript row, the transcript as newline separated "[mm:ss] text" lines. Flat text rather than a nested array, so it survives a Clay column and a spreadsheet cell. |
transcript_language | string | null | Language code of the transcript that was pulled. |
transcript_is_auto_generated | boolean | null | True when the transcript is YouTube's automatic speech recognition rather than a human caption track. Auto generated transcripts carry recognition errors and this flag is how you know to expect them. |
transcript_status | string | null | ok, not_found, not_extractable, blocked or skipped. not_found means the video has no caption track at all, which is common and is a real answer. |
run_date | string | ISO 8601 timestamp of this run. Social counts move, so a row without a date is a number with no shelf life. |
Filter on row_type first. A run with transcripts on returns one channel row plus one transcript row per video, and the two populate different columns. A channel row has null transcript fields; a transcript row has null channel counts.
🛠️ How to pull a company's YouTube channel and transcripts
- Put a company domain in
company_domain, or a handle inhandle. - Leave
includeTranscriptsatfalsefor channel stats only. That is the cheap, fast configuration and it is what most buyers want. - Set it to
trueand settranscriptVideoCountto pull transcripts for that many recent videos. - For a list, pass an array of objects.
🧪 Using it in Clay
Add an Enrichment > Apify column, map company_domain.
For channel stats, leave transcripts off and you get one clean row per company. For transcripts, be aware that one input row produces several output rows, which is a one to many shape: run it as its own table rather than as a column on your account table.
💵 How much does it cost?
Pay per event. You are charged for output, never for input.
| Event | Fires when | Price |
|---|---|---|
company-checked | Once per company for which the discovery cascade completed and a non degraded channel row was produced, whether or not a channel was found. Does not fire on a degraded row. | $0.0035 |
profile-resolved | Once per company whose candidate channel URL passed the identity gate. Fires on the validation work, not on a populated subscriber cell. | $0.0025 |
follower-count-extracted | Once per channel where a numeric subscriber count was read off the public page. Does not fire when the owner has hidden the count, which reports not_extractable. | $0.0025 |
transcript-extracted | Once per video for which transcript TEXT was actually returned. A video with no caption track does not charge, and neither does a video whose caption track exists but whose content YouTube refused to serve. Never fires when transcripts are turned off. This is deliberately strict: the fetch costs us roughly a cent whether or not it yields text, and the buyer should not carry that. | $0.0150 |
Transcripts are billed per video that actually returned text. A video with no caption track costs you nothing, because nothing was delivered.
transcriptVideoCount is the dial that sets the cost of a transcript run: five videos is five transcript events.
What the same coverage costs bought a la carte: streamers/youtube-channel-scraper charges $0.0013 per result for channel and video inventory and takes a channel URL. Dedicated transcript actors on the Store sit in the $0.001 to $0.005 per video range. This actor is priced in the same band and adds domain to channel resolution, which neither does.
⌨️ Input
| Field | Type | Required | Meaning |
|---|---|---|---|
company_domain | string | no | Bare company domain, for example shopify.com. Supply this or a handle. With a domain the actor runs full discovery; with a handle it skips straight to the fetch. |
company_name | string | no | Optional. Improves search accuracy and is what the identity gate checks a discovered profile against, so supplying it reduces wrong matches. |
handle | string | no | Optional. A YouTube handle such as @shopify, or a full channel URL. Supplying it skips discovery and goes straight to the channel. |
includeFollowerCounts | string | no | When "true" (default) the profile page is fetched and the counts are extracted. Set "false" to resolve the profile URL only, which is cheaper and needs no proxy. Sent as a string for Clay compatibility. |
skipCache | string | no | When "false" (default) a successful lookup is cached for seven days and reused. Set "true" to force a fresh fetch. Sent as a string for Clay compatibility. |
includeTranscripts | string | no | When "true", full timestamped transcripts are pulled for the most recent videos on the channel and returned as one row per video. Default is "false" because transcripts are the expensive half of this actor and most buyers want channel stats only. Sent as a string for Clay compatibility. |
transcriptVideoCount | string | no | How many of the channel's most recent videos to pull transcripts for, when transcripts are on. Default 5. Each video is one extra fetch and one extra billable transcript event, so this is the dial that sets the cost of a transcript run. |
{"company_domain": "shopify.com","company_name": "Shopify","includeTranscripts": "false"}
📤 Output
One flat, snake_case row per company. No nested objects, so it drops straight into Clay, a spreadsheet or a warehouse table without a flattening step.
{"degraded": false,"degradation_reason": null,"company_domain": "shopify.com","company_name": "Shopify","row_type": "channel","youtube_url": "https://www.youtube.com/@shopify","youtube_handle": "shopify","youtube_channel_id": "UCIv38OrggTu3vNkCAo96-CQ","youtube_channel_name": "Shopify","youtube_subscribers": 902000,"youtube_subscribers_display": "902K","youtube_subscribers_exact": false,"youtube_video_count": null,"youtube_total_views": null,"youtube_joined_date": "Aug 22, 2008","youtube_description": "Shopify is the leading global commerce company.","youtube_discovery": "homepage_link","youtube_status": "ok","video_id": null,"video_url": null,"video_title": null,"transcript_text": null,"transcript_timestamped": null,"transcript_language": null,"transcript_is_auto_generated": null,"transcript_status": null,"run_date": "2026-08-22T09:00:00.000Z"}
false versus null, and why the difference matters
false means we looked and the answer is no. null means we could not look,
or the platform withheld it. They are never interchangeable in this output. If
you filter for companies with no presence on this platform, filter on false,
because null rows are unknown rather than absent and including them will
overstate your list.
💡 Tips
- Leave transcripts off unless you need the text. The channel page is 1.9 MB and the transcripts are extra fetches on top.
- Store
youtube_channel_id, not the handle. Handles can be changed by their owner. transcript_is_auto_generated: truemeans expect recognition errors, especially on product names and jargon. Worth knowing before you feed it to a model.- Use
transcript_textfor LLM input andtranscript_timestampedfor humans who need to find the moment.
⚠️ Known limits
- Subscriber counts are rounded by YouTube above roughly a thousand subscribers, on the page and in the official API alike. There is no exact figure to be had.
youtube_subscribers_exactmarks it. - Transcript extraction is currently gated by YouTube and mostly returns
not_extractable. This is the headline limitation. Measured 2026-08-22 across every available route: the caption track list is readable over residential routing, and the caption content endpoint returns HTTP 200 with a zero byte body without a proof of origin token minted by YouTube's player. The actor distinguishes this from a video that genuinely has no captions, and charges for neither. - Not every video has a transcript. Many have no caption track at all. That returns
transcript_status: "not_found", which is a real answer about the video, and it is not charged. - Auto generated transcripts contain recognition errors. The flag tells you which ones they are.
- Channels can hide their subscriber count. That is an owner setting and it reports
not_extractable, not zero. - The channel page is the heaviest fetch in this actor family at 1.9 MB to 3.5 MB. It is cheap in money over datacenter routing and it is not fast.
- No comments, no per video engagement metrics, no watch time.
- Channel level video count and total views are frequently null. YouTube's current channel layout publishes per playlist video counts and a single featured video's view count, neither of which is a channel total. This actor returns null rather than reporting one of those as if it were the channel figure.
❓ FAQ
Does this need a YouTube API key? No. And the API would not help: it does not serve transcript text at all, and it rounds subscriber counts exactly as the page does.
Why can I not get an exact subscriber count? YouTube rounds it everywhere it publishes it. Anyone offering you an exact figure is either a channel owner or guessing.
Why do I get several rows for one company?
Because transcripts are on. One channel row plus one transcript row per video. Filter on row_type.
What if a video has no captions?
transcript_status is not_found and you are not charged for that video.
What is the difference between not_found and not_extractable on a transcript?
not_found means the video genuinely has no caption track. not_extractable means it HAS one and YouTube would not serve us the text. The distinction matters: a tool that reported both as "no transcript" would tell you a captioned video has no captions. Neither is charged.
Can I pass a handle or a channel URL instead of a domain?
Yes, in handle.
🧩 Want other GTM data?
Mamba Labs builds a fleet of GTM enrichment actors that share one flat,
Clay-ready output convention, so their rows join on company_domain with no
cleaning step:
- Company Firmographic Enricher headcount, industry, location and revenue band from a domain, joins on
company_domain. - Domain to LinkedIn URL Resolver the company LinkedIn URL for domains where the social mapper found none.
- GTM Hiring Signal Scraper open go to market roles, which is the buying signal a follower count is a proxy for.
- Company Social Presence Mapper every platform in one row when you want breadth rather than depth on one network.
Full fleet: apify.com/mambalabs
🆘 Support
Issues, field requests and bug reports: open an issue on the actor's Issues tab. Mamba Labs reads every one.