# Skool Group Scraper By Category & Filter (`scrapio/skool-group-scraper`) Actor

Skool Group Scraper by Category & Filter finds relevant Skool communities by category and advanced filters. Extract group names, descriptions, URLs, member counts, categories, creators, and public community data for market research, prospecting, and audience discovery.

- **URL**: https://apify.com/scrapio/skool-group-scraper.md
- **Developed by:** [Scrapio](https://apify.com/scrapio) (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

from $3.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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 Group Scraper — Extract Communities, Owners and Pricing Data

Skool Group Scraper By Category & Filter searches Skool's public discovery directory by keyword, category, and language, then narrows the results to a price type and a minimum member count — before any row reaches your dataset. Instead of returning raw HTML or the entire discovery firehose, it returns typed JSON: one record per community, carrying pricing, membership stats, course counts, and the owner's public profile fields, ready for a database, a spreadsheet, or an LLM context window without any parsing. No Skool account or login is required — everything is read from Skool's own public pages. This guide covers every input and output field, and how teams actually run this Actor in production: enrichment pipelines, scheduled monitoring, and bulk dataset builds.

### 🧭 What Does Skool Group Scraper Do?

Skool is the community platform behind thousands of paid and free membership groups — course creators, coaches, and niche communities that charge monthly or annual dues through Skool's own billing. This Actor drives a real browser against Skool's public `/discovery` directory and each community's public `/about` page, resolves your search and filter inputs against Skool's own category and language lists, and returns one JSON record per matching community. No Skool account, cookie, or login is required — discovery and `/about` pages are both public.

- Searches Skool's discovery directory server-side by keyword (`q`), category (`c`), and language (`lang`)
- Resolves a category **name** you type (e.g. `Money`, `Health`) to Skool's internal 32-character category id automatically
- Resolves a language name or 2-letter code (e.g. `Spanish` or `ES`) to Skool's `lang` value
- Filters client-side on price type (all / free / paid) and minimum member count, before a row is ever built
- Enriches every matching community from its public `/about` page: pricing, membership settings, course/module counts, owner name/bio/location/social links, and landing-page attachments
- Runs one or more discovery URLs in a single job, deduplicating communities seen across all of them
- Ships an automatic proxy fallback ladder so most runs need no proxy configuration at all

### Features & Capabilities

Skool Group Scraper By Category & Filter combines Skool's own server-side search with client-side filtering that never charges you for a row you didn't want.

**Core features.** Server-side discovery search sends `searchKeyword`, `category`, and `language` straight to Skool's discovery data route as `q`, `c`, and `lang`, so filtering happens on Skool's servers, not by scanning every page yourself. Name-to-id category resolution lets you type `Money`, `Self-improvement`, or `Spirituality` and have it matched (case- and emoji-insensitive) against the live category list embedded in the discovery page; a raw 32-hex category id also works directly. Client-side price and size filters (`priceType`, `minMembers`) are evaluated against each community's real `monthlyPrice`, `annualPrice`, and `totalMembers` fields *during* pagination, not as a separate post-processing pass — so filtered-out communities never reach your dataset. Every kept community carries the full record: `monthlyPrice`, `monthlyCurrency`, `annualPrice`, `annualCurrency`, `totalMembers`, `totalPosts`, `numCourses`, `numModules`, `ownerName`, `ownerBio`, `ownerLocation`, and 50+ more fields, listed in full below.

**How Skool Group Scraper compares to other Skool scrapers.** Feature comparison based on this Actor's source code and the competitors' own Apify Store listings, checked 2026-07-25:

| Feature | Skool Group Scraper By Category & Filter | memo23/skool-members-scraper | gordian/skool-group-scraper |
| --- | --- | --- | --- |
| Category & language filter (server-side) | ✅ | Not documented | Not documented |
| Price-type / minimum-member filter before charge | ✅ | Not documented | Not documented |
| Login or cookie required | ❌ Never | ✅ Required for member scraping (cookie-based auth) | Not documented |
| Entity scope | Communities (discovery listings) | Communities + individual members | Communities |
| Proxy handling | Automatic NO\_PROXY → datacenter → residential fallback | Manual residential proxy recommended for blocking | Not documented |
| Output format | Typed JSON | JSON, CSV, Excel, HTML, XML (Apify platform formats) | JSON, CSV, Excel (Apify platform formats) |

If your use case is feeding structured data to an LLM or a filter pipeline, the "filter before charge" row is the decision-maker — paying per row for communities you're about to discard client-side is a cost problem, not a data problem, and neither competitor above documents doing this filtering before the row is billed.

**When another tool might suit you better.** If you need **individual member profiles** inside a Skool community — names, bios, social contacts, activity data for each person who joined — this Actor isn't the right tool: it returns one record per *community*, not per member. memo23/skool-members-scraper is built for that member-level entity, though it requires you to supply your own Skool session cookies and be a member of the group you want to scrape. If you already have a short, fixed list of exact group URLs and don't need any keyword, category, language, price, or member-count filtering, a simpler single-purpose group scraper like gordian/skool-group-scraper may be a lighter-weight fit.

#### Skool Group Scraper within the Scrapio data stack

Skool Group Scraper By Category & Filter covers Skool **communities** discovered through search and filters. For **individual Facebook group discovery** with size, privacy, and keyword qualification — the closest cross-platform equivalent to this Actor's filter-before-charge approach — use Facebook Groups Search Scraper By Member Count & Keyword Match. For **community owner/admin contact extraction** on Facebook, use Facebook Group Admin Contact Scraper. Both are Scrapio Actors, and both apply the same "filter before you're charged" principle to a different platform.

### Why do developers and data teams scrape Skool?

Skool hosts thousands of paid and free membership communities across coaching, courses, fitness, trading, and hobby niches — a market that's opaque from the outside unless you can see pricing, size, and category at scale.

- 🏢 **Course creators and community operators** research pricing and positioning before launching a new community: pull every `paid` community in a category (e.g. `Fitness`), read `monthlyPrice`, `totalMembers`, and `numCourses` across the set, and see what a viable price point and course depth look like in that niche before setting your own.
- 📊 **AI training data and RAG indexing** — `description` and `landingPageDescription` are the highest-information text fields for embedding into a RAG index of "what communities exist for X"; `totalMembers`, `monthlyPrice`, `numCourses`, and `numModules` are the structurally consistent numeric fields best suited to training a classifier or ranking model, since they appear as typed integers on every enriched record rather than free text that needs parsing.
- 📱 **Competitive and market intelligence** — track `monthlyPrice` and `totalMembers` for a named set of competing communities over repeated runs to see who is raising prices, growing fastest, or expanding course catalogs (`numCourses`, `numModules`).
- 🔬 **Research and academic use** — discovery-directory snapshots by category and language support studies of the creator-economy and online-education market, using only Skool's publicly published community metadata.
- 🎥 **Product and SaaS development** — build a directory, leaderboard, or price-comparison product on top of Skool's public discovery data, refreshed on a schedule rather than hand-collected.

### 🍚 Input Parameters

All eight parameters, read directly from `.actor/actor.json`, in schema order. `urls` is the only required field.

| Parameter | Required | Type | Default / constraints | Description |
| --- | --- | --- | --- | --- |
| `searchKeyword` | No | string | — | Free-text search term sent to Skool's discovery search (the `q` parameter). Example: `fitness`, `notion`, `faceless`. |
| `category` | No | string | — | Filter to one Skool category by name — e.g. Money, Tech, Health, Sports, Music, Hobbies, Spirituality, Self-improvement. The name is resolved to Skool's internal category id automatically; a raw 32-char id also works. Unknown names are ignored (logged). |
| `language` | No | string | — | Filter to communities in one language. Use the English language name (e.g. Spanish, French, German) or its 2-letter code (e.g. ES). Resolved to Skool's `lang` value automatically. |
| `priceType` | No | string (select) | Default `"all"`. Enum: `all` (All communities), `free` (Free only), `paid` (Paid only) | Keep all communities, only free ones, or only paid ones. 'free' = no paid monthly/annual membership price. |
| `minMembers` | No | integer | Default `0`, minimum `0` | Only keep communities with at least this many members. 0 = no minimum. |
| `urls` | **Yes** | array (string list) | — | One or more Skool discovery URLs to search. The keyword / category / language above are applied on top of each URL. Default is the main discovery page. |
| `maxItems` | No | integer | Default `10`, minimum `1`, maximum `50000` | Maximum number of communities to collect per discovery URL (counted after filtering). Lower it for a quick preview. |
| `proxyConfiguration` | No | object (proxy editor) | Prefill `{"useApifyProxy": false}` | Turn on to run through Apify Proxy from the start. Leave off for the normal experience (fallback routes are handled for you). |

**Skool has no public developer API for its discovery directory**, so there's no official endpoint to build this against. Getting this data yourself means rendering Skool's Next.js discovery page, extracting and parsing the SSR-embedded `__NEXT_DATA__` JSON block, discovering the correct Next.js `buildId` to call the internal data route, resolving category names and language codes to Skool's internal ids, and handling the blocking countermeasures described in the FAQ below — all of which this Actor already does.

```json
{
  "searchKeyword": "fitness",
  "category": "Health",
  "language": "English",
  "priceType": "paid",
  "minMembers": 500,
  "urls": ["https://www.skool.com/discovery"],
  "maxItems": 100,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

#### Supported URL types and input formats

`urls` accepts a plain string, or an object of the form `{"url": "..."}` — both are normalized to the same list internally. A bare domain like `www.skool.com/discovery` (missing the `https://` scheme) has it prepended automatically.

- **Browse everything, filtered client-side only**: `urls: ["https://www.skool.com/discovery"]` with `priceType: "paid"` and `minMembers: 1000` and no `searchKeyword`/`category`/`language` — behaves like the plain discovery directory, narrowed only by price and size.
- **Full server-side search**: `urls: ["https://www.skool.com/discovery"]` with `searchKeyword: "notion"`, `category: "Tech"`, `language: "Spanish"` — all three are combined into the discovery search query before any client-side filter runs.
- **Multiple discovery pages in one job**: `urls: ["https://www.skool.com/discovery", "https://www.skool.com/discovery?q=trading"]` — each URL is searched independently with the same keyword/category/language/filters layered on top, and communities already collected from an earlier URL in the same run are never returned twice.

### 📦 Output Format

One JSON record per matching community, pushed to the default dataset as soon as that community's enrichment finishes — so the dataset fills incrementally during a run rather than all at once at the end. The charged event is `row_result`, one charge per pushed community. There is no separate uncharged accounting or "skipped" row for a community that fails your filters — it never becomes a record at all, because `priceType` and `minMembers` are evaluated *during* pagination, before a row is built. Nothing to filter out downstream; filtered-out communities simply never arrive.

#### Output for a Skool community

Every key the row-building code writes, from `map_group_to_output()` and `apply_about_enrichment()` in `src/extractor.py`. Nothing here is paraphrased — this is the literal field set, including the fields Skool exposes only on its `/about` page.

```json
{
  "id": "5bf05ef84e524567abab979b06b5cfb9",
  "name": "fitness-mastery-hub",
  "displayName": "Fitness Mastery Hub",
  "description": "Coaching, programming, and accountability for serious lifters.",
  "landingPageDescription": "Join 500+ members building strength with weekly programming, form checks, and live Q&As.",
  "supportEmail": "coach@fitnessmasteryhub.com",
  "monthlyPrice": 39,
  "monthlyCurrency": "usd",
  "annualPrice": null,
  "annualCurrency": null,
  "color": "#F4CBC4",
  "initials": "FM",
  "privacy": 1,
  "membership": 1,
  "plan": null,
  "landingPageAccessType": 1,
  "affiliatePercent": 0,
  "pluginAutoDmEnabled": 0,
  "pluginMinChatLevelEnabled": 0,
  "surveyEnabled": 0,
  "surveyQuestions": [],
  "surveyUpdatedAt": null,
  "logoUrl": "https://assets.skool.com/f/.../logo.png",
  "logoBigUrl": "https://assets.skool.com/f/.../logo-big.jpg",
  "coverSmallUrl": "https://assets.skool.com/f/.../cover-md.jpg",
  "faviconUrl": "https://assets.skool.com/f/.../favicon.png",
  "customLinks": [],
  "totalMembers": 548,
  "totalOnlineMembers": 12,
  "totalAdmins": 3,
  "totalPosts": 892,
  "totalRules": 5,
  "numCourses": 6,
  "numModules": 44,
  "audioChatVisible": false,
  "calendarVisible": true,
  "classroomVisible": true,
  "mapVisible": false,
  "landingPageAttachments": [
    {
      "id": "91549370e67a4bef9d5cec15d534dce0",
      "type": 2,
      "imageFileId": null,
      "imageOriginalUrl": null,
      "imageSmallUrl": null,
      "imageBigUrl": null,
      "videoId": null,
      "videoUrl": "https://www.loom.com/share/example",
      "videoThumbnailUrl": "https://cdn.loom.com/sessions/thumbnails/example.gif"
    }
  ],
  "ownerId": "58d5ff2786ba4883b39251cd22701d1b",
  "ownerName": "coach-mel",
  "ownerFirstName": "Mel",
  "ownerLastName": "Rivera",
  "ownerBio": "Strength coach. 10 years coaching lifters online.",
  "ownerLocation": "Austin, TX",
  "ownerDiscTop": null,
  "ownerActivityStatus": null,
  "ownerMyersBriggs": null,
  "ownerOnline": 0,
  "ownerLastOffline": "1764200517573641700",
  "ownerPictureProfile": "https://assets.skool.com/f/.../profile.jpg",
  "ownerPictureBubble": "https://assets.skool.com/f/.../profile-sm.jpg",
  "ownerInstagram": "https://instagram.com/coachmel",
  "ownerYoutube": null,
  "ownerFacebook": null,
  "ownerTwitter": null,
  "ownerLinkedin": null,
  "ownerWebsite": "https://fitnessmasteryhub.com/",
  "ownerCreatedAt": "2022-05-25T02:10:03.534129Z",
  "ownerUpdatedAt": "2025-11-27T00:31:39.759122Z",
  "createdAt": "2024-09-10T22:04:42.873505Z",
  "updatedAt": "2025-12-14T20:57:33.896160Z",
  "createdBy": "58d5ff2786ba4883b39251cd22701d1b",
  "matchedCategory": { "name": "Health", "id": "a1b2c3d4e5f60718293a4b5c6d7e8f90" },
  "discoveryRank": 1
}
```

**Nested output — landing page attachments and matched category.** `landingPageAttachments` is an array of objects, one per media block on the community's landing page: `id`, `type` (Skool's internal attachment-type integer), `imageFileId`, `imageOriginalUrl`, `imageSmallUrl`, `imageBigUrl`, `videoId`, `videoUrl`, and `videoThumbnailUrl`. Image and video fields are mutually exclusive per attachment — an image attachment carries null video fields and vice versa. `matchedCategory` is a two-key object — `{ "name", "id" }` — holding the category your `category` input resolved to for this run; it is identical across every row in the same run and is `null` when no category filter was supplied.

