# SchoolSpring Scraper (`crawlerbros/schoolspring-scraper`) Actor

Scrape SchoolSpring - 110K+ teaching and education jobs in the US. Search by keyword, location, category, grade level and job type, or fetch full job details (pay, contact info, requirements, coordinates) by ID or URL.

- **URL**: https://apify.com/crawlerbros/schoolspring-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Jobs, Lead generation, Automation
- **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

## SchoolSpring Scraper

Scrape **SchoolSpring** — the leading US education job board with 110K+ active teaching, administration, support and substitute jobs. Search by keyword, location, job category, grade level and job type, or fetch full job details (salary, contact person, requirements, GPS coordinates, posting deadlines) by job ID or URL. HTTP-only via the public `api.schoolspring.com` JSON API. No auth, no proxy.

### What this actor does

- **Three modes:** `search`, `byId`, `byUrl`
- **Rich filters:** keyword, location, category dropdown, grade level, job type, posted-within-days
- **Full detail records:** pay ranges, contact person, degree/experience requirements, coordinates
- **Category taxonomy:** dropdown built from SchoolSpring's own job-category system
- **Empty fields are omitted**

### Output per job (mode = `search`)

- `jobId` — SchoolSpring job ID
- `title`, `employer`, `location`
- `displayDate` — listing date (YYYY-MM-DD)
- `schoolSpringUrl`

### Output per job (mode = `byId` / `byUrl`)

