# GreatSchools Scraper \[$1/1K💰] | School Ratings | K-12 Data (`ahmed_jasarevic/greatschools-scraper`) Actor

Extract US K-12 school data from GreatSchools: ratings, parent reviews, enrollment, grade levels, test scores and school URLs by city or state. Export JSON, CSV or Excel.

- **URL**: https://apify.com/ahmed_jasarevic/greatschools-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 school records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## GreatSchools Scraper – School Ratings, Test Scores & Parent Reviews

Extract **US K-12 school data from GreatSchools.org**: GreatSchools rating (1–10), parent rating, review count, enrollment, grade levels, school type, city and state — plus optional parent reviews and detailed test scores. $1 per 1,000 schools and $0.20 per 1,000 reviews. Runs on plain HTTP with no browser.

### What Can You Do With GreatSchools Data?

- **School ratings research** – compare GreatSchools ratings across a city, district or state in one table
- **Real estate and relocation analysis** – attach school quality data to neighborhood or listing research
- **Edtech and tutoring lead research** – build a school list by city, grade level and type
- **Parent-sentiment analysis** – pull parent reviews and ratings for a text or sentiment study
- **District benchmarking** – compare enrollment, student-teacher ratio and test-score performance between areas
- **Market maps and dashboards** – schedule monthly runs and track how ratings and review counts change

### How It Works

