# WA School Enrollment - District Trends & Demographics (`j0401/wa-school-enrollment`) Actor

Washington K-12 public-school enrollment (243k records, WA OSPI Report Card, 12 school years 2014-15 to current): headcounts and demographics by school, district, county and grade. Track a district's enrollment trend year over year, or compare districts statewide.

- **URL**: https://apify.com/j0401/wa-school-enrollment.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 wa school enrollment records

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/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

## WA School Enrollment - District Trends & Demographics (`wa-school-enrollment`)

Pull **Washington K-12 public-school enrollment** - **243,225 records across 12 school years (2014-15 through 2025-26)**, from the WA Office of Superintendent of Public Instruction (OSPI) Report Card, free public open data. For every school, district, county and the state: the headcount and demographic composition of students, year by year.

This is the **enrollment side of WA's school system** - the numbers behind where families are (and aren't) moving. It answers the question *"is this school district growing or shrinking, and who is enrolling there?"*

Built for **real-estate developers and brokers sizing an area**, **education startups building a Washington district/school list**, **municipal and policy researchers**, and **market-intelligence users** who need a school district's trajectory as a demand signal.

**Looking for what those graduates do next?** [WA Graduate Outcomes](https://apify.com/j0401/wa-graduate-outcomes) (`wa-graduate-outcomes`) is the same WA K-12 school-quality family - a district or high school's **graduate results**: median earnings after high school, post-secondary completion, and remedial course rates, from the same OSPI source and with the same district/school codes. Enrollment here tells you who is (and isn't) coming; graduate outcomes tells you how their graduates do.

### The core tool: a district's enrollment trend ("migration early warning")

Give a district, get its **year-over-year K-12 enrollment for the last 12 school years** - a clean trend with `yoyChange` and `yoyPct` on every row. Watch an area fill up (or empty out):

```
input { "districtCode": "31002" }          // Everett School District
  schoolyear=2024-25  allStudents=20,592   yoyChange=+155   yoyPct=+0.76%
  schoolyear=2025-26  allStudents=20,777   yoyChange=+185   yoyPct=+0.90%
```

The COVID shock is plainly visible in the source data (e.g. WA districts drop sharply in 2020-21, then climb back) - exactly the signal a migration-early-warning tool should surface. Track it overall, or by a demographic (`subgroup=lowIncome`, `englishLearners`, `hispanic`, ...) to watch the *composition* of a district change over time.

### What each record has

| Field | Meaning |
|---|---|
| `schoolyear` | 2014-15  2025-26 (current year is added each fall) |
| `organizationLevel` | State / County / District / School |
| `districtCode` / `districtName` | WA district code + name (e.g. `31002` / Everett) |
| `schoolCode` / `schoolName` | School, where a school-level row |
| `gradeLevel` | `All Grades`, `Kindergarten`, `9th Grade`,  (`All Grades` = the official yearly total) |
| `allStudents` | Total headcount |
| `subgroup` / `subgroupStudents` / `subgroupPct` | The demographic watched and its count / share (race groups, low income, EL, special ed, homeless, foster care, migrant, military parents) |
| `yoyChange` / `yoyPct` | Trend mode only: change vs. the prior school year |
| `dataAsOf` | When OSPI last refreshed this row |

### Typical questions it answers

- **Is a district growing?** - `districtCode` (or `districtName`), no year -> the 12-year trend.
- **Which WA districts are biggest?** - `aggregate=true`, `groupBy=district` -> top districts by headcount (latest year).
- **An area's poverty trend** - `districtCode` + `subgroup=lowIncome` -> low-income count and share across years.
- **A single school's size** - `schoolName=Jefferson Elementary` + `schoolyear=2024-25`.
- **Kindergarten demand in a district** - `districtCode` + `schoolyear` + `gradeLevel=Kindergarten`.
- **District list in one county** - `county=King`, `aggregate=true`.

### Inputs (all optional)

| Input | What it does |
|---|---|
| `districtCode` | Exact district code. With **no schoolyear** this returns the 12-year **trend** (the core tool) |
| `districtName` | District name, substring (e.g. "Everett", "Seattle") |
| `county` | County substring (scopes a list / comparison) |
| `schoolName` | School name substring |
| `schoolyear` | One school year (e.g. `2024-25`); omit / `latest` = current year |
| `gradeLevel` | `Kindergarten`, `9th Grade`,  default `All Grades` |
| `subgroup` | Demographic to track: `allStudents` (default), `lowIncome`, `englishLearners`, `specialEd`, `homeless`, `fosterCare`, `migrant`, `militaryParents`, `hispanic`, `asian`, `black`, `white` |
| `aggregate` | Compare districts/counties/schools (one row each) instead of individual records |
| `groupBy` | `district` (default) / `county` / `school` |
| `maxResults` | Cap records pushed (default 200) |

**Empty input** returns a safe snapshot: the top school districts by enrollment, current school year (used by Apify's daily quality test too).

### Low cost

**From $0.001 per record** - with a per-run charge cap so a mistake can't run up a big bill.

Twelve school years of enrollment are pre-aggregated by the state into **wide rows that double-count if summed naively** (OSPI ships an "All Grades" total *alongside* the per-grade rows, so adding grades yourself counts every student twice). We read the state's authoritative totals and the complementary demographic pairs (low-income / not low-income) so a district or county trend is never inflated. You query clean annual totals and honest trends; the wide-row double-count traps and paired demographics stay on our side.

### Data source & freshness

- **Source**: [data.wa.gov - OSPI "Report Card Enrollment from 2014-15 to Current Year"](https://data.wa.gov/) (`rxjk-6ieq`, Socrata SODA API, free public, no login). Public data - the same figures OSPI's Report Card portal shows.
- **Coverage**: ~324 district-level entities and ~2,400 schools with an "All Grades" yearly total, every county. District-level "All Grades" rows: 3,892 (~324 districts x 12 school years).
- **Update cadence**: OSPI publishes each school year's enrollment in the fall; the merge table used here reaches the **current** year (2025-26 as of Sept 2026).

# Actor input Schema

## `districtCode` (type: `string`):

Exact WA school-district code, e.g. "31002" (Everett). With no schoolyear this returns the district's 12-year enrollment trend (the core tool).

## `districtName` (type: `string`):

District name, substring, case-insensitive. E.g. "Everett" or "Seattle School District". Also usable for the trend when it resolves to one district.

## `county` (type: `string`):

County name substring, e.g. "King", "Snohomish". Used to scope a detail list or aggregate.

## `schoolName` (type: `string`):

School name substring, e.g. "Jefferson Elementary". Returns that school's headcount(s).

## `schoolyear` (type: `string`):

A school year like "2024-25" or "2018-19". Omit (or "latest") for the current school year. Range 2014-15 through current.

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

Filter detail rows to one grade, e.g. "Kindergarten", "9th Grade". Default "All Grades" (one row per school / district).

## `subgroup` (type: `string`):

Which population the trend / aggregate tracks. "allStudents" = total headcount; others give that group's count and share, e.g. lowIncome to watch poverty concentration over time.

## `aggregate` (type: `boolean`):

When on (or when no filter is given), returns one comparison row per school district (top by size), latest school year, instead of individual records. Computed server-side.

## `groupBy` (type: `string`):

Which unit to roll the comparison up to: district, county, or school.

## `maxResults` (type: `integer`):

Cap the number of records pushed (0 = a reasonable cap). Trend mode has at most ~12 rows. A detail scan can reach the run's charge cap.

## Actor input object example

```json
{
  "subgroup": "allStudents",
  "aggregate": false,
  "groupBy": "district",
  "maxResults": 200
}
```

# Actor output Schema

## `recordsUrl` (type: `string`):

Washington health-care provider credentials or aggregates - as JSON

## `datasetUrl` (type: `string`):

No description

## `runUrl` (type: `string`):

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("j0401/wa-school-enrollment").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("j0401/wa-school-enrollment").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 '{}' |
apify call j0401/wa-school-enrollment --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,j0401/wa-school-enrollment"
        }
    }
}

```

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/xrVqdtlUiMeznNK8l/builds/twhUd3lVqAcBJxxz9/openapi.json