**Schema stability and export options.** Field names stay stable across runs because they're read directly from Skool's own `__NEXT_DATA__` payload and `/about` page structure rather than scraped from rendered HTML text — if Skool's front-end styling changes, the underlying data keys generally don't. Two things worth knowing before you rely on specific fields:

- `affiliatePercent`, `pluginAutoDmEnabled`, `pluginMinChatLevelEnabled`, `surveyEnabled`, `surveyQuestions`, `surveyUpdatedAt`, and `customLinks` are currently always returned as a fixed placeholder (`0`, `false`, `[]`, or `null`) rather than the community's real configured value — `apply_about_enrichment()` never writes to these seven keys, so they don't vary between communities in this Actor's output today.
- Every other field is either populated from the discovery listing, overwritten with the real value from the community's `/about` page during enrichment, or left `null` when Skool doesn't expose it for that community — fields are never fabricated to fill a gap.
- Enrichment from `/about` is attempted up to twice per community. If both attempts fail (a slow load, a transient block), the community is still pushed to the dataset, but only with the fields the discovery listing already carried — `landingPageDescription`, `supportEmail`, `ownerId`/`ownerName`/`ownerBio`/`ownerLocation` and the rest of the owner block, `totalPosts`, `totalRules`, `numCourses`, `numModules`, and `landingPageAttachments` stay at their pre-enrichment default of `null` (or `[]` for the attachments list) rather than being silently guessed.
- `monthlyPrice`, `monthlyCurrency`, `annualPrice`, and `annualCurrency` are read once from the discovery listing's pricing metadata and are not re-fetched during `/about` enrichment, since Skool's `/about` page doesn't re-expose pricing separately from the discovery payload.

