GreatSchools School Ratings Scraper avatar

GreatSchools School Ratings Scraper

Pricing

from $5.28 / 1,000 school profile extracteds

Go to Apify Store
GreatSchools School Ratings Scraper

GreatSchools School Ratings Scraper

Extract public GreatSchools school profiles, ratings, academic indicators, enrollment, demographics, addresses, and review summaries from school or location URLs.

Pricing

from $5.28 / 1,000 school profile extracteds

Rating

0.0

(0)

Developer

Automation Lab

Automation Lab

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

10 days ago

Last modified

Categories

Share

Export public GreatSchools school ratings and profile context as structured JSON. Give the Actor a school profile URL or a GreatSchools city/location school-list URL and receive normalized school identity, ratings, academic indicators, enrollment, demographics, address, and review-summary fields.

The Actor is designed for recurring school-market and location analysis. It uses public, logged-out pages and does not require a GreatSchools account.

What does this GreatSchools school ratings scraper collect?

For every school profile, the Actor can collect:

  • GreatSchools numeric school ID, state-qualified schoolKey, and NCES school ID
  • district name and GreatSchools district URL
  • school website (output only; never visited) and published students-per-teacher ratio
  • school name, type, and grade range
  • overall GreatSchools rating
  • component ratings such as student progress and test scores
  • published subject proficiency and state comparison values
  • enrollment and public demographic shares
  • street address, city, state, postal code, coordinates, and phone
  • aggregate community review rating and count
  • first review text exposed in public structured profile data (not guaranteed to be the latest review)
  • canonical profile URL and extraction timestamp

Fields remain null or arrays remain empty when GreatSchools does not publish that metric for a school.

Who is it for?

  • Education researchers compare published school indicators across a market.
  • Real-estate analysts add school context to location and neighborhood datasets.
  • Relocation teams prepare repeatable school comparisons for supplied locations.
  • Data teams replace manual profile copying with a scheduled JSON dataset.
  • Developers feed normalized school records into spreadsheets, warehouses, and dashboards.

Why use this Actor?

GreatSchools pages contain several structured surfaces. This Actor combines them into one stable record rather than returning raw HTML. Location pages are expanded into individual profiles, duplicate schools are removed, and maxItems is enforced on useful school records.

The implementation uses direct HTML requests, so it avoids browser overhead and does not expose an automatic paid-proxy fallback.

Getting started

  1. Open the Actor input page.
  2. Add one or more public greatschools.org school profile or location URLs.
  3. Set Maximum school profiles.
  4. Click Start.
  5. Open the School profiles dataset view.
  6. Export JSON, CSV, Excel, XML, or another supported dataset format.

Input parameters

FieldTypeRequiredDefaultPurpose
startUrlsarrayyes—GreatSchools profile URLs or city/location school-list URLs.
maxItemsintegerno25Maximum unique school profiles to save, from 1 to 10,000.

Only public HTTP(S) GreatSchools URLs without credentials or nonstandard ports are accepted and normalized to HTTPS. Initial URLs and every redirect are checked before fetching; foreign or malformed discovered links are skipped. External school websites are output-only. Fragments and trailing slashes are normalized for URL deduplication; location query parameters are preserved.

Profile URL example

{
"startUrls": [
{
"url": "https://www.greatschools.org/california/san-francisco/6435-King-Starr-Elementary-School/"
}
],
"maxItems": 1
}

Use this mode when you already know the exact schools to enrich.

Location URL example

{
"startUrls": [
{
"url": "https://www.greatschools.org/california/san-francisco/schools/"
}
],
"maxItems": 10
}

The Actor reads the first location result page, discovers school links, and fetches profiles until the limit is reached. It does not paginate or claim exhaustive location coverage. An explicit empty ItemList on a recognized school-list location page succeeds with zero profiles. Missing or unrecognized payloads fail clearly rather than silently returning an empty dataset.

Output example

{
"schoolId": 6435,
"schoolKey": "CA-6435",
"districtName": "San Francisco Unified School District",
"districtUrl": "https://www.greatschools.org/california/san-francisco/san-francisco-unified-school-district",
"website": "http://starrkingschool.org/",
"studentTeacherRatio": 14,
"ncesSchoolId": "063441005671",
"name": "King (Starr) Elementary School",
"schoolType": "public",
"grades": "K-5",
"enrollment": 333,
"greatSchoolsRating": 6,
"ratingIndicators": [
{ "name": "Student Progress Rating", "rating": 4 },
{ "name": "Test Score Rating", "rating": 8 }
],
"subjectScores": [
{ "subject": "English", "schoolPercentProficient": 60.87, "statePercentProficient": 48.81 }
],
"reviewRating": 4.36,
"reviewCount": 28,
"address": {
"street": "1215 Carolina Street",
"city": "San Francisco",
"state": "CA",
"postalCode": "94107"
},
"latitude": 37.753468,
"longitude": -122.399117,
"sourceUrl": "https://www.greatschools.org/california/san-francisco/6435-King-Starr-Elementary-School/",
"scrapedAt": "2026-09-10T12:00:00.000Z"
}

