# Skool Community Scraper - Discovery, Details & Owner Intel (`apricot_blackberry/skool-scraper`) Actor

Scrape public Skool.com data: search/browse the Discovery directory and extract community details — name, member count, pricing, description, owner name, bio and social links. No login required. JSON/CSV export.

- **URL**: https://apify.com/apricot\_blackberry/skool-scraper.md
- **Developed by:** [Creator Fusion](https://apify.com/apricot_blackberry) (community)
- **Categories:** Lead generation, Social media, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Skool Scraper — Community Data, Discovery Search & Owner Intel for AI Agents & Lead Gen

Extract public **Skool community data** without logging in and get it back as **typed JSON rows — schema below**. This Skool scraper searches the official [Skool Discovery](https://www.skool.com/discovery) directory and pulls full details for any community: name, **member count**, pricing, description, and the **community owner's name, bio, location, and social links**. That owner block makes it a **creator-economy lead generation** tool — every Skool owner is a creator running a paid or free membership business, and each detail row hands you their audience size, price point, and contact surface. It works over plain HTTP against Skool's own Next.js data route (no browser, no login, no cookies), so runs are fast and the default **datacenter proxy** is enough — no residential proxy costs.

### Why AI agents use this Skool scraper

- **Deterministic typed output** — every row conforms to the published dataset schema; fields are stable across runs and nullable fields are explicitly typed.
- **Per-event pricing** — one charge per row scraped plus a run-start fee, so autonomous agents can budget a run before launching it.
- **No auth needed** — no Skool account, cookies, API keys, or browser; only public data.
- **Clear error semantics** — bad input fails fast with a non-zero exit; per-URL failures in details mode are pushed as rows with an `error` field, never silently dropped.
- **Rate-limit handling built in** — automatic retries with backoff on HTTP 429/5xx, per-session proxy rotation.

### Input schema

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `mode` | string enum: `discovery`, `details` | yes | `discovery` | What to scrape. `discovery` searches/browses the Skool Discovery directory; `details` fetches full data (incl. owner intel) for specific community URLs. |
| `searchTerms` | array of strings | no | `["ai"]` (prefill) | Search queries for the Discovery directory, one result set per term. Use a single empty string (`""`) to browse the top communities without a keyword. Ignored in details mode. |
| `communityUrls` | array of strings | no | `["https://www.skool.com/synthesizer"]` (prefill) | Skool community URLs like `https://www.skool.com/{slug}` or `.../{slug}/about`. Required in details mode (the run fails fast without them). Ignored in discovery mode. |
| `maxItems` | integer (min 1) | no | `50` | Maximum communities to scrape: applied per search term in discovery mode, and as an overall cap across all URLs in details mode. |
| `proxyConfiguration` | object (proxy) | no | `{ "useApifyProxy": true }` | Default Apify datacenter proxy is sufficient (no residential needed) — Skool sits behind AWS WAF and may challenge unproxied IPs, so keep a proxy enabled. |

### Output schema

Every row has a `type` discriminator: `"discovery"` or `"detail"`.

| Field | Type | Nullable | Modes | Description |
|---|---|---|---|---|
| `type` | string | no | both | `"discovery"` or `"detail"`. |
| `searchTerm` | string | yes | discovery | Query that produced the row; `null` when browsing all. |
| `position` | integer | no | discovery | 1-based rank within the search term's results. |
| `name` | string | no | both | Community display name. |
| `slug` | string | no | both | URL slug (`https://www.skool.com/{slug}`). |
| `url` | string | no | both | Canonical community URL. |
| `description` | string | yes | both | Short community description. |
| `longDescription` | string | yes | details | Long landing-page description. |
| `members` | integer | yes | both | Total member count. |
| `admins` | integer | yes | details | Number of admins. |
| `posts` | integer | yes | details | Total posts. |
| `rules` | integer | yes | details | Number of community rules. |
| `courses` | integer | yes | details | Number of courses. |
| `modules` | integer | yes | details | Number of course modules. |
| `isPrivate` | boolean | no | details | `true` if the community is private (metadata still public). |
| `price` | object | no | both | `{ isFree, currency, amount, interval }`. Free communities: `isFree: true` and `null` for the rest. `amount` is in major units (9 = $9.00). |
| `membershipModel` | integer | no | discovery | Skool's internal membership model code. |
| `membershipProducts` | array of objects | yes | details | Raw Skool membership product objects (tiered plans); `null` if none. |
| `links` | array of objects | yes | details | External links from the about page; `null` if none. |
| `owner` | object | yes | details | Owner profile: `handle`, `firstName`, `lastName`, `fullName`, `profileUrl`, `bio`, `location`, `avatarUrl`, and `socials` (`website`, `youtube`, `instagram`, `twitter`, `facebook`, `linkedin` — each URL or `null`). `null` if unparseable. |
| `avatarUrl` | string | yes | both | Community logo URL. |
| `coverUrl` | string | yes | both | Community cover image URL. |
| `color` | string | yes | both | Community brand color (hex). |
| `groupId` | string | yes | both | Skool's internal group ID. |
| `createdAt` | string (ISO 8601) | yes | both | When the community was created. |
| `scrapedAt` | string (ISO 8601) | no | both | When this row was scraped. |
| `error` | string | — | details (error rows) | Only on per-URL failure rows, which carry just `type`, `slug`, `url`, `error`. |

#### Example item — discovery mode

```json
{
  "type": "discovery",
  "searchTerm": "ai",
  "position": 1,
  "name": "AI Video Bootcamp",
  "slug": "aivideobootcamp",
  "url": "https://www.skool.com/aivideobootcamp",
  "description": "Master AI Video & AI Image Creation...",
  "members": 26612,
  "price": { "isFree": false, "currency": "usd", "amount": 9, "interval": "month" },
  "membershipModel": 0,
  "avatarUrl": "https://assets.skool.com/f/.../logo.jpg",
  "coverUrl": "https://assets.skool.com/f/.../cover-md.jpg",
  "color": "#f8d481",
  "groupId": "a1b2c3d4e5f6",
  "createdAt": "2025-10-06T19:45:35.441626Z",
  "scrapedAt": "2026-08-14T12:00:00.000Z"
}
```

#### Example item — details mode

```json
{
  "type": "detail",
  "name": "Synthesizer: Free Skool Growth",
  "slug": "synthesizer",
  "url": "https://www.skool.com/synthesizer",
  "description": "Learn how to grow a Skool community.",
  "longDescription": "Everything you need to start, grow and monetize...",
  "members": 46198,
  "admins": 12,
  "posts": 18302,
  "rules": 3,
  "courses": 2,
  "modules": 14,
  "isPrivate": false,
  "price": { "isFree": true, "currency": null, "amount": null, "interval": null },
  "membershipProducts": null,
  "links": [{ "title": "YouTube", "url": "https://youtube.com/@..." }],
  "owner": {
    "handle": "kirby",
    "firstName": "Andrew",
    "lastName": "Kirby",
    "fullName": "Andrew Kirby",
    "profileUrl": "https://www.skool.com/@kirby",
    "bio": "Host of Skool Platinum @ Skool",
    "location": null,
    "avatarUrl": "https://assets.skool.com/f/.../avatar.jpg",
    "socials": {
      "website": "https://www.skool.com/synthesizer/",
      "youtube": null,
      "instagram": null,
      "twitter": null,
      "facebook": null,
      "linkedin": null
    }
  },
  "avatarUrl": "https://assets.skool.com/f/.../logo.jpg",
  "coverUrl": "https://assets.skool.com/f/.../cover-md.jpg",
  "color": "#ffffff",
  "groupId": "f6e5d4c3b2a1",
  "createdAt": "2023-01-15T10:00:00.000000Z",
  "scrapedAt": "2026-08-14T12:00:00.000Z"
}
```

### Error semantics

- **Bad input fails fast.** An invalid `mode`, or `details` mode without `communityUrls`, throws immediately: the run fails with a non-zero exit code and a descriptive status message. Nothing is charged beyond the run start.
- **Per-URL failures are per-item, never silent.** In details mode, an unreachable or unparseable community pushes a row `{ "type": "detail", "slug", "url", "error": "<message>" }` and the run continues with the next URL. Filter on the presence of `error` to detect failures; such rows are not charged as `community-detail` events.
- **Unrecognized URLs are skipped** with a log warning (no row pushed).
- **Discovery page errors stop that term only.** A non-200/non-JSON discovery response ends pagination for the current search term; other terms still run.
- **Transient errors are retried.** HTTP 429 and 5xx get up to 3 attempts with increasing backoff before counting as a failure.
- **Zero results is a successful run** with an empty dataset — not an error. Agents should treat an empty dataset as "no matches", not as a failure to retry.

### Use from AI agents (MCP)

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?tools=apricot_blackberry/skool-scraper",
      "headers": { "Authorization": "Bearer <YOUR_APIFY_TOKEN>" }
    }
  }
}
```

Works in Claude, Cursor, ChatGPT deep research connectors, and any MCP client; the input schema above is the tool's parameter schema.

### Use from code

**curl** (synchronous run, returns dataset items):

```bash
curl -X POST "https://api.apify.com/v2/acts/apricot_blackberry~skool-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"discovery","searchTerms":["ai"],"maxItems":50}'
```

**JavaScript** (`apify-client`):

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('apricot_blackberry/skool-scraper').call({
    mode: 'discovery',
    searchTerms: ['ai'],
    maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

**Python** (`apify_client`):

```python
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("apricot_blackberry/skool-scraper").call(run_input={
    "mode": "discovery",
    "searchTerms": ["ai"],
    "maxItems": 50,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

### Use from automation platforms

- **n8n / Make / Zapier** — use the native Apify integration and pick the actor by name (`apricot_blackberry/skool-scraper`).
- **LangChain / LlamaIndex** — use the Apify tool wrappers (`ApifyActorsTool` / Apify Actor loaders) with the same input JSON.
- **Webhooks** — Apify webhooks can fire on run completion (e.g. `ACTOR.RUN.SUCCEEDED`) to push new community/lead rows into your own pipeline automatically, no polling required.

### Pricing

Pay per event — you only pay for what you scrape:

| Event | Charged |
|---|---|
| `actor-start` | Once per run |
| `discovery-result` | Per community row from discovery |
| `community-detail` | Per full community detail row |

### FAQ

**Can I scrape Skool without logging in?**
Yes. This actor only reads public data embedded in Skool's public pages — the Discovery directory and community about pages. No account, cookies, or password needed.

**How do I get the member count of a Skool community?**
Run details mode with the community URL, or discovery mode with a search term — every row includes `members`.

**How do I find Skool community owners for lead generation?**
Run discovery for your niche keyword, sort by `members`, then feed the URLs into details mode. Each detail row includes the owner's name, bio, and social links — a ready-made prospect list of creators who already run paid communities.

**Does it work for private communities?**
Yes for metadata — private communities still expose name, member count, pricing, and owner on their public about page. Post content inside private communities is not accessible.

**Do I need residential proxies?**
No. The actor uses plain HTTP against Skool's own Next.js data route, and the default Apify datacenter proxy is sufficient.

### Changelog

- **1.0.1** — Published dataset output schema (typed, validated rows); agent-first docs with MCP, API, and automation-platform integration snippets.
- **1.0** — Initial release: discovery search + pagination, community details with owner intel, pay-per-event pricing.

# Actor input Schema

## `mode` (type: `string`):

What to scrape. `discovery` searches/browses the Skool Discovery directory; `details` fetches full data (incl. owner intel) for specific community URLs.

## `searchTerms` (type: `array`):

Search queries for the Discovery directory, one result set per term. Use a single empty string ("") to browse the top communities without a keyword. Ignored in details mode.

## `communityUrls` (type: `array`):

Skool community URLs like https://www.skool.com/{slug} or .../{slug}/about. Required in details mode (the run fails fast without them). Ignored in discovery mode.

## `maxItems` (type: `integer`):

Maximum communities to scrape: applied per search term in discovery mode, and as an overall cap across all URLs in details mode.

## `proxyConfiguration` (type: `object`):

Proxy to use. Default Apify datacenter proxy is sufficient (no residential needed) — Skool sits behind AWS WAF and may challenge unproxied IPs, so keep a proxy enabled.

## Actor input object example

```json
{
  "mode": "discovery",
  "searchTerms": [
    "ai"
  ],
  "communityUrls": [
    "https://www.skool.com/synthesizer"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Typed JSON rows in the default dataset - community discovery results and full community details with owner intel.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchTerms": [
        "ai"
    ],
    "communityUrls": [
        "https://www.skool.com/synthesizer"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("apricot_blackberry/skool-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchTerms": ["ai"],
    "communityUrls": ["https://www.skool.com/synthesizer"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("apricot_blackberry/skool-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "ai"
  ],
  "communityUrls": [
    "https://www.skool.com/synthesizer"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call apricot_blackberry/skool-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,apricot_blackberry/skool-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/BAd6eIugLi8Umv39u/builds/9sD7eVdMXoIsVOlXN/openapi.json