Results export from the Apify platform in JSON, JSONL, CSV, Excel (XLSX), HTML table, XML, or RSS — the same export formats available to any Apify dataset, accessible from the Storage tab or the Apify API.

### 💡 Skool Group Scraper Strategy Guide

**⚠️ Real constraint to plan around:** internal pagination during a search stops after roughly 60 discovery pages per URL (`scan_cap` in `src/extractor.py`), even if `maxItems` hasn't been reached yet — a strict `minMembers` or `priceType` filter combined with a narrow category can exhaust the available discovery results before your target count. Widen the category or drop a filter if a run consistently returns fewer rows than `maxItems`.

**Strategy 1 — Real-time enrichment pipeline.** Trigger a run from your signup or CRM webhook whenever a lead mentions a specific Skool niche, with `searchKeyword` set to that niche and `maxItems` kept low (10–25) for a fast turnaround. Read back `displayName`, `monthlyPrice`, `totalMembers`, and `ownerName`/`ownerWebsite` from the dataset and append them to the CRM record as market context before your sales team reaches out. Because rows stream to the dataset as each community finishes enrichment, a downstream watcher can start reading before the run itself completes.

**Strategy 2 — Scheduled monitoring and alerting.** Set up an Apify Schedule (e.g. weekly) with a fixed `category` and `priceType: "paid"`. Compare each run's `totalMembers` and `monthlyPrice` per `name` (the stable community slug) against the previous run's dataset, and alert when a competitor's `totalMembers` jumps sharply or `monthlyPrice` changes. This Actor doesn't diff runs internally — the comparison happens in your own pipeline between the two datasets Apify keeps for you.

