# Niche Scraper - School Districts, Schools & Colleges (`parseforge/niche-school-district-profiles-scraper`) Actor

Reads Niche profiles into structured rows: the overall grade, every subject grade, the statistics table with national comparisons, all published rankings, address, phone, website, star rating, review count, member schools and area income, rent and home value.

- **URL**: https://apify.com/parseforge/niche-school-district-profiles-scraper.md
- **Developed by:** [ParseForge](https://apify.com/parseforge) (community)
- **Categories:** Education, Other, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.20 / 1,000 school district profiles

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?

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

[![ParseForge](https://raw.githubusercontent.com/ParseForge/apify-assets/main/banner.jpg)](https://apify.com/parseforge?fpr=vmoqkp)

### Niche Scraper - School Districts, Schools & Colleges

**Turn Niche profiles into structured rows: the overall Niche grade, every subject grade, the full statistics table with its national comparisons, all published rankings, contact details, star rating, review count and the schools inside a district.** Covers school districts, K-12 schools, colleges, graduate schools and places. Export to CSV, JSON, Excel, or XML.

| Who uses it | What they pull from Niche |
|---|---|
| Real estate and proptech | District grades and area income, rent and home value, joined to a listing |
| Education researchers | Proficiency, graduation rate, spend per student and teacher pay at scale |
| EdTech and enrolment teams | Ranked lists of districts and schools by state, with contact details |
| Relocation services | A comparable grade and rating for every district in a metro |
| Journalists | Rankings and review sentiment across a state |

### What it does

Pick an entity type and a state, and the Actor reads Niche's own published sitemap to find the profiles, then opens each one and extracts:

- 🎓 **Grades:** the overall Niche grade plus every subject grade the profile carries, as a label-to-grade map. For a district that is Academics, Diversity, Teachers, College Prep, Clubs & Activities, Administration, Sports, Food and Resources & Facilities.
- 📊 **Statistics with national baselines:** percent proficient in reading and maths, average graduation rate, student count, free or reduced lunch share, average teacher salary, share of teachers in their first two years, and expenses per student, each paired with the national figure Niche prints beside it.
- 🏆 **Rankings:** every published list the profile appears on, split into the list name, the rank and the size of the field, deduplicated.
- 📍 **Contact and location:** website, phone, street address, city, state and ZIP.
- ⭐ **Reviews:** the star rating and review count on every row, and optionally up to ten review excerpts.
- 🏫 **Member schools:** optionally, the schools listed on a district or college profile, each with its own rating and review count.
- 🏘️ **Area:** the name of the surrounding town and its median household income, median rent and median home value.

### What you can do with Niche data

**🏡 Score a housing market by its schools.**

Pull every district in a state with its grade, proficiency and area home value, and rank the ones where school quality outruns house prices.

**📈 Benchmark a district.**

Every statistic arrives beside the national figure Niche prints next to it, so a row is already a comparison rather than a number needing context.

**🗺️ Build a state-wide table.**

Set `state` and let it walk the sitemap. Rankings arrive parsed, so "#26 of 217" is two numbers you can sort on.

### Why choose this scraper

| | What you get |
|---|---|
| **Five profile types** | School districts, K-12 schools, colleges, graduate schools and places, all through the same row shape. |
| **Grades as data, not text** | Grades come back as a `{"Academics": "A", "Teachers": "B+"}` map with the screen-reader prefix and the "minus" spelling already normalised to `A-`. |
| **Statistics with the national baseline** | `Expenses Per Student: $26,445 / student` arrives with `Expenses Per Student (national): $17,834` beside it. |
| **Self-healing against the bot wall** | Niche is behind HUMAN (PerimeterX). When a page comes back flagged the Actor takes a new exit IP and retries that same URL, rather than burning the run against a dead address. |
| **Dead links cost nothing** | Niche's sitemaps carry a 2025 timestamp and some slugs have since died. A 404 is skipped on sight and never billed. Retrying them is also what escalates HUMAN from a challenge to an IP ban, so skipping them protects the rest of the run. |
| **Public pages only** | Niche's robots.txt disallows its `/api/` prefix. This Actor does not touch it: it reads the published sitemap and the profile pages. |

### What a row looks like

```json
{
  "entityType": "school-districts",
  "name": "Milton Public Schools",
  "url": "https://www.niche.com/k12/d/milton-public-schools-ma/",
  "overallGrade": "A",
  "grades": { "Academics": "A", "Diversity": "B", "Teachers": "A", "College Prep": "A", "Sports": "B+" },
  "stats": {
    "Percent Proficient - Reading": "45%",
    "Average Graduation Rate": "93%",
    "Students": "4,503",
    "Average Teacher Salary": "$79,373",
    "Expenses Per Student": "$19,356 / student",
    "Expenses Per Student (national)": "$17,834"
  },
  "rankings": [{ "list": "Best School Districts in Massachusetts", "rank": 26, "outOf": 217 }],
  "website": "https://www.miltonps.org/",
  "phone": "(617) 696-4808",
  "streetAddress": "25 GILE RD",
  "cityStateZip": "MILTON, MA 02186",
  "state": "MA",
  "zip": "02186",
  "rating": 4.23,
  "reviewCount": 31,
  "areaMedianHouseholdIncome": 188529,
  "areaMedianHomeValue": 933200
}
```

### Configure the run

| Input | What it does |
|---|---|
| `entityType` | `school-districts`, `k12-schools`, `colleges`, `graduate-schools` or `places`. |
| `startUrls` | Specific Niche profile URLs. Skips discovery. |
| `state` | Two-letter state code. Applied to the sitemap, so it costs nothing. |
| `nameContains` | Keep only profiles whose URL contains this text. |
| `includeMemberSchools` | Attach the schools listed on the profile. |
| `includeReviews` | Attach up to ten review excerpts. |
| `proxyConfiguration` | Residential is required; see below. |
| `maxItems` | How many profiles to return. |

### Pricing

Pay-per-event: **$0.012 per profile**, dropping to $0.0072 on Gold and above, plus a run-start fee of $0.002 on the free plan and $0.0002 on any paid one. Nothing else is billed: rankings, grades, statistics, member schools and review excerpts all ride on the profile row.

| Profiles | Free plan | Gold |
|---|---|---|
| 10 | $0.12 | $0.07 |
| 100 | $1.20 | $0.72 |
| 1,000 | $12.00 | $7.20 |

New Apify accounts start with $5 in free credit.

### Free users

Free-plan runs return up to 10 profiles as a preview. [Upgrade your Apify plan](https://console.apify.com/sign-up?fpr=vmoqkp) to collect up to 1,000,000 per run.

### Run it

1. [Create a free Apify account with $5 in credit](https://console.apify.com/sign-up?fpr=vmoqkp).
2. Open the [Niche Scraper](https://apify.com/parseforge/niche-school-district-profiles-scraper?fpr=vmoqkp).
3. Pick an `entityType`, type a `state`, and click **Start**.
4. Export the results as CSV, Excel, JSON, or XML from the **Dataset** tab.

### Use with AI agents (MCP)

```bash
claude mcp add --transport http apify "https://mcp.apify.com?tools=parseforge/niche-school-district-profiles-scraper"
```

- *"Rank Massachusetts school districts by graduation rate and show me the area home values."*
- *"Which New York districts are graded A for teachers but below average on spend per student?"*
- *"Pull the Niche profiles for these five districts and compare their proficiency scores."*

```
Use the Apify Actor "parseforge/niche-school-district-profiles-scraper" to read Niche profiles. Input: { "entityType": "school-districts" | "k12-schools" | "colleges" | "graduate-schools" | "places", "state": "<two-letter code>", "nameContains": "<text>", "maxItems": <n> }. It returns overallGrade, a grades map, a stats map with national baselines, parsed rankings, address, phone, website, rating and review count. Call it with the ApifyClient and my APIFY_TOKEN.
```

### Troubleshooting

**Why do I need a residential proxy?**

Niche is behind HUMAN (PerimeterX). Measured 2026-09-07, plain HTTP with a Chrome TLS fingerprint got 403 with a `px-captcha` body on every content path over both datacenter and residential exits; a real browser on a residential exit cleared it first try. Datacenter will not work.

**Why does the log say it rotated the exit IP?**

Because a page came back with the HUMAN block page. A flagged exit stays flagged, so retrying the same URL on it only spends the clock. The Actor takes a new browser on a new proxy session and retries that same URL. Up to six rotations per run, then it stops rather than burning the whole budget.

**Why were some URLs skipped as 404?**

Niche's sitemaps carry a 2025 timestamp and a share of the slugs in them no longer resolve. Those are skipped on sight and never billed.

**Why is a statistic missing?**

Niche fills its statistics table by entity type and by what the underlying federal data covers. A college profile carries admissions and cost figures a district profile does not, and a small district may have no proficiency figure published at all. Empty means Niche did not print it.

**Why fewer profiles than `maxItems`?**

The state and name filters matched fewer live profiles than you asked for, or the run hit its time budget. The log prints the candidate count after filtering.

### FAQ

| Question | Answer |
|---|---|
| Which profile types are supported? | Five: school districts, K-12 schools, colleges, graduate schools, and places (towns, neighbourhoods and counties). |
| Do I need a Niche account? | No. Only public profile pages are read. |
| Does it use Niche's API? | No. Their robots.txt disallows `/api/`, so the Actor reads the published sitemap and the profile pages instead. |
| Can I scrape one specific district? | Yes, paste its profile URL into `startUrls`. |
| Are the grades letter grades? | Yes, normalised: `A`, `A-`, `B+` and so on, with Niche's screen-reader prefix and "minus" spelling cleaned up. |
| Do I get the full reviews? | You always get the star rating and review count. Tick `includeReviews` for up to ten review excerpts. |
| How many profiles per run? | Free plan: 10. Paid: up to 1,000,000, bounded by how many live profiles match your filters. |
| Is this an official Niche product? | No. It is unofficial and reads only public pages. |

### Related actors

- [Career Site Jobs Scraper](https://apify.com/parseforge/career-site-jobs-scraper?fpr=vmoqkp): open roles read live from company career sites.

Browse the full [ParseForge collection](https://apify.com/parseforge?fpr=vmoqkp) for more scrapers.

🆘 **Need help?** Email parseforge@protonmail.com with your run ID, your input, and what you expected.

⚠️ **Disclaimer.** This Actor is unofficial and is not affiliated with, endorsed by, or sponsored by Niche.com. It collects only publicly available school, college and place profile data. Review excerpts are written by individuals: do not use them to identify, profile, or target anyone. You are responsible for using the data in compliance with Niche's terms and applicable laws.

# Actor input Schema

## `entityType` (type: `string`):

Which Niche profile index to read. Each one has its own sitemap and its own set of grades and statistics.

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

Specific Niche profile pages, for example https://www.niche.com/k12/d/milton-public-schools-ma/. Leave empty to discover them from Niche's own sitemap.

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

Two-letter state code, for example ma or ny. Niche puts the state at the end of every profile slug, so this filter is applied to the sitemap and costs nothing.

## `nameContains` (type: `string`):

Keep only profiles whose URL contains this text, for example springfield or regional.

## `includeMemberSchools` (type: `boolean`):

Attach the schools listed on the profile, each with its own rating and review count. Districts and colleges have them; places do not.

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

Attach up to ten published review excerpts with their star ratings. The overall rating and review count are always returned regardless.

## `proxyConfiguration` (type: `object`):

Niche is behind the HUMAN (PerimeterX) challenge. A residential proxy clears it; a datacenter one does not. The Actor rotates the exit IP by itself when a page comes back flagged.

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

How many profiles to return. Free-plan runs return up to 10 as a preview.

## Actor input object example

```json
{
  "entityType": "school-districts",
  "state": "ma",
  "includeMemberSchools": false,
  "includeReviews": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  },
  "maxItems": 25
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `csv` (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 = {
    "entityType": "school-districts",
    "state": "ma",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    },
    "maxItems": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("parseforge/niche-school-district-profiles-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 = {
    "entityType": "school-districts",
    "state": "ma",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
    "maxItems": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("parseforge/niche-school-district-profiles-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 '{
  "entityType": "school-districts",
  "state": "ma",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  },
  "maxItems": 25
}' |
apify call parseforge/niche-school-district-profiles-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parseforge/niche-school-district-profiles-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/8CEjdQNTZNdeyda0I/builds/77XVExHPOkRs2bVat/openapi.json