- `jobId`, `title`, `employer`, `externalJobCode`
- `jobDescription`, `requirements`, `instructions` — HTML stripped to text
- `jobType` (Full-time / Part-time / Summer / ...), `shiftType`, `positions`
- `payMin`, `payMax`, `payType`, `payDisplay` — when the district advertises pay
- `degreeType`, `experienceRequired`, `certificationEligibleRequired`, `unionName`
- `contactName`, `contactTitle`, `contactEmail`, `contactPhone`
- `location`, `latitude`, `longitude`
- `jobBoards[]`, `jobBoardUrl` — the district job-board that posted the job
- `categories[]` — job category / sub-category strings (e.g. `Classroom Teacher / Elementary`)
- `postDate`, `displayDate`, `applicationDeadline`, `closeDate`
- `infoUrl` — external application page (often a TED K-12 / PowerSchool link)
- `eoeStatement`
- `schoolSpringUrl`, `recordType: "job"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byId` / `byUrl` |
| `searchQuery` | string | `math teacher` | Free-text keyword (mode=search) |
| `location` | string | – | e.g. `Ohio`, `New York`, `Chicago` (mode=search) |
| `category` | enum | – | Full 239-value category taxonomy (e.g. `Elementary`, `Math: Algebra`, `Special Education: General`) |
| `categoryId` | int | – | Numeric category ID override |
| `organizationName` | string | – | Employer organization name, e.g. `New Albany Plain Local` (resolved via SchoolSpring's org directory) |
| `gradeLevel` | enum | – | Preschool / Primary / Intermediate / Middle / Secondary / Post-secondary |
| `jobType` | enum | – | Full-time / Part-time / Summer / After school/Evening |
| `sortDateAscending` | bool | `false` | Newest first (`false`) or oldest first (`true`) |
| `jobIds` | array | – | Job IDs (mode=byId) |
| `startUrls` | array | – | Job URLs (mode=byUrl) |
| `postedWithinDays` | int | – | Only jobs posted within N days |
| `containsKeyword` | string | – | Substring filter on title/employer/location |
| `locationKeyword` | string | – | Substring filter on location text |
| `minPay` | int | – | Min advertised annual pay, USD (detail mode) |
| `maxItems` | int | `50` | Hard cap (1–2000) |

#### Example: math teacher jobs posted this week

```json
{
  "mode": "search",
  "searchQuery": "math teacher",
  "postedWithinDays": 7,
  "maxItems": 50
}
```

#### Example: all elementary jobs in Ohio

```json
{
  "mode": "search",
  "category": "43",
  "location": "Ohio",
  "maxItems": 100
}
```

#### Example: full details for specific jobs

```json
{
  "mode": "byId",
  "jobIds": ["5864716", "5865419", "5865326"]
}
```

#### Example: lookup by URL

```json
{
  "mode": "byUrl",
  "startUrls": [
    {"url": "https://www.schoolspring.com/jobdetail?jobId=5864716"}
  ]
}
```

### Use cases

- **Education staffing agencies** — monitor open teaching positions by district and category
- **Teacher job seekers** — track new postings in a target state with posted-within filters
- **District recruiting teams** — benchmark competing districts' job postings, pay ranges and deadlines
- **Market research** — quantify education job demand by subject, grade level and geography
- **Edtech sales** — build lists of districts currently hiring (employer + jobBoardUrl) for outreach

### FAQ

**What is SchoolSpring?**  A US education job board (part of PowerSchool/Unified Talent) carrying 110K+ teaching and education jobs posted by school districts nationwide.

**Is there a rate limit?**  No documented hard cap. The actor uses small polite delays between requests.

**Why does the `category` dropdown have 239 options?**  The dropdown mirrors SchoolSpring's full sub-category taxonomy, so every valid category is selectable without needing the numeric override.

**Why are some jobs missing pay data?**  Districts advertise pay voluntarily. Jobs without advertised pay simply omit the pay fields — the record is still complete.

**What is `infoUrl`?**  The district's own application page (often a TED K-12 or PowerSchool ATS link). SchoolSpring sometimes requires an account to apply directly; the `infoUrl` is the canonical application path.

**How fresh is the data?**  Live — every run queries the SchoolSpring API in real time.

**Is this affiliated with SchoolSpring?**  No. This is an independent third-party actor using SchoolSpring's public API.

# Actor input Schema

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

What to fetch.

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

Free-text keyword, e.g. `math teacher` (mode=search).

## `location` (type: `string`):

Location filter, e.g. `Ohio`, `New York`, `Chicago` (mode=search).

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

Job category dropdown. Uses SchoolSpring's own category taxonomy (mode=search).

## `categoryId` (type: `integer`):

Numeric category ID override (mode=search). Takes precedence over `category` if both given. Find IDs via the SchoolSpring category API.

## `organizationName` (type: `string`):

Search jobs posted by a specific employer organization, e.g. `New Albany Plain Local` (mode=search). Resolved against SchoolSpring's organization directory.

## `gradeLevel` (type: `string`):

Grade level filter (mode=search).

## `jobType` (type: `string`):

Employment type filter (mode=search).

## `sortDateAscending` (type: `boolean`):

When false (default), newest jobs first. When true, oldest first (mode=search).

## `jobIds` (type: `array`):

SchoolSpring job IDs, e.g. `5864716`.

## `startUrls` (type: `array`):

Job detail URLs, e.g. `https://www.schoolspring.com/jobdetail?jobId=5864716`.

## `postedWithinDays` (type: `integer`):

Only emit jobs posted within this many days.

## `containsKeyword` (type: `string`):

Only emit jobs whose title, employer or location contains this text (case-insensitive).

## `locationKeyword` (type: `string`):

Only emit jobs whose location text contains this (case-insensitive).

## `minPay` (type: `integer`):

Only emit jobs whose advertised minimum pay is at least this (detail mode).

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

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "math teacher",
  "category": "",
  "gradeLevel": "",
  "jobType": "",
  "sortDateAscending": false,
  "jobIds": [],
  "maxItems": 50
}
```

# Actor output Schema

## `jobs` (type: `string`):

Dataset containing all scraped SchoolSpring jobs.

# 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": "math teacher",
    "category": "",
    "gradeLevel": "",
    "jobType": "",
    "sortDateAscending": false,
    "jobIds": [],
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/schoolspring-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": "math teacher",
    "category": "",
    "gradeLevel": "",
    "jobType": "",
    "sortDateAscending": False,
    "jobIds": [],
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/schoolspring-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": "math teacher",
  "category": "",
  "gradeLevel": "",
  "jobType": "",
  "sortDateAscending": false,
  "jobIds": [],
  "maxItems": 50
}' |
apify call crawlerbros/schoolspring-scraper --silent --output-dataset

```

## MCP server setup

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