TL;DR. Skool has no public API, so reading/writing data programmatically requires going through Skool’s internal endpoints — which are protected by cookies + AWS WAF + a
buildIdthat rotates weekly. Building a maintainable Skool scraper is a ~50-hour engineering project that breaks weekly. The legitimate alternative is the Apify-hosted Skool All-in-One API actor — same data, structured response, ~$1.50/mo, maintained.
What people mean by “Skool scraper”
There are three different things people search “skool scraper” for:
- Export their own community’s data — own admin access, want a backup or to migrate. See Export Skool members to CSV / Sheets / CRM.
- Automate their own community — own admin access, want to post / approve programmatically
- Scrape someone else’s community — no admin access, want public data or scraping past member lists
This page covers (1) and (2). For (3) — that’s not what the actor does, and we don’t recommend it (legal, ethical, and reliability issues).
Why a hand-rolled scraper is harder than it looks
If you curl https://www.skool.com/your-community you get back HTML wrapped around an __NEXT_DATA__ script tag containing some of the data — but only the public view, no admin actions, no real-time data, no API calls.
The internal API at api.skool.com is what the Skool web app and mobile apps call. To reach it:
1. Authentication via Playwright
There’s no Authorization: Bearer header. Skool uses cookies issued after a real browser login flow. You have to drive a headless Chromium through the login screen, capture the resulting cookies, store them.
# Hand-rolled login (rough sketch — production needs much more)
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("https://www.skool.com/login")
page.fill("input[name=email]", "...")
page.fill("input[name=password]", "...")
page.click("button[type=submit]")
page.wait_for_url("https://www.skool.com/**")
cookies = page.context.cookies()
browser.close()
You now have auth_token, client_id, and several other cookies. But that’s not enough.
2. AWS WAF token rotation
Skool sits behind AWS WAF. Every request must include a fresh aws-waf-token. The token has a ~3.5-day TTL but the WAF can invalidate sooner under load patterns it considers suspicious. When invalid, you get a 403 with a JavaScript challenge embedded — Playwright can solve it, raw requests cannot. So your scraper needs a fallback Playwright session for token refresh.
3. buildId discovery
Skool’s Next.js app embeds a buildId in its HTML (<script id="__NEXT_DATA__">{"buildId":"abc123",...}</script>). API responses are sometimes shape-different across builds. You have to parse buildId from each page load and key your response parsers off of it.
When Skool deploys (~weekly), buildId changes, sometimes with breaking schema changes. Your scraper must detect this and adapt.
4. Endpoint coverage
Skool’s web app makes ~30 distinct endpoint calls across its surface. Each has:
- Its own request shape
- Its own response shape (different
successflag locations, different error shapes) - Its own pagination strategy (
page,cursor,tail=true,pinned=true) - Its own rate limit behavior
Reverse engineering them all takes 30-50 hours of focused work. Maintaining them takes ~2 hours per week as Skool ships.
5. Rate limiting
Skool’s hard limit on writes is ~25/min. Hit it and you get 429s for ~5 minutes. Your scraper needs a queue. Implementing this correctly (with backoff, deduplication, idempotent retries for safe operations) is another ~10 hours.
6. Error structure
Skool’s internal error responses are inconsistent across endpoints. Some return {error: "..."}, some {message: "..."}, some return 200 with {success: false} in the body, some 4xx with HTML. Your scraper needs a normalizer.
The cost of “I’ll just build my own”
I built one. Then I rebuilt it as the Apify-hosted Skool API actor. Approximate development time:
- Initial reverse engineering: 30 hours
- Authentication + WAF token handling: 8 hours
- Endpoint coverage (~25 actions): 20 hours
- Error normalization: 8 hours
- Rate limit queue: 6 hours
- TipTap markdown conversion (for course bodies): 10 hours
- File upload (for course covers): 4 hours
- Structured error contract: 4 hours
- Testing in a real production community: ongoing
Per-week maintenance: 1-3 hours when Skool ships. Past 12 months: ~80 hours of post-launch maintenance.
That’s all sunk cost so you don’t have to.
What the actor does that your scraper would have to
| Component | Your scraper | Actor |
|---|---|---|
| Playwright login | Build, host, maintain Chromium | One JSON POST, ~10s |
| WAF token refresh | Detect 403 + run Playwright fallback | Automatic, transparent |
buildId rotation |
Parse HTML weekly, adapt parsers | Automatic |
| Endpoint coverage | Reverse engineer ~25 endpoints | All wrapped |
| Error structure | Normalize 5+ different shapes | {success, errorCode, hint, retryable} |
| Rate limit queue | Build + test | Built-in |
| TipTap conversion | Build markdown→TipTap parser | Built-in (classroom:setBody) |
| File uploads | Multi-step signed URL flow | One files:uploadImage call |
| Production deployment | Your infra | Apify-hosted |
| Monitoring | Your dashboards | Apify run logs |
| Per-week maintenance | 1-3 hours | 0 hours |
When building your own would make sense
- You need to scrape at internet scale (1000s of communities you don’t own — but please don’t, it’s against Skool’s TOS)
- You have regulatory constraints that prevent third-party data flow (your data can’t go through Apify; rare)
- You need sub-100ms latency (the actor’s ~2s/call won’t work for high-frequency real-time)
For 99% of Skool automation use cases (own community admin operations), the actor is the better choice.
What about RapidAPI / other “Skool API” listings?
There are a few Skool API marketplaces (RapidAPI, others) that list scrapers. We’ve evaluated them:
- Most are single-endpoint wrappers (just
posts:listor justmembers:list) — not the full surface - Most don’t handle WAF token rotation, breaking randomly every few days
- None have a maintained, structured error contract
- Pricing is often subscription-based and more expensive than the actor’s pay-per-event
If you find one that works for your specific use case, great. For the full surface (read AND write across posts/members/classroom/files), the actor is currently the only complete option.
Related
- Skool API documentation
- Skool authentication — how cookies + WAF work
- Skool automation hub
- Skool + Python
Skip the build, use the actor
→ Open the Skool All-in-One API actor on Apify
Read AND write across the full Skool admin surface. One POST per action. Pay-per-event (~$1.50/mo typical). 80+ hours of maintenance done for you.
No Skool community yet? Launch one in 10 minutes — 14-day free trial.