**Strategy 3 — Bulk dataset build.** Run one job per category (Money, Health, Tech, and so on) or per keyword you care about, each with a high `maxItems`, then merge the resulting datasets into one CSV or database table for market research or a training set. Keep `minMembers` low or unset in this mode — filtering narrows the *set*, not the crawl depth, so an aggressive filter combined with the ~60-page scan ceiling above can under-fill a bulk run.

**Strategy comparison at a glance**

| Strategy | Best for | Run pattern | Output format |
| --- | --- | --- | --- |
| Real-time enrichment | CRM/lead enrichment on inbound signals | Webhook → single narrow run → append fields | Streamed JSON rows via Apify API |
| Scheduled monitoring | Tracking price/size changes in a niche | Apify Schedule → diff against prior run's dataset | JSON dataset per run |
| Bulk dataset build | Market research / training datasets | One run per category or keyword → merge | CSV / JSON, merged externally |

### 🌴 Related Skool Scrapers & Tools

| Scraper | What it extracts |
| --- | --- |
| Facebook Groups Search Scraper By Member Count & Keyword Match | Facebook groups qualified by member count, privacy, activity, and keyword match — the closest cross-platform equivalent to this Actor's filter-before-charge approach |
| Facebook Group Admin Contact Scraper | Admin and moderator contact leaderboard for a Facebook group — the adjacent use case of turning a community's leadership into outreach contacts |

