I run a visa agency in Bali. The other half of my week goes into Apify Actors, and one of them turns YouTube channels into rows you can put in a CRM: subscribers, video count, every link the creator published, their socials, and the business e-mail where there is one.
The assumption everybody brings to that job — mine included, the first week — is that the channel page either has an address or it does not. It does not work like that. YouTube knows about a third address space it will not print, and the field that looks most like "the creator's website" is the one I trust least.
So I ran 30 channels and counted.
The run
Three queries through YouTube's own channel search — wedding photographer, home renovation, indie game developer — ten channels each, 25 October 2026. No handles of my own, nothing hand-picked, so the sample is whatever YouTube ranks. Median size 235,000 subscribers, smallest 1,070, largest 4.31M.
| Channels read | 30 of 30, zero errors |
| Subscriber + video count present | 30 of 30 |
| At least one social profile | 25 of 30 |
A website value |
28 of 30 |
| A readable e-mail | 17 of 30 |
| …from the channel itself | 11 |
| …from the linked website | 6 |
hasHiddenBusinessEmail |
27 of 30 |
| Button present, no readable address | 11 |
Whole run: 29.8 seconds, $0.26, no browser and no login.
The third address space
That hasHiddenBusinessEmail row is the one worth staring at. In the channel's ytInitialData blob there is a key called signInForBusinessEmail, and its presence means the creator filled in the "business inquiries" field in YouTube Studio. The address is real. Reading it needs a signed-in session and a captcha, which is a different and much more expensive kind of scraping than fetching a public page, so this Actor does not read it — it reports the flag and moves on.
27 of 30 creators had filed one. 17 published something in plain text somewhere. For 11 channels the button was the only contact route in existence — no address on the channel, none on the site, in several cases no site at all.
I kept the flag in the output because a null e-mail means two different things to whoever gets the CSV:
-
email: null, hasHiddenBusinessEmail: false— nothing to chase. Three channels in this run. -
email: null, hasHiddenBusinessEmail: true— a creator who wants business mail and is one manual click away. Eleven channels.
Collapsing those two into "no e-mail" throws away a third of the list. If you build your own version of this, keep the distinction even if you never scrape the button.
The website field is the first link, not the best one
website is defined as the first link the creator published that is not a known social profile. That definition sounds harmless and produces this:
| Channel | website |
|---|---|
| JonasTyroller | https://store.steampowered.com/app/2239150/Thronefall/ |
| Blackthornprod | https://blackthornprod.itch.io/ |
| JuniperDev | https://juniperdev-yt.itch.io |
| NewbieIndieGameDev | https://newbie-indie-game-dev.itch.io/ |
| TheRenovationProject | https://paypal.me/HomeReno728?country.x=FR |
| rooiwhoo | https://bio.site/rooiwhoo |
| coresfilmsweddings | https://vimeo.com/groups/weddinginpuntacana |
| InboundShovel | https://store.steampowered.com/app/3125320/Isadoras_Edge/ |
Eight of the 28 non-empty values point at somebody else's platform: a Steam product page, an itch.io subdomain, a PayPal tip jar, a link-in-bio, a Vimeo group. TheRenovationProject published exactly three links and all three were donation pages — the "website" of a 49,800-subscriber channel is a PayPal handle, because that is genuinely all they put up.
And the ordering bites even when a real site exists. HomeRenoVisionDIY, 4.31M subscribers, published nine links:
https://cavemantools.com <- website
https://www.homerenovisiondiy.com <- the actual site
https://youtube.com/channel/UCnor.../join
https://shoplowes.me/3Iyk7or
https://amzlink.to/az0wS4EEsW3QW
...
Their own domain is second. First is their tool brand, which is a legitimate business of theirs and not the thing you would put in a "website" column. Two rows below sit shoplowes.me and amzlink.to — affiliate redirects that would have won the slot on a channel without a homepage.
I have not pushed the obvious fix of blacklisting those hosts, and the reason is the indie game developers. For Blackthornprod, itch.io is the storefront; a null would be worse than an itch.io URL. So the honest handling is at your end: read links, not website, and decide against your own use case. Every link the creator published is in there, in published order, and website is a convenience that was right 20 times out of 28.
The second hop, and the addresses it has to throw away
Six of the 17 e-mails — 35% of everything found — were not on YouTube at all. They came from fetching the site the channel links to and reading the home page. HomeRepairTutor publishes two links, no address, and jeff@homerepairtutor.com is sitting on their homepage.
The first version of that hop was a disaster, in an instructive way. A creator's home page carries a lot of e-mail addresses belonging to other people: the booking widget, the site builder, the platform's support desk. It cheerfully returned callie@calendly.com and support@apppa.ge as creator contacts. Both are valid addresses. Both are worthless.
So an address scraped from a site is kept only if it is on that site's own domain, or on an ordinary mail provider; a known service domain is dropped rather than passed off as a lead. There is a list of about thirty of those, and it is the kind of list that only ever grows.
Note the asymmetry it creates, since I would rather you heard it from me: paypal is on the reject list for e-mail domains, while paypal.me passes the website filter and took the website slot above. The two filters were written for different jobs on different days. Writing this up is how I noticed.
E-mail domain and website domain agree less than half the time
A reflex when you have a channel and a domain is to guess the address: first.last@domain, info@domain. On the 17 channels where I had both a real e-mail and a real website:
- 6 sat on the same domain as the website, cleanly.
-
6 were on
gmail.comoryahoo.co.uk. - The rest were somewhere else entirely:
taylor@craterr.comfor a channel linkingtaylorjacksoncourses.com,jennaphipps@night.cofor a channel linkingjennaphipps.com,info@homerenovisiondiy.comon a channel whosewebsitewascavemantools.com.
A third of working creators route business mail through a personal Gmail. Pattern-guessing a corporate layout against their domain returns nothing and verifies as nothing — the published address is the only one that exists.
Calling it
No required fields, so an agent can call it correctly first try. The input that produced everything above:
curl -X POST "https://api.apify.com/v2/acts/lergassy~youtube-creator-contacts/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"searchQueries":["wedding photographer","home renovation","indie game developer"],
"maxChannelsPerQuery":10}'
Swap searchQueries for channels: ["mkbhd", "@veritasium", "https://youtube.com/@..."] when you already have the list — handles, @handles and full URLs are all accepted. minSubscribers and onlyWithEmail filter before billing, so the rows you reject are free.
One row from the run, trimmed:
{
"type": "channel",
"handle": "MagicWeddingPhotographer",
"title": "Magic Wedding Photographer",
"subscribers": 51000,
"videoCount": 325,
"email": "collaboration@magicweddingphotographer.com",
"emailSource": "channel",
"hasHiddenBusinessEmail": true,
"website": "https://www.magicweddingphotographer.com",
"links": [
"https://youtube.com/c/MagicWeddingPhotographer",
"https://www.instagram.com/magicweddingphotographer",
"https://www.magicweddingphotographer.com",
"https://education.magicweddingphotographer.com"
],
"instagram": "https://www.instagram.com/magicweddingphotographer",
"isFamilySafe": true,
"scrapedAt": "2026-10-25T21:09:23.054Z"
}
emailSource is channel or website, so you always know whether the creator typed that address into YouTube themselves — which matters when you write the first line of the e-mail. The actor is YouTube Creator Contacts; the last run cost $0.0087 per channel averaged over hits and misses.
Two bugs that looked like data
Both of these shipped, briefly, and neither threw an error.
Counting subscribers across the whole payload. ytInitialData for a channel also contains the channels YouTube recommends next to it. A regex for "([0-9.,]+[KMB]? subscribers)" over the full blob finds a neighbour's number first on some layouts. The count now comes only from the channel's own header block, with the About panel as fallback.
\n surviving into an address. In the JSON blob a newline is the two characters \ and n. A creator who writes Business:\nbusiness@studio.com yields the match nbusiness@studio.com — a syntactically perfect, completely wrong address that no validator will flag. One .replace(/\\[nrt]/g, ' ') before the e-mail regex. If you extract contacts from any embedded JSON blob, go check for this one now.
When this is the wrong tool
It reads the channel's About page and one page of the linked site. If you need contacts in depth — the /contact page, the team page, phone numbers, a crawl past the home page — that is a website job, not a YouTube job, and Website Contacts API is the one I point people at. If you need per-video data, view counts over time, or comments, this is the wrong shape entirely: one channel in, one flat row out, nothing about videos but how many there are.
And if your plan depends on reaching all of a list by e-mail, the measured ceiling here is 17 in 30 — on a sample YouTube chose, not one I curated. Eleven more are reachable through a button a human has to click. Build the workflow around that number rather than discovering it after the outreach sequence is written.
Top comments (0)