All platforms

AppliTrack Jobs API

Query jobs from AppliTrack boards through one API with ?source=applitrack — plus how AppliTrack's Output.asp endpoint really behaves.

?source=applitracksource reference

AppliTrack is Frontline Education's applicant tracking product, and it is what US K-12 school districts hire through: teachers, aides, bus drivers, custodians, coaches, cafeteria staff. Each district's board lives under applitrack.com/<district>/onlineapp, where <district> is a short path segment like wvde or jcps. It's 41,110 postings in this dataset — a number that moves hourly, so read it from /v1/meta rather than trusting this sentence.

It is also, by some distance, the cheapest source in this pool to fetch. One unauthenticated GET returns an entire district's board with the descriptions already in it. No pagination, no detail pass, no token.

Try it#

BASH
curl -G https://api.hyperjobs.io/v1/jobs \
  -H "Authorization: Bearer $HYPERJOBS_KEY" \
  --data-urlencode "source=applitrack" \
  --data-urlencode "time_frame=7d" \
  --data-urlencode "limit=2"
Illustrative — the shape, not a live response
{
  "data": [
    {
      "id": "applitrack:wvde_48210",
      "title": "Special Education Teacher",
      "company": {
        "slug": "wvde",
        "name": "West Virginia Department of Education",
        "domain": "wvde.us",
        "website": "https://wvde.us",
        "logo": "https://logo.hyperjobs.io/wvde.us",
        "industry": "Education Administration Programs",
        "employee_count": null
      },
      "location": {
        "remote": false,
        "countries": ["United States"],
        "cities": null,
        "regions": null,
        "raw": ["United States"]
      },
      "employment_type": ["FULL_TIME"],
      "work_arrangement": null,
      "department": "Elementary School Teaching",
      "team": "Nimitz High School",
      "seniority": null,
      "salary": {
        "min": null,
        "max": null,
        "currency": null,
        "unit": null,
        "annual_min": null,
        "annual_max": null,
        "summary": null
      },
      "skills": ["special education", "iep"],
      "taxonomies": ["Education"],
      "apply_url": "https://www.applitrack.com/wvde/onlineapp/jobpostings/Output.asp?AppliTrackJobId=48210&AppliTrackLayoutMode=detail&AppliTrackViewPosting=1",
      "url": "https://www.applitrack.com/wvde/onlineapp/jobpostings/Output.asp?AppliTrackJobId=48210&AppliTrackLayoutMode=detail&AppliTrackViewPosting=1",
      "source": "applitrack",
      "posted_at": "2026-07-09T00:00:00.000Z",
      "expires_at": "2026-08-15T00:00:00.000Z",
      "updated_at": "2026-07-14T06:41:12.000Z"
    }
  ],
  "total": 2,
  "limit": 2,
  "offset": 0
}

Two things in there are unusual and both come straight from the platform. expires_at is populated: districts post a hard application deadline, and most ATS expose none at all. And cities is null while countries is ["United States"] — that is not a gap in our geocoding, it's the honest answer. See below.

How AppliTrack boards actually work#

One GET, no auth, no pagination, the whole board including every description:

BASH
curl "https://www.applitrack.com/<district>/onlineapp/jobpostings/Output.asp?all=1"

<district> is the path segment from the board URL. That's the entire fetch surface. ?all=1 is the whole thing — there is no page two, and there is no detail request, because the bodies are already inline.

The best jobs-per-request source we have

Measured 2026-07: wvde returned 1,078 jobs in 9.4MB from one call; jcps returned 32 from one call. Every other platform on this site costs you either pagination, an N+1 detail pass, or both. AppliTrack costs you one request per district and nothing else.

Budget for the size, though: a big district's response is ~9MB, so a 20-second timeout is not enough. Ours allows 90.

The response is not HTML#

This is the one real wrinkle, and it stops a naive parser dead. Output.asp does not return a document. It returns a JavaScript program whose markup is embedded inside document.write('…') string literals, which means every quote in the payload arrives backslash-escaped:

document.write('<ul class=\'postingsList\' id=\'p48210_\'>…');

The board's own view.asp bootstraps this by letting the browser execute it. You don't need to. Unescape \' and \" and you have ordinary markup you can parse with ordinary tools — no JS engine, no headless browser. But feed the raw response to an HTML parser and you get a document containing one <script> and zero jobs, at HTTP 200.