The live record can contain additional arrays documented in the dataset schema. The compatible School profiles overview remains available; School context and academics exposes district, contact, NCES and academic fields. Export the full dataset for all fields.

New context fields are nullable. studentTeacherRatio is the published number of students per teacher, not class size or students per counselor. schoolKey uses uppercase state plus numeric ID (for example CA-6435), falling back to a validated canonical profile URL when state/ID is unavailable. Numeric school IDs alone are not globally unique.

How much does it cost to extract GreatSchools school profiles?

Pricing is pay per event:

  • a $0.005 start fee per run;
  • $0.0088 per school profile on the Bronze plan, with lower unit prices on higher plans.

At Bronze pricing, 1 profile costs about $0.0138, 10 profiles about $0.093, and 100 profiles about $0.885, including one start event. Apify displays the exact applicable tier before a run. Failed or rejected pages are not charged as profile items.

Scheduling school-market analysis

Create an Apify Schedule with the same location URLs and item limit. Each run creates a fresh dataset. Export or compare snapshots in your own warehouse to identify changes in published ratings, enrollment context, or review aggregates.

The Actor does not itself calculate historical differences or send alerts. Those are downstream workflow steps.

Integrations

Dataset results can be connected to:

  • Google Sheets for location comparison tables
  • webhooks for completion-driven pipelines
  • Make or Zapier for low-code routing
  • BigQuery, Snowflake, or another data warehouse
  • Python and JavaScript analysis notebooks
  • Apify API and MCP clients

Run with the Apify API using cURL

curl -X POST \
"https://api.apify.com/v2/acts/automation-lab~greatschools-school-profiles-ratings/runs" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"startUrls":[{"url":"https://www.greatschools.org/california/san-francisco/schools/"}],"maxItems":10}'

Keep tokens in environment variables or a secrets manager.

Run with JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/greatschools-school-profiles-ratings').call({
startUrls: [{ url: 'https://www.greatschools.org/california/san-francisco/schools/' }],
maxItems: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Run with Python

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation-lab/greatschools-school-profiles-ratings").call(
run_input={
"startUrls": [{"url": "https://www.greatschools.org/california/san-francisco/schools/"}],
"maxItems": 10,
}
)
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)

Use through Apify MCP

Add this Actor to Claude Code:

claude mcp add --transport http apify \
"https://mcp.apify.com?tools=automation-lab/greatschools-school-profiles-ratings"

Claude Desktop, Cursor, and VS Code setup:

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com?tools=automation-lab/greatschools-school-profiles-ratings"
}
}
}

Example prompts:

  • “Extract up to 10 school profiles from this GreatSchools San Francisco location URL.”
  • “Get the rating, enrollment, grades, address, academic indicators, and review aggregate for this school URL.”

Follow one MCP run through to bounded results

  1. Discover the scoped tools. The Actor-specific URL above selects a stable subset and automatically adds get-actor-run, get-dataset-items, get-key-value-store-record, and abort-actor-run; it does not expose exactly one tool. Inspect scoped tools/list for actual names and argument schemas, then load only the needed Actor/run/data tools. Discovery does not authorize execution or aborts.
  2. Start once and retain identifiers. For an authorized invocation, save the returned run ID, status and storage IDs; these are metadata, not result rows. call-actor waits only up to waitSecs (0–45 seconds, default 30), so a response may still be pending. Poll get-actor-run for that same run with bounded backoff (for example 2, 4, 8 seconds, capped at 10) and a total deadline (for example 120 seconds). Set the client request timeout above the selected server wait plus transport margin, within that deadline. After a client timeout, recover/check the known run instead of restarting; if its ID is unknown, disclose uncertainty rather than blindly rerun. At the deadline, report pending with the run ID and stop polling. Report terminal failure honestly; available rows are partial, not a successful full result.
  3. Fetch bounded rows after success. Call get-dataset-items with the returned dataset ID (defaultDatasetId in the run API), explicit limit: 20, offset: 0, and only needed fields, such as schoolKey,name,sourceUrl,greatSchoolsRating,grades,enrollment,districtName,studentTeacherRatio, using the discovered argument schema. An example total consumer budget is 100 source rows or 64 KiB of serialized UTF-8 result content across all pages admitted to model context, whichever comes first. Prefer untransformed JSON and track source offsets/pagination metadata, not transformed counts: filtering or unwinding can change returned row counts. Process pages host-side before model injection and enforce the byte ceiling even for an oversized row/page by omitting or summarizing it with disclosure. If your client cannot intercept oversized responses, do not claim a hard byte guarantee or request unbounded results. Stop at exhaustion or budget and report rows returned, continuation offset and partial/truncated status. Keep full exports in Apify storage or downstream processing outside model context. These are consumer context limits, not changes to Actor collection defaults or output fields.
  4. Qualify context expectations. Tool-discovery transport bytes are not necessarily model-visible context. Host-side caching, progressive loading and prompt caching depend on the client and negotiated capabilities; none guarantees universal token savings. No numeric savings are promised without measurements naming the client/version, capabilities, discovery/cache mode, model/tokenizer, visible tool/result subset and baseline method.