Scrapio does not currently publish a second Skool community scraper — this Actor is the category-and-filter entry point to Skool's discovery directory in the Scrapio catalog.

### How to integrate Skool Group Scraper with your stack

Skool Group Scraper By Category & Filter works with any language or tool that can make an HTTP request to the Apify API, or call it through Apify's official client libraries.

**Python** — full working script: run the Actor, pull the dataset, export the fields you care about to CSV.

```python
from apify_client import ApifyClient
import csv

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run_input = {
    "searchKeyword": "fitness",
    "category": "Health",
    "priceType": "paid",
    "minMembers": 500,
    "urls": ["https://www.skool.com/discovery"],
    "maxItems": 100,
}

run = client.actor("<YOUR_USERNAME>/skool-group-scraper-by-category-filter").call(run_input=run_input)

rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())

with open("skool_communities.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "displayName", "totalMembers", "monthlyPrice", "ownerName"])
    writer.writeheader()
    for row in rows:
        writer.writerow({k: row.get(k) for k in writer.fieldnames})

print(f"Saved {len(rows)} communities to skool_communities.csv")
```

**Node.js** — same pattern, using the JS client.

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });

const input = {
    searchKeyword: 'fitness',
    category: 'Health',
    priceType: 'paid',
    minMembers: 500,
    urls: ['https://www.skool.com/discovery'],
    maxItems: 100,
};

