This repository is a small, tested Python client for the SocialBlade Stats Scraper on Apify. Feed it a list of accounts across YouTube, Twitch, Instagram and TikTok, and it returns one row per account with the audience size, the letter grade SocialBlade assigns, a rank breakdown and, if you ask for it, a short daily history of follower movement. The heavy lifting happens on Apify, so your script stays a few dozen lines long. Locally you end up with results.json and results.csv, ready for a DataFrame, a spreadsheet or a scheduled archive.
Actor: SocialBlade Stats Scraper Β· Publisher: Devil Scrapes Β· Also in JavaScript: socialblade-scraper-javascript
- Four networks, one schema: a YouTube channel and a TikTok account land in the same columns, with
follower_countmeaning subscribers on YouTube and followers everywhere else. - Name a target two ways: a
platformplushandlepair, or a full SocialBlade profile URL, which wins if both are present. Mix networks freely in onetargetslist. - Daily history on request: with
includeHistoryon,growth_historyholds up to 15 dated snapshots of followers, plus views and content count where the network has them. Switch it off for lighter rows. - Network-specific extras stay null elsewhere: Instagram rows add engagement rate and average likes and comments, TikTok rows add lifetime likes and the verified flag, YouTube rows add total views.
- Counts are numbers: figures SocialBlade delivers as text are converted to integers, so sorting and arithmetic work without cleanup.
- One dead handle does not end the run: throttled or failed requests are retried up to five times with growing pauses on a new proxy session, and a target that still fails is logged and skipped.
Marketing analysts often need to know where a brand's audience actually grows. Run a company's YouTube, Instagram and TikTok handles together, normalise the daily history and the network where followers rise fastest stands out in one sorted table.
Agencies can load a shortlist of candidate channels, check grade, the ranks dictionary and recent momentum, then drop accounts whose following has flattened. Doing this in a notebook leaves a reproducible record of why each channel made the cut.
Each row carries at most 15 daily snapshots. Schedule python main.py --out snapshots/$(date +%F) from cron every week, append the rows and drop duplicate dates, and after a quarter you hold a continuous series for every account you track.
Students and analysts studying platform dynamics can sample many accounts per network and compare grades, follower counts and growth rates. One schema across four platforms removes most of the reshaping work before the statistics start.
You need an Apify account and an API token from Console β Settings β Integrations. Apify's free plan includes monthly usage credit; this Actor's event prices are listed under Pricing below.
git clone https://github.com/devilscrapes/socialblade-scraper-python.git
cd socialblade-scraper-python
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
export APIFY_TOKEN=your_token_here
python main.py # uses input.json
python main.py my-input.json --out data --max-charge 2The script starts the SocialBlade Stats Scraper, waits for it to finish, prints a link to the run in Apify Console and saves every result to results.json and results.csv. It exits with code 1 and the run's status message if the run fails.
Leave out argument parsing and file output and very little remains: a client, a call that waits for the run, and a loop over the stored rows.
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("DevilScrapes/socialblade-stats-scraper").call(run_input={'targets': [{'platform': 'youtube', 'handle': 'mrbeast6000'}], 'includeHistory': True, 'maxItems': 1, 'proxyConfiguration': {'useApifyProxy': True, 'apifyProxyGroups': ['RESIDENTIAL']}})
for item in client.dataset(run.default_dataset_id).iterate_items():
print(item)The script hands input.json to the Actor untouched. The bundled file asks for one very large public YouTube channel, the target the Actor's own daily platform test uses, with history switched on and maxItems at 1, so a first run stays small. Replace it with your own list, mixing platforms freely, or pass a SocialBlade profile link as url.
{
"targets": [
{
"platform": "youtube",
"handle": "mrbeast6000"
}
],
"includeHistory": true,
"maxItems": 1,
"proxyConfiguration": {
"useApifyProxy": true,
"apifyProxyGroups": [
"RESIDENTIAL"
]
}
}| Field | Type | Required | Default | Allowed values |
|---|---|---|---|---|
targets |
array | yes | [{"platform": "youtube", "handle": "mrbeast6000"}] |
β |
includeHistory |
boolean | no | true |
β |
maxItems |
integer | no | 100 |
β |
proxyConfiguration |
object | no | {"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]} |
β |
You get one row per account that SocialBlade could answer for. grade is SocialBlade's own score passed through unchanged, and ranks is a nested object with overall, primary, views, country and category positions, any of which may be null. growth_history is a list of dictionaries with a date and the counts for that day, and it can be empty when SocialBlade keeps no history for an account.
| Field | Type | Always present |
|---|---|---|
platform |
string | yes |
handle |
string | yes |
channel_id |
string or null | no |
display_name |
string or null | no |
avatar_url |
string or null | no |
follower_count |
integer | yes |
view_count |
integer or null | no |
content_count |
integer or null | no |
grade |
string | yes |
country |
string or null | no |
ranks |
object or null | no |
engagement_rate |
number or null | no |
avg_likes |
number or null | no |
avg_comments |
number or null | no |
total_likes |
integer or null | no |
verified |
boolean or null | no |
growth_history |
array | yes |
source_url |
string | yes |
scraped_at |
string | yes |
| Event | Price (USD) |
|---|---|
| Actor start | $0.2 |
| Result emitted | $0.001 |
Prices as configured on 2026-10-16. The Actor page always shows the current price. Runs are billed to the Apify account that owns the token. Use --max-charge to cap what a single run can cost.
The pandas snippet below (pip install pandas) flattens every account's daily history into one long table, then measures each account's net gain, gain per day and percentage growth across the window it covers. The result is saved to growth_window.csv.
import json
import pandas as pd
rows = json.load(open("results.json", encoding="utf-8"))
daily = pd.json_normalize(rows, record_path="growth_history", meta=["platform", "handle"])
daily["date"] = pd.to_datetime(daily["date"], utc=True)
daily = daily.sort_values(["platform", "handle", "date"])
window = daily.groupby(["platform", "handle"]).agg(
first_day=("date", "min"),
last_day=("date", "max"),
start=("follower_count", "first"),
end=("follower_count", "last"),
)
window["days"] = (window["last_day"] - window["first_day"]).dt.days.clip(lower=1)
window["net_gain"] = window["end"] - window["start"]
window["gain_per_day"] = (window["net_gain"] / window["days"]).round(1)
window["growth_pct"] = (100 * window["net_gain"] / window["start"]).round(3)
print(window.sort_values("growth_pct", ascending=False).to_string())
window.to_csv("growth_window.csv")No. The Actor reads the profile data SocialBlade shows without logging in, and the only credential your script needs is an Apify API token.
No. Those estimates are filled in by the browser after the page loads and are not part of the data the Actor reads, so they are left out rather than guessed.
A handle SocialBlade does not know, or a profile that kept failing after five attempts, produces no row; the run log names it. The run's status message reports how many targets succeeded out of how many were requested.
The Actor stops starting new targets after about 20 minutes and saves what it has. For very large lists, split them across several runs or schedules so every account is reached.
Set APIFY_TOKEN first: export the token in the same shell, or put it in a local.envfile your shell loads. Never commit it.- Run finished with
FAILEDorABORTED: open the printed Console link; the run log says why. Input validation errors name the field. - Fewer rows than expected: a
--max-chargecap also limits how many results can be charged. Raise the cap or lower the limits in your input. - Something looks wrong in the data: open an issue on the Actor page so the maintainers see it.
- SocialBlade Stats Scraper on Apify Store
- JavaScript version of this example
- All Devil Scrapes Actors
- Apify web scraping cookbook
Related Actors:
- YouTube Channel Videos Scraper β channel metadata and recent videos straight from YouTube.
- YouTube Shorts Sponsorship Signals Scraper β spot sponsored Shorts before you pitch a channel.
- Patreon Creator Scraper β patron counts and tiers for the creator side of the economy.
MIT licensed example code. The Actor itself runs on Apify and is maintained by Devil Scrapes. Not affiliated with SocialBlade.