A YouTube channel scraper in Python can collect channel names, subscriber counts, and URLs. That solves extraction. It does not solve creator qualification.
For outreach, the expensive mistake is not missing one channel. It is spending time on channels that stopped publishing, no longer reach viewers, use the wrong content format, or expose no public business-contact route.
This tutorial builds a bounded Python workflow that returns active creator prospects instead of a raw channel dump.
Define active before scraping
“Active” needs a rule. A practical first pass might require:
- at least one video per month;
- a public upload within the last 60 days;
- at least 1,000 median views across a recent sample;
- 5,000–250,000 subscribers;
- long-form or Shorts content that matches the offer.
Those values are not universal. A thumbnail agency, affiliate manager, recruiter, and mobile-app sponsor will use different thresholds. The important part is to write the rule before seeing the results.
Install the Apify client
pip install apify-client
Load your token from an environment variable. Never place it in the script or commit it to Git.
export APIFY_API_TOKEN="..."
Run a qualified channel search
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_API_TOKEN"])
run_input = {
"preset": "qualified_shortlist",
"niches": ["AI automation", "B2B SaaS"],
"languages": ["en"],
"countries": ["US", "CA", "GB"],
"worldwideLanguageMode": False,
"minSubscribers": 5_000,
"maxSubscribers": 250_000,
"minVideosPerMonth": 1,
"lastUploadWithinDays": 60,
"minRecentMedianViews": 1_000,
"contentFormats": ["long-form", "Shorts"],
"requirePublicBusinessContact": False,
"maxChannels": 10,
"videosAnalyzedPerChannel": 10,
"maximumSearchCalls": 12,
}
run = client.actor("kazkn/youtube-creator-lead-finder").call(
run_input=run_input,
)
dataset = client.dataset(run["defaultDatasetId"])
creators = dataset.list_items().items
The Actor discovers candidates from the requested niches and queries. Channel URLs remain optional. It deduplicates output by channelId inside the run and writes one Dataset row per qualified channel.
Inspect recent performance, not lifetime totals
For each returned creator, the most useful review fields are recent:
for creator in creators:
print({
"channel": creator["channelName"],
"url": creator["channelUrl"],
"subscribers": creator.get("subscriberCount"),
"last_upload": creator.get("lastUploadAt"),
"videos_per_month": creator.get("estimatedVideosPerMonth"),
"median_views": creator.get("recentMedianViews"),
"score": creator.get("opportunityScore"),
"reasons": creator.get("opportunityReasons", []),
"warnings": creator.get("warnings", []),
})
Median recent views are especially useful because one viral upload can distort an average. The sample is still bounded, so keep its warnings and do not present the metric as a complete channel history.
Match the content format to the offer
A channel can be active and still be the wrong prospect.
- A long-form editing service may prioritize
longFormRatio. - A vertical-video agency may prioritize
shortsRatio. - A webinar or streaming product may prioritize
liveRatio.
The output also includes a format confidence value. Shorts classification uses a duration heuristic from available public API data, so uncertain cases should remain visible rather than being forced into a perfect category.
Keep geography and language evidence separate
Search region, declared country, inferred country, and detected language are different facts.
The Dataset keeps them separate through fields such as:
-
declaredCountry; -
inferredCountries; -
countryConfidence; -
primaryLanguage; -
detectedLanguages; -
languageConfidence.
If the brief asks for French-speaking creators worldwide, leave countries empty and set worldwideLanguageMode to True. Do not silently turn the search region into the creator’s declared location.
Export the shortlist to CSV
import csv
columns = [
"channelId",
"channelName",
"channelUrl",
"subscriberCount",
"lastUploadAt",
"estimatedVideosPerMonth",
"recentMedianViews",
"shortsRatio",
"longFormRatio",
"publicBusinessEmail",
"contactSourceUrl",
"opportunityScore",
]
with open("qualified-youtube-creators.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(file, fieldnames=columns, extrasaction="ignore")
writer.writeheader()
writer.writerows(creators)
Keep contactSourceUrl, opportunityReasons, and warnings in the production export. They are the audit trail behind the row.
Public contacts are evidence, not enrichment
The workflow can collect a professional email, website, social profile, or management route only when the creator exposed it in accessible public channel text.
It does not reveal YouTube’s protected business-email field, bypass CAPTCHA, sign in, guess private addresses, or fetch linked websites. An empty contact field is preferable to an invented address.
Start with a bounded public Task
The public Export Qualified YouTube Channels to CSV Task opens with a small editable input and the qualified Dataset view:
Run the CSV-ready YouTube channel scraper
For the complete input schema, output contract, limits, and live pricing, see YouTube Creator Lead Finder.
A useful scraper does not stop when it has extracted the channel. It stops when the row is qualified enough for a human to make the next decision.
Top comments (0)