const run = await client.actor('<YOUR_USERNAME>/skool-group-scraper-by-category-filter').call(input);
const { items } = await client.dataset(run.defaultDatasetId).listItems();

for (const community of items) {
    console.log(community.displayName, community.totalMembers, community.monthlyPrice);
}
```

**Async and scheduled pipelines.** For fire-and-forget large jobs, start the run via `apify_client`'s async call and poll or subscribe to an Apify webhook on the `ACTOR.RUN.SUCCEEDED` event instead of blocking on the run. For recurring jobs, use an Apify Schedule to run this Actor automatically on a cron-style interval (hourly, daily, weekly) — the pattern used in Strategy 2 above.

### Who needs Skool Group Scraper? Use cases and industries

- 🏢 **Course creators and community operators** pull every `paid` community in their target category to benchmark `monthlyPrice`, `totalMembers`, and `numCourses` before setting their own pricing and course depth.
- 📊 **Growth and marketing teams** track `totalMembers` and `monthlyPrice` for a named list of competitor communities over repeated scheduled runs to catch pricing changes and growth spikes early.
- 📱 **Lead-generation and outreach teams** use `ownerName`, `ownerWebsite`, and `supportEmail` (where a community's `/about` page publishes one) to build an outreach list of community owners in a given niche.
- 🔬 **Researchers** studying the online-education and creator-economy market pull category- and language-filtered snapshots of Skool's public discovery directory for market-sizing and trend analysis, using only publicly published community metadata.

### Is it legal to scrape Skool?

Scraping publicly accessible web data is generally legal in the United States — in *hiQ Labs, Inc. v. LinkedIn Corp.*, 938 F.3d 985 (9th Cir. 2019), the Ninth Circuit held that scraping data not behind a login wall does not violate the Computer Fraud and Abuse Act. Skool's `/discovery` directory and each community's `/about` page are both public, unauthenticated pages, and this Actor never logs in or accesses anything behind a paywall.

Separately, scraping in a way that violates a platform's Terms of Service can expose you to civil claims (breach of contract) even where it isn't criminal — that risk sits with how you use this Actor, not with the Actor itself. Because community-owner fields (`ownerName`, `ownerLocation`, `ownerBio`, social links, and any `supportEmail` a community publishes) are personal data about an identifiable individual, storing or using them for commercial purposes may bring data protection laws like GDPR or CCPA into play depending on your jurisdiction and use case.

Skool Group Scraper By Category & Filter returns only publicly accessible data. What you do with that data is your responsibility — consult legal counsel for commercial applications involving personal data.

### ❓ Frequently asked questions

**Does Skool Group Scraper By Category & Filter work without a Skool account?** Yes. The Actor never logs in, and no cookies or credentials are accepted as input — it reads Skool's public `/discovery` directory and each community's public `/about` page.

**How does it handle Skool's anti-scraping measures?** It waits for Skool's SSR-embedded `__NEXT_DATA__` script tag rather than network-idle (Skool's SPA has continuous background traffic that never goes idle), adds a random 1–2 second delay before loading each discovery page, and — unless you supply your own proxy — automatically escalates through a no-proxy → datacenter-proxy → residential-proxy ladder if a request is blocked. The no-proxy and datacenter tiers are each tried once before stepping up; the residential tier retries up to 3 times with a fresh session id and a short randomized backoff between attempts, and once a run has fallen back to residential it stays there for the rest of that run rather than stepping back down. Turning on your own `proxyConfiguration` skips the ladder entirely and routes every request through your configured proxy from the first request, with no automatic fallback tier.

**Can I run it at scale without getting blocked?** `maxItems` accepts up to 50,000 per discovery URL, and detail-page enrichment runs 3 communities concurrently, a value fixed in the Actor's code rather than exposed as input. Internal pagination stops after roughly 60 discovery pages per URL regardless of `maxItems`, so a very strict filter combined with a narrow category can return fewer rows than requested. No uptime or success-rate figure is published for this Actor.

**How fresh is the data Skool Group Scraper returns?** Live. Every run drives a real browser against Skool's current `/discovery` and `/about` pages at the moment the run executes — nothing is cached or served from a prior run.

**Which fields work best for AI training and RAG indexing?** For RAG, index `description`, `landingPageDescription`, and `ownerBio` — the free-text fields with the most semantic content about what a community actually offers. For structured training features, `totalMembers`, `monthlyPrice`, `numCourses`, and `numModules` are the most consistently populated numeric fields across enriched records. All fields return as typed primitives (strings, integers, booleans, or `null`) requiring no text parsing before use.

**Does scraping the community owner's data raise data protection concerns?** The Actor returns only what a community's public `/about` page already publishes about its owner — name, bio, location, and any social links or support email the owner chose to display. Lawful basis for storing and using that personal data for your own purposes sits with you, not with the Actor.

**Does Skool Group Scraper work with Claude, ChatGPT, and other AI agent tools?** There's no dedicated MCP server for this Actor. It's callable as a standard Apify Actor through the Apify API or `apify-client` SDKs, so any agent framework that can make an HTTP call or invoke a registered tool function can trigger a run and read back typed JSON — no HTML parsing required before passing results into a model's context window.

**What happens if my category or language filter doesn't match anything?** An unrecognized `category` name is logged as a warning and ignored — the run continues without that filter rather than failing, falling back to a plain keyword search or the full discovery listing. An unrecognized `language` value is passed through as a lowercased string to Skool's `lang` parameter as a best-effort fallback.

**How does Skool Group Scraper compare to other Skool scrapers?** As of 2026-07-25, memo23/skool-members-scraper covers more ground for individual member-level data but requires you to supply Skool session cookies and be a member of the target group — this Actor needs neither, because it only reads community-level discovery and `/about` data. gordian/skool-group-scraper accepts direct group URLs with a simple input shape, but neither its listing nor easyapi/skool-groups-scraper documents server-side category, language, price-type, or minimum-member filtering — the filtering this Actor applies before a row is ever billed.

### Disclaimer

Skool Group Scraper By Category & Filter extracts only publicly available data from Skool. This tool is intended for lawful use cases only. Users are responsible for complying with Skool's terms of service and applicable data protection laws in their jurisdiction.

# Actor input Schema

## `searchKeyword` (type: `string`):

Free-text search term sent to Skool's discovery search (the `q` parameter). Example: fitness, notion, faceless.

## `category` (type: `string`):

Filter to one Skool category by name — e.g. Money, Tech, Health, Sports, Music, Hobbies, Spirituality, Self-improvement. The name is resolved to Skool's internal category id automatically; a raw 32-char id also works. Unknown names are ignored (logged).

## `language` (type: `string`):

Filter to communities in one language. Use the English language name (e.g. Spanish, French, German) or its 2-letter code (e.g. ES). Resolved to Skool's `lang` value automatically.

## `priceType` (type: `string`):

Keep all communities, only free ones, or only paid ones. 'free' = no paid monthly/annual membership price.

## `minMembers` (type: `integer`):

Only keep communities with at least this many members. 0 = no minimum.

## `urls` (type: `array`):

One or more Skool discovery URLs to search. The keyword / category / language above are applied on top of each URL. Default is the main discovery page.

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

Maximum number of communities to collect per discovery URL (counted after filtering). Lower it for a quick preview.

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

Turn on to run through Apify Proxy from the start. Leave off for the normal experience (fallback routes are handled for you).

## Actor input object example

```json
{
  "searchKeyword": "fitness",
  "category": "Money",
  "language": "Spanish",
  "priceType": "all",
  "minMembers": 0,
  "urls": [
    "https://www.skool.com/discovery"
  ],
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

All scraped items in the Actor's default dataset.

# 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 = {
    "urls": [
        "https://www.skool.com/discovery"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapio/skool-group-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 = {
    "urls": ["https://www.skool.com/discovery"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapio/skool-group-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 '{
  "urls": [
    "https://www.skool.com/discovery"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call scrapio/skool-group-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapio/skool-group-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/sqyGhSRypahI1arlB/builds/gQKPMHT5zAKoKTO3Z/openapi.json
