# Outschool Class Scraper (`crawlerbros/outschool-class-scraper`) Actor

Scrape Outschool's live-online and self-paced class catalog for kids and teens. Search by keyword, subject, and format; get pricing, ratings, age/grade ranges, teacher profiles, and schedules. Enrich individual class URLs with full syllabi, learning goals, and teacher bios.

- **URL**: https://apify.com/crawlerbros/outschool-class-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Automation, Developer tools, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Outschool Class Scraper

Scrape Outschool's catalog of live-online and self-paced classes for kids and teens. Search by keyword, subject, and format; get pricing, ratings, age/grade ranges, teacher profiles, and upcoming schedules. Enrich individual class URLs with full syllabi, learning goals, and teacher bios.

### What this actor does

- **Two modes:** `search` (keyword/subject/format search with rich filters) and `byUrls` (fetch full details for specific class URLs)
- **Filters:** class type (Academic Curriculum / Tutoring / Electives & Enrichment), subjects, format (live/self-paced), age range, price range, minimum rating, exclude ongoing clubs, only-available
- **Sorting:** price, rating, or newest
- **Rich detail enrichment:** full class description, teacher bio/credentials, learning goals, prerequisites, materials, and a lesson-by-lesson syllabus
- **No login, no cookies, no paid proxy** — public class-catalog data only, via the same GraphQL endpoints Outschool's own site explicitly allow-lists for crawlers in `robots.txt`
- **Empty fields are omitted** — every record only contains fields that have real data

### Output per class

- `title` — class title
- `sourceUrl` — canonical `outschool.com/classes/...` URL
- `classSlug` — Outschool's class slug ID
- `summary` / `quickSummary` — class description
- `subject` — top-level subject (e.g. `Coding & Tech`, `Math`)
- `classFormat` — `Live online` or `Self-Paced`
- `ageMin` / `ageMax`, `gradeLevelMin` / `gradeLevelMax`
- `durationMinutes`, `durationWeeks`, `weeklyMeetings`, `meetingCount` (mode=`byUrls`)
- `priceCents` / `priceDollars`
- `rating`, `reviewCount`
- `sizeMin` / `sizeMax` — class size range
- `isClub`, `isSelfPaced`, `isFlexSchedule`, `isOneTime`, `isAvailable`, `canEnroll`
- `imageUrl`, `videoUrl`, `videoThumbnailUrl`
- `teacherName`, `teacherUrl`, `teacherRating`, `teacherReviewCount`, `teacherPhotoUrl`
- `nextSectionStart` / `nextSectionEnd`, `spotsRemaining` (mode=`search`)
- `sectionCount`, `openSectionCount`, `upcomingSectionCount` — total / open / upcoming class sections (mode=`search`)
- `lessonCount`, `syllabus[]` (mode=`byUrls`: `title`, `description`, `lessonNumber`, `weekNumber`)
- `learningGoals[]`, `prerequisites`, `materials`, `classExperience`, `whyMe` (mode=`byUrls`)
- `teacherAbout`, `teacherHeadline`, `teacherCredentials[]`, `teacherCityState`, `teacherClassCount` (mode=`byUrls`)
- `publishedAt`, `isPublished`, `isSoldOut` (mode=`byUrls`)
- `recordType: "class"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byUrls` |
| `searchQuery` | string | `coding` | Free-text query. Leave empty to browse by subject/format only. |
| `classType` | select | – | `Course` (Academic Curriculum) / `Tutoring` / `Enrichment or Club` (Electives & Enrichment). Leave empty for all types. |
| `subjects` | array | – | `Coding & Tech` / `English` / `Math` / `Life Skills` / `Science & Nature` / `Games & Hobbies` / `World Languages` / `Social Studies` / `Arts` / `Music` / `Health & Wellness` / `Test Prep` |
| `formats` | array | – | `Live online` / `Self-Paced` |
| `onlyAvailable` | boolean | `true` | Skip sold-out / non-enrollable classes |
| `minAge` / `maxAge` | int | – | Age range overlap filter (3-18) |
| `minPriceDollars` / `maxPriceDollars` | number | – | Price range filter (USD) |
| `minRating` | number | – | Drop classes rated below this (0-5) |
| `excludeClubs` | boolean | `false` | Skip open-ended clubs, only structured classes |
| `sortBy` | select | `relevance` | `relevance` / `priceAsc` / `priceDesc` / `ratingDesc` / `newest` |
| `classUrls` | array | – | Class URLs to fetch (mode=`byUrls`) |
| `maxItems` | int | `30` | Hard cap on emitted records (1–500) |

#### Example: affordable self-paced coding classes for ages 10-14

```json
{
  "mode": "search",
  "searchQuery": "",
  "subjects": ["Coding & Tech"],
  "formats": ["Self-Paced"],
  "minAge": 10,
  "maxAge": 14,
  "maxPriceDollars": 100,
  "sortBy": "priceAsc",
  "maxItems": 50
}
```

#### Example: highest-rated live math classes

```json
{
  "mode": "search",
  "searchQuery": "math",
  "formats": ["Live online"],
  "minRating": 4.5,
  "sortBy": "ratingDesc"
}
```

#### Example: enrich specific class URLs with full syllabus

```json
{
  "mode": "byUrls",
  "classUrls": [
    "https://outschool.com/classes/all-about-python-coding-level-1-Y3R381hD"
  ]
}
```

### Use cases