![How the GreatSchools Scraper works: from a city page to structured school records.](https://api.apify.com/v2/key-value-stores/oeuA0kLOyhbRM4fzt/records/how-it-works-greatschools-scraper.webp)

GreatSchools city browse pages ship their school list as embedded JSON inside the HTML — the same payload the site's own React app renders. The actor requests the city page over plain HTTP, extracts that JSON and maps each school into a flat record, so 25 schools per page arrive without a browser or a rendering step.

Pagination follows the site's own `?page=` parameter up to `maxPagesPerCity`. With `includeReviews` on (the default), each school's profile page is fetched and its reviews parsed into a separate reviews dataset; with `includeTestScores` on, the profile page's test-score section is parsed as well. Both options add requests, which is why they are billed as separate events.

### Extract School Data Without The GreatSchools API

GreatSchools does not offer a public, self-serve API for school records. Its data appears on the website, in third-party real-estate products and in paid data licences. If you need a city's schools as rows — names, ratings, enrollment, grade levels — the website is the only free source.

This actor reads the same embedded JSON the site renders, so the numbers match what a visitor sees, and returns them as JSON, CSV or Excel instead of HTML pages.

### School Ratings And Enrollment By City And State

Give the actor a `state` (two-letter code) and a `city` in URL form (`san-francisco`, `new-york`, `austin`) and it crawls that city's browse pages. Give only a state and it starts from the state's main page. Give `startUrls` to target a specific GreatSchools city or district URL instead — for example `https://www.greatschools.org/best-schools/california/san-francisco/`.

Each record carries `greatSchoolsRating` on the site's 1–10 scale, `parentRating` on a 1–5 scale, `numReviews`, `enrollment`, `gradeLevels`, `schoolType`, `city`, `state` and the canonical `schoolUrl`. Private schools appear where the source lists them; the rating is blank when GreatSchools has not published one.

### Parent Reviews And Test Scores As Separate Datasets

Reviews are on by default. Turning `includeReviews` off makes the run much faster and cheaper (no per-school profile request) but leaves `numReviews` as the only review signal. When reviews are collected they land in their own dataset, one row per review, so you can analyse text without duplicating school rows.

`includeTestScores` is off by default because it targets a heavier profile page. Turn it on when you need subject-level proficiency numbers rather than the summary rating.

### Input – Configure A School Extract

| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
| `state` | string | No | `""` | Two-letter US state code (`CA`, `NY`, `TX`); empty means crawl from `startUrls` |
| `city` | string | No | `""` | URL-friendly city name (`san-francisco`); empty with a state crawls the state page |
| `startUrls` | array | No | — | Custom GreatSchools city/district URLs; overrides `state` and `city` |
| `maxSchools` | integer | No | `0` | Max schools to save; `0` = no limit. Free users capped at 10 |
| `maxPagesPerCity` | integer | No | `0` | Max pagination pages per city (25 schools per page); `0` = all |
| `includeReviews` | boolean | No | `true` | Fetch each school's profile page and parse reviews |
| `includeTestScores` | boolean | No | `false` | Fetch detailed test-score data from profile pages |
| `proxy` | object | No | — | Proxy configuration for the crawler |
| `maxRequestsPerCrawl` | integer | No | `5000` | Hard request cap |

### Output – School Dataset Fields

| Field | Type | Description |
|---|---|---|
| `name` | string | School name |
| `schoolType` | string | Public, charter, private, magnet, etc. |
| `gradeLevels` | string | Grade span, e.g. `9-12` or `K-5` |
| `city` | string | City |
| `state` | string | Two-letter state code |
| `greatSchoolsRating` | number | GreatSchools summary rating, 1–10 |
| `enrollment` | number | Student count |
| `parentRating` | number | Average parent rating, 1–5 |
| `numReviews` | number | Number of parent reviews on the profile |
| `schoolUrl` | string | Canonical GreatSchools profile URL |

Reviews dataset (when `includeReviews` is on) holds one row per review with the review text, rating and school reference. Test-score data is added to the school record when `includeTestScores` is on.

### Example Input – Every School In San Francisco

```json
{
  "state": "CA",
  "city": "san-francisco",
  "maxSchools": 300,
  "includeReviews": true,
  "includeTestScores": false
}
```

### Example Output – One School Record

```json
{
  "name": "Lincoln High School",
  "schoolType": "Public",
  "gradeLevels": "9-12",
  "city": "San Francisco",
  "state": "CA",
  "greatSchoolsRating": 9,
  "parentRating": 4.5,
  "numReviews": 128,
  "enrollment": 2150,
  "schoolUrl": "https://www.greatschools.org/california/san-francisco/1234-Lincoln-High-School/"
}
```

### Export School Data To JSON, CSV Or Excel And Schedule Runs

Schools change slowly: enrollment once a year, ratings once a year, reviews continuously. A **monthly schedule** with `includeReviews` on is the right cadence for review tracking; a **yearly run** with `includeTestScores` on is enough for academic data.

At $0.001 per school and $0.0002 per review, a 300-school city with 100 reviews each costs about $0.30 for schools plus $6 for reviews. Turn reviews off for pure rating pulls.

### Related Actors

- [GreatSchools Scraper by ParseForge](https://apify.com/parseforge/greatschools-scraper) – alternative GreatSchools actor with a per-result pricing model
- [Google Maps Scraper](https://apify.com/apify/google-maps-scraper) – geocode school addresses and collect nearby business context
- [Website Content Crawler](https://apify.com/apify/website-content-crawler) – pull district websites, school handbooks and policy pages into clean text
- [Google Search Scraper](https://apify.com/apify/google-search-scraper) – find school news, boundary changes and district announcements

### FAQ

#### Why use this actor instead of the GreatSchools website?

Because the website has no export. This actor returns a city's schools as a table in seconds, follows pagination for you, and can collect every parent review into a separate dataset.

#### Is there a GreatSchools API?

There is no public self-serve API for school ratings; GreatSchools licenses data to partners. This actor is the practical alternative: it reads the same embedded JSON the site renders on city pages and returns it as structured rows.

#### Why is `includeReviews` on by default?

Because review count and parent rating are the fields most people want, and the reviews dataset is the part you cannot get from the browse page alone. It costs one extra request per school — turn it off when you only need ratings, enrollment and grade levels.

#### How many schools can I get per city?

25 schools per browse page. `maxPagesPerCity` controls how many pages are followed; `maxSchools` caps how many are saved. A large city such as New York needs many pages — set `maxPagesPerCity` explicitly if you want a bounded run.

#### What are alternatives for US school data?

The federal **Common Core of Data (CCD)** and **Civil Rights Data Collection** are free, authoritative and cover every public school, but they carry no GreatSchools rating and no parent reviews. State education departments publish test scores. GreatSchools is the only source that combines a summary rating with parent sentiment.

#### Are private schools included?

Only where they appear in the source's city browse pages. Coverage of private schools is partial and their ratings are often blank.

#### Do I need a proxy?

Usually not for a single city. Large multi-city runs and review-heavy runs can hit rate limits — enable a proxy group if that happens.

### SEO Keywords

greatschools scraper, greatschools api, greatschools data, school ratings data, k-12 school data, school test scores data, public school database, school district data, school comparison data, parent reviews dataset, school enrollment data, education data api, greatschools alternative, us school data csv, school quality data, edtech data source, real estate school ratings, school catchment research, school lead list, k-12 education dataset

### For AI Agents & LLM Apps

Returns one row per US K-12 school scraped from GreatSchools city browse pages, with rating, enrollment, grade span and review counts; parent reviews and test scores are optional add-ons.

Minimal working input:

```json
{ "state": "CA", "city": "san-francisco", "maxSchools": 25 }
```

Variant — ratings only, no review requests:

```json
{ "startUrls": [{ "url": "https://www.greatschools.org/best-schools/california/san-francisco/" }], "maxSchools": 100, "includeReviews": false }
```

Output fields: `name, schoolType, gradeLevels, city, state, greatSchoolsRating, enrollment, parentRating, numReviews, schoolUrl`.

Behaviors an agent should know:

- `startUrls` **overrides** `state` and `city` when both are set.
- `includeReviews` defaults to **true** and adds one request plus one review charge per review — set it to `false` for cheap rating-only runs.
- `maxSchools: 0` (default) means no limit; free users are capped at 10 schools.
- `maxPagesPerCity: 0` follows all pagination (25 schools per page); set it to bound a large-city run.
- `greatSchoolsRating` is on a **1–10** scale, `parentRating` on a **1–5** scale — do not normalise them to each other silently.
- `numReviews` is present even when reviews are not fetched; it is the source's count, not the number of rows you received.

Billing: **$0.001 per school** saved plus **$0.0002 per review**, plus a small actor-start event.

### Legal & Compliance Disclaimer

This actor is an independent tool. It is not affiliated with, endorsed by, or sponsored by GreatSchools.org or GreatSchools Inc.

It accesses publicly available school pages and the JSON those pages embed — no login, no paywall bypass, no CAPTCHA solving. It does not return personal contact data: parent reviews are published pseudonymously by the source, and the actor stores review text and ratings, not reviewer identities.

GreatSchools ratings and profiles are the platform's content. Users are responsible for complying with GreatSchools' Terms of Service and with applicable law when they store, republish or commercialise the data. If you use review text, respect the source's content licence and do not republish reviews in full. This section is a factual disclosure, not legal advice.

# Actor input Schema

## `state` (type: `string`):

US state code (e.g., CA, NY, TX). If empty, will crawl all states from the start URLs.

## `city` (type: `string`):

City name in URL format (e.g., san-francisco, new-york, austin). If empty with state provided, will crawl the state's main page.

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

Custom start URLs to crawl (overrides state/city). Use GreatSchools city browse URLs like https://www.greatschools.org/best-schools/california/san-francisco/

## `maxSchools` (type: `integer`):

Maximum number of schools to extract (0 = no limit). Note: free users are limited to 10 schools.

## `maxPagesPerCity` (type: `integer`):

Maximum number of pagination pages to crawl per city (25 schools per page). 0 = all pages.

## `includeReviews` (type: `boolean`):

Whether to fetch detailed reviews from each school's profile page (slower, more requests).

## `includeTestScores` (type: `boolean`):

Whether to fetch detailed test score data from school profile pages (slower, more requests).

## `proxy` (type: `object`):

Select proxies to be used by your crawler.

## `maxRequestsPerCrawl` (type: `integer`):

Maximum number of requests that can be made by this crawler (hard limit).

## Actor input object example

```json
{
  "state": "CA",
  "city": "san-francisco",
  "startUrls": [],
  "maxSchools": 10,
  "maxPagesPerCity": 0,
  "includeReviews": true,
  "includeTestScores": false,
  "proxy": {
    "useApifyProxy": false
  },
  "maxRequestsPerCrawl": 5000
}
```

# Actor output Schema

## `dataset` (type: `string`):

Link to the dataset with scraped school data

# 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 = {
    "state": "CA",
    "city": "san-francisco",
    "startUrls": [],
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/greatschools-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 = {
    "state": "CA",
    "city": "san-francisco",
    "startUrls": [],
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/greatschools-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 '{
  "state": "CA",
  "city": "san-francisco",
  "startUrls": [],
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call ahmed_jasarevic/greatschools-scraper --silent --output-dataset

```

## MCP server setup

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