email: "" for everyone except the authenticated user. Even community owners get masked emails for third parties when calling GET /users/{id}.
The admin panel has an "Export" button that does give you everything — emails, tiers, LTV, survey answers — but only if you click it manually. For a CRM sync pipeline, that's not enough.
This post shows how to call that same export programmatically via the Skool All-in-One API actor on Apify. One HTTP request, full member roster as JSON, ready to pipe into NocoDB / Airtable / Postgres / anywhere.
It's the foundation of the CRM single-source-of-truth pipeline I run for Cágala, Aprende, Repite (700+ members).
What you'll need
- An Apify account (free tier covers this — the export costs ~0ドル.05/run)
- Skool admin/owner cookies for your community
- A community where you're admin (export is admin-only)
If you've never used the actor before: it wraps Skool's entire REST surface so you don't have to handle cookies, WAF token rotation, weekly buildId changes, or the 3-step async pattern Skool's export uses internally. One JSON POST → parsed response.
The one-liner that returns your full roster
curl -X POST \
"https://api.apify.com/v2/acts/cristiantala~skool-all-in-one-api/run-sync-get-dataset-items?token=$APIFY_TOKEN&timeout=60&build=latest" \
-H "Content-Type: application/json" \
-d '{
"action": "members:export",
"cookies": "auth_token=...; client_id=...; aws-waf-token=...",
"groupSlug": "your-community",
"params": { "status": "active" }
}'
Response (one item per member, already parsed — no CSV parsing on your side):
[{"firstName":"Maria","lastName":"Lopez","email":"maria@example.com","invitedBy":"Cristian Tala","joinedDate":"2026-04-12 18:14:56","survey":[{"question":"What's your LinkedIn?","answer":"linkedin.com/in/marialopez"},{"question":"What are you building?","answer":"SaaS for restaurants"},{"question":"How did you find us?","answer":"Newsletter"}],"tier":"standard","ltv":"0ドル"}]
The actor handles the underlying 3-step flow Skool's admin UI runs when you click Export:
-
POST /groups/{id}/request-bulk-action?type=bulk-export-csv → returns {token, file_id}
-
GET /wait?token={token} → polls until completed (2-8 sec typically)
-
POST /files/{file_id}/download-url → signed CloudFront URL → GET that → CSV body → parse to JSON
You don't see any of that. One call in, parsed JSON out.
Filter what you export
{"params":{"status":"active","tiers":["premium","vip"]}}
| Param |
Values |
Default |
status |
active / cancelling / churned / banned
|
active |
tiers |
array of your community's tier slugs |
all tiers |
Useful for cohort analysis: "all premium members who joined in the last 30 days" → filter status: active, tiers: ["premium"], then client-side filter by joinedDate.
The data quality reality nobody mentions
Measured against a real production community of 700+ members:
-
~68% of members have a populated
email field. The other ~32% (typically members who joined via the Skool Discovery network — the platform's "browse communities" feature) don't share their email with the community owner. Skool keeps that field empty in the export. This is structural, not a bug.
-
~88% have a LinkedIn URL in their first survey answer (when the apply form asks for it). Apply-form answers are far more complete than the email field.
-
invitedBy is empty unless the member came through a tracked Skool referral link.
For the ~32% with no email, fall back to the LinkedIn URL from the survey. That's typically enough to identify the member for outreach.
What the export does NOT include
One important gap: the acquisition source (Joined from LinkedIn / Joined from your blog / Joined from Skool network) is NOT in the export. It lives in member.metadata.attrSrcComp on the SSR member object — accessed via a separate call:
{"action":"members:list","cookies":"...","groupSlug":"...","params":{"all":true}}
members:list returns joinedFrom / joinedVia per member — the missing piece for attribution analytics. Merge both responses by memberId if you need the full picture.
Pipe straight to your CRM
Two production patterns I use:
A. Nightly snapshot → NocoDB. Cron runs the export, diffs against yesterday's, upserts into a personas table keyed by email. New rows get joined_at, missing rows get churned_at. This is the single-source-of-truth for the CRM.
B. On-demand cohort pull. Export tier: ["premium"], filter rows where joinedDate >= 30 days ago, send each to a personalized email sequence in Postmark. The survey array gives the personalization data: their LinkedIn, what they're building, where they heard about you.
# JSON snapshot
curl ... > members-$(date +%F).json
# Or convert to CSV with jq
curl ... | jq -r '
(.[0] | [.firstName, .lastName, .email, .joinedDate, .tier, .ltv] | @csv),
(.[] | [.firstName, .lastName, .email, .joinedDate, .tier, .ltv] | @csv)
' > members-$(date +%F).csv
Gotchas I hit so you don't have to
-
build.stale error = expired cookies, not a bug. Skool's aws-waf-token rotates every ~3.5 days. Re-run auth:login with email+password to get fresh cookies. The actor returns a clear errorCode: BUILDID_STALE with the exact JSON payload you need to re-auth.
-
Don't poll the export every 5 minutes. Designed for daily/weekly snapshots. The CSV is generated on-demand by Skool — calling it on every webhook is wasteful and you'll eventually hit rate limits.
-
Large communities (10K+ members) can take 30+ seconds to generate. Set your HTTP client timeout to at least 90 sec.
-
invitedBy is empty unless the member came through a tracked referral. All blanks doesn't mean broken — just means no member came through your ref link.
Why this actor exists
I run my own Skool community alone — no team, no virtual assistants. Approving members, replying to posts, publishing courses, exporting member data for follow-up. Everything in this actor (and the 20 production recipes in the docs) exists because I needed it to keep up with the daily work as a solo admin.
If you're running a Skool community without a team and the manual admin clicks are eating your day, the actor is built for you.
→ Use the Skool All-in-One API actor on Apify — pay-per-event (~1ドル.50/mo typical).
→ Full recipe with all the edge cases
New to Skool? Launch your community here — 14-day free trial.