- **Homeschool curriculum planning** — build a shortlist of classes filtered by age, subject, and budget
- **Edtech competitive analysis** — track Outschool's catalog breadth and pricing by subject
- **Teacher/instructor research** — pull ratings, credentials, and class history for specific educators
- **Content gap analysis** — compare subject/format coverage against your own platform
- **Price benchmarking** — analyze pricing distribution across subjects and formats

### FAQ

**Do I need an Outschool account?**  No. This actor only reads publicly available class-catalog data through the same GraphQL endpoints Outschool's own class-search page and class-detail pages call — no login, cookies, or paid proxy required.

**Why do some classes lack a `rating`?**  Newly-listed classes haven't accumulated reviews yet. Use `minRating` to filter these out if needed.

**What's the difference between `search` and `byUrls`?**  `search` returns catalog-level fields (price, rating, schedule) across many classes at once. `byUrls` fetches each class's own detail page for richer content — full syllabus, learning goals, prerequisites, and teacher bio — at the cost of one request per class.

**How is `priceDollars` calculated?**  Outschool prices classes in cents; `priceDollars` is `priceCents / 100`.

**What does `classType` filter?**  Outschool's own top-level browse tabs: `Course` = Academic Curriculum (structured, sequential courses), `Tutoring` = 1-on-1 or small-group tutoring, `Enrichment or Club` = Electives & Enrichment (hobby classes, ongoing clubs/groups). Leave empty to search across all types.

**What counts as a "club"?**  Outschool's open-ended, ongoing group activities (not fixed-length classes). Set `excludeClubs: true` to only get structured, scheduled classes.

**How fresh is the data?**  Real-time — every run queries Outschool's live class-search index.

**How does `sortBy` (price/rating/newest) work?**  The actor scans a deeper pool of results (beyond just `maxItems`) before sorting and truncating, so the top results by price/rating/recency are accurate over a representative slice of the catalog rather than only the first page of relevance-ranked matches.

### Limitations

Outschool's `robots.txt` also allow-lists three GraphQL operations this actor does not currently call (`ListingsByActivityUids`, `ListByFirstListedAt`, `CategoryPagesByPage`) — their exact query documents are not derivable without a live browser session (the GraphQL endpoint uses byte-exact query allow-listing and returns opaque errors for unregistered queries). The `search` mode with `sortBy: "newest"` and a deep scan, plus `subjects`/`formats` filters, closely approximates what those endpoints would offer.

# Actor input Schema

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

What to fetch.

## `searchQuery` (type: `string`):

Free-text query matched against class titles/descriptions. Leave empty to browse by subject/format only.

## `classType` (type: `string`):

Filter to one of Outschool's top-level browse categories (mode=search). Leave as "All types" to search across all of them.

## `subjects` (type: `array`):

Filter to one or more top-level subjects. Leave empty for all subjects.

## `formats` (type: `array`):

Filter to live-online and/or self-paced classes. Leave empty for both.

## `onlyAvailable` (type: `boolean`):

Skip classes that are sold out or not currently enrollable.

## `minAge` (type: `integer`):

Drop classes whose age range doesn't overlap this minimum (years).

## `maxAge` (type: `integer`):

Drop classes whose age range doesn't overlap this maximum (years).

## `minPriceDollars` (type: `number`):

Drop classes priced below this (per class/week).

## `maxPriceDollars` (type: `number`):

Drop classes priced above this (per class/week).

## `minRating` (type: `number`):

Drop classes rated below this value (0-5).

## `excludeClubs` (type: `boolean`):

Skip open-ended clubs/groups and only include structured classes.

## `sortBy` (type: `string`):

Result ordering.

## `classUrls` (type: `array`):

Full Outschool class URLs to fetch, e.g. `https://outschool.com/classes/all-about-python-coding-level-1-Y3R381hD`.

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

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "coding",
  "classType": "",
  "subjects": [],
  "formats": [],
  "onlyAvailable": true,
  "excludeClubs": false,
  "sortBy": "relevance",
  "classUrls": [
    "https://outschool.com/classes/all-about-python-coding-level-1-Y3R381hD"
  ],
  "maxItems": 30
}
```

# Actor output Schema

## `classes` (type: `string`):

Dataset containing all scraped Outschool classes.

# 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 = {
    "mode": "search",
    "searchQuery": "coding",
    "classType": "",
    "onlyAvailable": true,
    "excludeClubs": false,
    "sortBy": "relevance",
    "classUrls": [
        "https://outschool.com/classes/all-about-python-coding-level-1-Y3R381hD"
    ],
    "maxItems": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/outschool-class-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 = {
    "mode": "search",
    "searchQuery": "coding",
    "classType": "",
    "onlyAvailable": True,
    "excludeClubs": False,
    "sortBy": "relevance",
    "classUrls": ["https://outschool.com/classes/all-about-python-coding-level-1-Y3R381hD"],
    "maxItems": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/outschool-class-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 '{
  "mode": "search",
  "searchQuery": "coding",
  "classType": "",
  "onlyAvailable": true,
  "excludeClubs": false,
  "sortBy": "relevance",
  "classUrls": [
    "https://outschool.com/classes/all-about-python-coding-level-1-Y3R381hD"
  ],
  "maxItems": 30
}' |
apify call crawlerbros/outschool-class-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawlerbros/outschool-class-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/RtWwowmadPAfmdWIY/builds/uWU8KdPCM1N32tG8D/openapi.json