Reliability and retries

Requests have a 30-second timeout, at most three attempts, up to five validated redirects per attempt, and exponential backoff with jitter for transient network failures, HTTP 429, and server errors. Stable errors, challenges and parsing failures are not retried blindly. A 404, foreign domain, challenge page, non-HTML response, or page without a recognizable school/list payload produces an explicit error instead of a fabricated record.

If a real fetch or parse fails after some profiles were saved, the run fails explicitly while retaining those useful partial records and their item charges. No failed page is fabricated into a profile.

Failed operations send sanitized diagnostic input, exceptions and Actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL query strings are removed; reports are retained for 30 days. Bounded request, attempt, status-category and saved-record counters support diagnosis without sending response bodies.

For best reliability, keep individual runs bounded and schedule recurring collections at a respectful frequency.

Limits and data freshness

  • Results reflect what the public page exposed when the Actor ran.
  • GreatSchools does not publish every metric for every school.
  • A location page can expose a bounded result set; the Actor does not claim nationwide exhaustive crawling from one URL.
  • Review output is a summary field and aggregate, not a complete review-history product.
  • The source can change its HTML or embedded data structures.
  • The Actor supports public US GreatSchools URLs and does not log into accounts.

Data handling, dependencies and support

This Actor does not use AI or send scraped content to an AI provider. It reads logged-out GreatSchools pages and uses Apify for execution, metering and per-run storage. No paid proxy, login, customer API key or external school-website request is required. Service costs are covered by the documented Actor pricing; there is no separate dependency charge.

Output includes public school contact/location data and public community review text. Do not submit private student information. Each run uses its own default dataset; this Actor creates no cross-run content cache or named shared dataset. Results and logs remain in your Apify account under its storage/retention controls; delete them there when no longer needed. The private sanitized failure reports described above are retained for 30 days.

For a problem, open an issue on this Actor's Apify Store page with a run link and a non-sensitive example. This is an independent automation-lab tool, not affiliated with or endorsed by GreatSchools. Apify's standard terms apply.

Legality and responsible use

GreatSchools data may be subject to source terms and intellectual-property rights. Use the Actor only for lawful purposes, collect only what you need, respect applicable privacy and database rules, and avoid using a single rating as the sole basis for high-impact decisions.

School ratings and community reviews are context, not a complete measure of school quality. Validate important conclusions against official education sources.

Troubleshooting

Why did the run reject my URL?

Confirm that it is a complete public URL on greatschools.org. Search-engine result URLs and third-party redirects are not accepted.

Why is a field null or an array empty?

The school may not have that metric, or GreatSchools may not expose it on the current public profile. Compare the source URL shown in the record.

Why did a location URL save fewer items than maxItems?

The source page may expose fewer unique school profiles. maxItems is a ceiling, not a promised count.

What should I do after a challenge or temporary error?

Wait before retrying. The Actor already performs bounded retries for transient responses; repeated immediate runs may make rate limiting worse.

FAQ

Does this use the discontinued GreatSchools API?

No. It converts public logged-out GreatSchools pages into API-like dataset records.

Can I pass several profile and location URLs together?

Yes. Duplicate profile URLs and state-qualified school identities are removed within a run; schools in different states sharing the same numeric ID are retained.

Does it collect every review?

No. This Actor focuses on school profiles and rating context. It includes the aggregate review rating/count and a public review summary when exposed.

Can I export CSV or Excel?

Yes. Use the dataset export controls or dataset API after the run completes.

Does it monitor changes automatically?

Use an Apify Schedule to rerun the same input. Store and compare snapshots in your downstream system.

Combine these results with other public location datasets from the automation-lab Apify profile. This Actor intentionally focuses on GreatSchools school profiles instead of mixing unrelated property or business records into one dataset.