Fields are label/value span pairs#

Inside each <ul class='postingsList' id='p<JOBID>_'> block, the structured fields are pairs:

HTML
<span class="label">Location:</span><br/>&nbsp;<span class="normal">Nimitz High School</span>
LabelWhat it becomes
Position TypeThe district's own category — Elementary School Teaching, Substitute, District
Date PostedThe posting date, US M/D/YYYY, no zone
Closing DateA real application deadline
LocationThe school or building, not a place
Additional InformationThe description body

Read those by matching labelnormal span pairs. The tempting shortcut is a flat text scan that grabs everything after a label until the next known label, and it bleeds badly — see below.

What bites you#

77% of postings have a description, and that is the ceiling#

This is the number to know about AppliTrack, and it is not a parse bug we haven't got round to fixing. It's the platform.

Plenty of districts don't type the posting into the form. They attach it as a PDF and leave the body reading "Please click the link to view the job description. Attachment(s): Licensed Journeyman Plumber.pdf". At aldineisd, 199 of 290 postings are that. The per-job detail page carries no body either — we checked, it's PDF-only there too. There is nothing to parse, so a null description is the correct answer rather than a missing one.

A single district will flatter you

Sampled on two small districts, AppliTrack looks like 100% descriptions — jcps is 32 of 32. Across a real 24-board rotation it is 919 jobs, 712 with a body: 77%.

If you build this and measure it on the first district you find, you will believe you have a perfect source, ship it, and discover the gap in production. Measure on a rotation, not on a board.

Recovering the rest means running a PDF text extractor over the attachments. That's a real option and not a wall, but it is a different project from scraping a board, and until someone does it, 77% is what AppliTrack is.

"Location" is a building, never a place#

The field is labelled Location: and it never contains one. Across three districts, all 76 distinct values were school and facility names — Nimitz High, Special Education Building, District-Wide, Various. 0 of 115 postings geocoded. Feeding those to a geocoder produced 3% country fill and 8,979 unresolved rows.

So the school goes in team, where it's true, and the location field gets the one geographic fact the platform actually supports: the country. AppliTrack is Frontline's US K-12 product. Of 1,486 discovered districts, none carries a non-US signal and 352 use US-exclusive terms (ISD = Independent School District, USD = Unified School District). The country is asserted. The city is not invented — the posting names no city, state or country anywhere, and the board page carries no district address either.

Districts invent their own labels#

There is no fixed label vocabulary. Districts add their own: Date Available:, SALARY/STIPEND:, Attachment(s):, STARTING DATE:. A parser that scans flat text and stops at the next label it knows about will sail straight past an unlisted one and swallow it, producing locations like:

"District Date Available: 09/01/2026"

Reading labelnormal span pairs needs no list of labels at all, which is why that's what we do. Quoting and padding vary per district too ('label' vs "label", " Closing Date: "), so the match has to tolerate both.

JobIDs are district-local#

JobID: 5 exists on more than one board. Key a posting by the bare id and districts silently overwrite each other's jobs. The key has to carry the district: wvde_48210.

Dates are bare US calendar dates#

Date Posted and Closing Date are M/D/YYYY with no zone, in district-local time. Date.parse reads them at your local midnight, which shifts them a day in either direction depending on where your server is. They need a bare-date parser, not a timestamp parser.

Or use ours#

The fetch is genuinely one line. It's everything around it that isn't: the document.write unescape, the label-pair reader that survives a district inventing SALARY/STIPEND:, the school going to team instead of poisoning the geocoder, the district-scoped key, and the bare-date handling.

You get all of that, plus dedup against the same role on LinkedIn, and expires_at fed from the district's real closing date rather than waiting for a board diff to notice the job is gone.

Where we're honest about the join

The company join is partial on AppliTrack — around 21% of postings resolve to an employer domain, well below what we manage on platforms that publish one. A district posting names no website and no domain, and "Jefferson County" is a name that belongs to a dozen places. We resolve what we can and leave the rest rather than guess a school district's identity.

And the two numbers that matter: 77% descriptions, and 100% country, 0% city. Both are the platform's ceilings, not ours, and we would rather you knew them before you query than after.

Query it with ?source=applitrack. Quickstart, then pricing.

Every source above normalises onto the same schema, with the hiring company already joined onto each posting.

Get an API key