EdJoin.org Scraper at a glance
EdJoin.org Scraper is a ready-to-run Apify actor from abotapi for collecting jobs data. Its documented output includes id, url, title, job type and type id, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $1.80 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify.
- Runs on
- Apify cloud: console, API, schedules and integrations
- Data type
- Jobs, Developer Tools, Automation
- Pricing
- $1.80 per 1,000 results (Free plan), from $1.00 on paid plans
- Output
- Documented below · JSON, CSV, Excel
- Inputs
- 22 options
Scrape EdJoin.org K-12 and higher-ed jobs by keyword, location, filters or URL. Extract districts, locations, salaries, openings, deadlines, requirements and full descriptions, with optional contact and address details.
What EdJoin.org Scraper can do
- Two ways in. Search by keyword, location and filters, or paste EdJoin search and job-posting links directly. No need to build query strings by hand.
- One flat record per job. Every listing merges the search-result card and, optionally, its detail page into a single record: about 40 fields on a listing-only run, more once detail enrichment is on.
- Full detail enrichment on demand. Contact name and email, complete street address, education and experience requirements, skills, the full job summary and description, employer logo and the offsite apply link, one extra request per job.
- Filters that narrow the search at the source. Job type, category, online-application-only, posted-within-days and sort order are all applied server-side, not filtered out after the fact.
- Walks a whole search, or an entire catalogue, forward automatically. Set a hard job or page cap, or let it run until results run out.
- Built for monitoring. Incremental mode tracks a recurring search over time and classifies every job NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED, so a scheduled run bills only for what changed.
Choose what to collect
These inputs let you configure EdJoin.org Scraper - Education Jobs, Salaries & Districts. Open the actor on Apify to enter your values and review the current options.
| Input | What it controls |
|---|---|
modestring · required | search = enter keyword, location and filters. url = paste EdJoin search or job-posting URLs. |
keywordsstring | Job title, keyword or organization to search for, e.g. 'teacher', 'principal', 'speech pathologist'. Leave empty to list everything. |
locationstring | Free-text location to narrow the search, e.g. 'Los Angeles', 'San Diego', a county or a ZIP. Leave empty for statewide / all. |
jobTypeIdsarray | Restrict to specific EdJoin job types by numeric ID (see the jobTypeId field in any output record). Example: 4 = Teacher - Middle Grades, 9 = Teacher - Special Education, 23 = Teacher Assistant / Aide. Multiple IDs are OR-combined. |
categoryIdinteger | Restrict to one EdJoin category by numeric ID (see categoryId in output). 1 = Certificated, 2 = Classified, 3 = Management, 4 = Other. Leave empty for all. |
stateIdinteger | Retired: the live source no longer honors a state filter (every value returns the unfiltered total), so this value is ignored. Saved tasks keep working. |
onlineApplicationOnlyboolean | ON: only return jobs that accept an EdJoin online application. OFF / unset: include all jobs. |
Show 15 more inputs
| Input | What it controls |
|---|---|
postedWithinDaysinteger | Only jobs posted within the last N days. 0 = no date limit. |
urlsarray | EdJoin search URLs (/Home/Jobs?...) or job-posting URLs (/Home/JobPosting/, /Home/DistrictJobPosting/). Multi-URL supported. Also accepted under the name startUrls. Left untouched, url mode scrapes the 8 example URLs listed here (one distinct target each; the non-www host, legacy /Home/DistrictJobPosting/ and extra-query-string variants of a posting URL are also accepted but resolve to the same posting, so they are not listed). |
sortBystring | Order of results. Newest first is the EdJoin default. |
fetchDetailsboolean | ON: each job gets contact name + email, full street address, application deadline, length of work year, education + experience requirements, skills, job summary, full description, employer logo, offsite application link and attachment (one extra request per job). OFF: faster, listing-card fields only (still ~35 fields). |
maxListingsinteger | Primary limit: overall cap on jobs across all searches/URLs. The run stops as soon as this many jobs are collected. Set to 0 for unlimited (then Max pages becomes the ceiling). |
maxPagesinteger | 0 (default) means walk the whole catalogue for each search: pagination stops naturally once a page comes back empty or repeats jobs already collected, or sooner once Max jobs is reached. Set a number only if you want an explicit page cap below that natural stop. |
resumeFromRunIdstring | Optional. Paste a previous run ID or dataset ID to continue a large walk-all pull: jobs already saved by that run are loaded before scraping starts and skipped, so this run only appends new jobs. Leave empty for a normal fresh run. Distinct from Incremental mode below, which tracks a RECURRING search rather than replaying one run. |
incrementalModeboolean | ON: remembers this search/URL set's results between scheduled runs and classifies each job as NEW / UPDATED / UNCHANGED / REAPPEARED / EXPIRED, so a recurring run only bills for what changed. OFF (default): every run is a plain fresh pull, same as today. Each job's fields are compared with its previous scrape (every output field except scrapedAt and any you list under 'Ignore fields when detecting changes'; detail-only fields are skipped on a run where the detail page did not load). Unrelated to 'Resume from a prior run' above (that continues one interrupted run; this tracks a recurring search). |
stateKeystring | Optional label for the incremental-mode baseline. Leave empty to derive it automatically from your search/URL settings (recommended). Set your own text only if you want to deliberately share one baseline across otherwise-different search settings, or split one search into several independently-tracked campaigns. Only applies when Incremental mode is ON. |
emitUnchangedboolean | ON: also return jobs that have not changed since the last run (changeType UNCHANGED), returns and BILLS extra rows every run. OFF (default): unchanged jobs are skipped; only NEW/UPDATED/REAPPEARED/EXPIRED are returned. Only applies when Incremental mode is ON. |
emitExpiredboolean | ON: also return a row for each previously-tracked job no longer found (changeType EXPIRED), returns and BILLS extra rows every run. Only emitted after a run that scanned the full tracked search, with no cap or resume in effect. OFF (default): expired jobs are not reported. Only applies when Incremental mode is ON. |
ignoreFieldsForChangesarray | Field names that must NOT count as a change when Incremental mode compares a job with its previous scrape (for example applicationDeadline or numberOpenings). Matches the name at any depth, or an exact dotted path. Ignored fields are still returned in the output; they only stop a job being flagged UPDATED. Leave empty to compare every field except scrapedAt. Only applies when Incremental mode is ON. |
mcpConnectorsarray | Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON, the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com). |
notionParentPageUrlstring | URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors. |
maxNotifyListingsinteger | Cap on items written to each connector per run. Does not affect the dataset. |
Fields in the output
The documented dataset includes the fields below. Availability can depend on the source page and selected mode.
idIDurlURL (link)titleTitlejobTypeJob typejobTypeIdType IDcategoryNameCategorydistrictNameDistrictcityCitycountyNameCountystateNameStatelocationLocationsalaryDisplaySalaryShow 30 more fields
salaryInfoAdd'l salary infopayRangeFromPay frompayRangeToPay topayRangeUnitPay unitemploymentTypeEmploymentnumberOpeningsOpeningsonlineAppOnline appdatePostedPostedapplicationDeadlineDeadlineworkYearLengthWork yearcontactNameContactcontactEmailContact emailstreetAddressAddresspostalCodeZIPemployerUrlEmployer URL (link)employerLogoLogo (link)offsiteUrlApply URL (link)districtdistrictcountycountycontactcontactdatedatestatestatesearchQuerySearchscrapedAtScrapedchangeTypeChange typechangedFieldsChanged fieldsfirstSeenAtFirst seenlastSeenAtLast seeneducationRequirementsEducationexperienceRequirementsExperienceExample output
An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.
{
"id": 20000001,
"url": "https://www.edjoin.org/Home/JobPosting/20000001",
"title": "Elementary Teacher, 1.0 FTE, 2026-2027",
"districtName": "Example Unified School District",
"city": "Exampleton",
"countyName": "Example",
"countyFullName": "Example County, CA",
"stateName": "California",
"stateId": 24,
"zip": "90000",
"location": "Exampleton, California",
"jobType": "Teacher - K-6",
"jobTypeId": 48,
"categoryName": "Certificated",
"categoryId": 1,
"salaryInfo": "See attached certificated salary schedule",
"salaryDisplay": "$60,000 - $117,000 Annually",
"payRangeFrom": "$60,000",
"payRangeTo": "$117,000",
"payRangeUnit": "Annually",
"employmentType": "Full Time",
"numberOpenings": 2,
"onlineApp": true,
"datePosted": "2026-01-01T00:00:00.000Z",
"applicationDeadline": "2026-02-01T00:00:00.000Z",
"workYearLength": "2026-2027 School Year",
"contactName": "Jane Example",
"contactEmail": "jobs@example.org",
"streetAddress": "100 Example Blvd.",
"addressLocality": "Exampleton",
"addressRegion": "California",
"postalCode": "90000-0000",
"addressCountry": "US",
"employerName": "Example Unified School District",
"employerUrl": "https://www.edjoin.org/example",
"employerLogo": "https://example.org/logos/example-000000.png",
"educationRequirements": "Valid California Teaching Credential",
"experienceRequirements": "Online application required; incomplete applications are screened out.",
"skills": "BA/BS plus subject-matter competence",
"jobSummary": "Full job summary text appears here when detail enrichment is on.",
"description": "See attachment on original job posting",
"offsiteUrl": "https://www.example.org/apply",
"attachmentName": "Job-Description-00000000.pdf",
"searchQuery": "teacher",
"scrapedAt": "2026-01-01T00:00:00.000Z"
}Ways to use this data
- School HR and staffing teams: track new certificated and classified openings across districts to prioritize sourcing and outreach.
- Recruiting and HR-tech platforms: mirror EdJoin postings into your own job board or ATS without sending users to EdJoin directly.
- Compensation and market-rate teams: collect posted salary ranges and requirements to benchmark against your own pay bands.
- Education researchers and journalists: build a dataset of job postings, salary ranges and hiring activity across school districts over time.
- Districts and agencies monitoring their own postings: schedule a recurring pull with Incremental mode to know the moment a listing changes or is taken down.
Before you run
Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.
Questions about this actor
What data does EdJoin.org Scraper return?
The documented output for EdJoin.org Scraper includes id, url, title, job type, type id, category, district and city. Availability of each field depends on the source page and the selected mode.
How much does EdJoin.org Scraper cost?
It costs $1.80 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.
Can I get only new or changed jobs on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated, reappeared or expired jobs for the same search, and unchanged ones are not billed unless you turn on Emit unchanged.
What's the difference between Resume and Incremental mode?
Resume from a prior run continues ONE interrupted walk-all pull using a pasted run or dataset ID: a one-time continuation that skips every job that run already saved (pair it with a search URL carrying &page=N, as described above, so the walk does not stop on already-saved first pages). Incremental mode remembers a search's baseline itself between scheduled runs, so a recurring run only returns what changed, with no ID to paste. They solve different problems and can be combined to seed Incremental mode's baseline from a prior resume pull.
Why did a resumed run, or my second search URL, return far fewer jobs than expected?
A search stops as soon as it reads a page holding only jobs the run has already seen, and that includes jobs from another search URL in the same run and jobs loaded from a resumed run. So a resumed walk-all pull can stop on page 1 with zero jobs, and a second search URL that overlaps the first can stop before its own new jobs. Run overlapping search URLs as separate runs, and resume a large pull through a search URL with &page=N as described under Resume and recurring updates above. A job-posting URL pasted next to searches can also be dropped if one of those searches skipped that job because of its share of Max jobs; paste posting URLs in their own run.
Why did my run fail instead of returning an empty dataset?
If EdJoin refuses every request a run makes, the run stops with a clear message so "no jobs match this search" is never confused with "nothing could be read." Run it again in a few minutes. A search that genuinely comes back empty still succeeds and returns a note instead of a job.
