JSON-LD JobPosting: how to find roles before aggregators index them
Many careers pages embed machine-readable data describing a role. When a valid JSON-LD JobPosting block is present, it can provide a cleaner source for monitoring than rendered HTML. It also helps explain how search products discover and display vacancies.
Many job pages include a machine-readable description alongside the visible HTML, with fields such as title, location, publication date, salary and employer. The common format is JSON-LD JobPosting, embedded in a script tag. Availability and completeness vary, so treat it as a useful source to inspect rather than a guarantee on every careers page.
Understanding the format does two useful things. It shows how a search engine can read structured details from a company's page, and it gives technical readers a cleaner monitoring route when the data is present. You still need to handle missing, invalid or JavaScript-rendered data.
What it actually is
JSON-LD ("JSON for Linked Data") is a way of embedding machine-readable data inside a web page. The JobPosting schema, defined at schema.org/JobPosting, is one of dozens of types Google uses to ingest structured information from the web.
Google documents JobPosting structured data as one route to eligibility for its job-search experience, but eligibility does not guarantee display. Many modern applicant tracking systems, including Workday, Greenhouse, Lever, Ashby, Phenom and iCIMS, expose structured job data on at least some public posting pages. Implementations still vary by platform and employer configuration.
What it looks like
If you view the source of a typical Greenhouse-hosted job posting and search for application/ld+json, you'll see something close to this:
{
"@context": "https://schema.org",
"@type": "JobPosting",
"title": "Senior Backend Engineer",
"description": "We're looking for...",
"datePosted": "2026-05-12",
"validThrough": "2026-08-12",
"employmentType": "FULL_TIME",
"hiringOrganization": {
"@type": "Organization",
"name": "Acme",
"sameAs": "https://acme.example"
},
"jobLocation": {
"@type": "Place",
"address": {
"@type": "PostalAddress",
"addressLocality": "London",
"addressCountry": "GB"
}
},
"baseSalary": {
"@type": "MonetaryAmount",
"currency": "GBP",
"value": {
"@type": "QuantitativeValue",
"minValue": 90000,
"maxValue": 130000,
"unitText": "YEAR"
}
}
}
Two useful fields are datePosted, which records the publication date supplied in the structured data, and baseSalary, when the employer includes it. Either field can be missing, stale or formatted badly, so check the visible advert before relying on it.
Why this matters for job search
Three practical reasons.
1. It gives you the employer-supplied posted date
The datePosted field tells you what the employer's page declares, which is often more useful than a platform-relative label such as "posted 3 days ago". It is not infallible: employers can update, omit or reuse dates, and aggregators receive listings through different routes. Our source-to-aggregator comparison treats the field as evidence to check, not an unquestionable clock.
2. It explains how search engines can read a job page
Structured data gives search engines a direct description of a role when they crawl the page. Crawl timing, indexing and display are not guaranteed, while other job platforms may receive or process listings through different routes. Our analysis of aggregator delay looks at the practical effect of seeing a role later than its canonical source.
3. It gives you a clean route to monitor companies yourself
If you're building monitoring, valid JSON-LD is a useful first source because the fields are already structured. It does not remove the need for fallbacks: blocks can be missing, malformed, nested unexpectedly or loaded after the initial HTML. Look for <script type="application/ld+json">, validate what you find, and handle the page without it.
How to inspect it yourself
In any browser:
- Open a job posting page (try a Greenhouse or Lever URL).
- Right-click and choose "View page source" (or press Ctrl+U / Cmd+U).
- Search for
application/ld+json. - You'll find one or more JSON blocks. The one with
"@type": "JobPosting"is the role data.
Google's Rich Results Test can identify structured-data errors and eligibility issues. Passing the test does not guarantee that Google will index or display the role.
Why the ATS name is not enough
- Hosted applicant-tracking pages: Greenhouse, Lever, Ashby, Workday, Phenom, iCIMS and SmartRecruiters pages can expose JobPosting data, but support varies by template and employer configuration.
- JavaScript-rendered pages: structured data may appear only after the page runs, so it can be absent from the raw response.
- Custom careers sites: implementation varies by employer. The company size or brand is not a reliable shortcut.
- Any platform: inspect the actual posting you plan to monitor. A platform-level expectation is not proof that this page contains valid data.
Our complete ATS reference covers how to identify which system a company uses.
A minimal "be your own crawler" walkthrough
For technical readers, here's the rough shape of a Python script that monitors a single careers page for new JSON-LD JobPosting entries:
import json, re, requests, hashlib
from bs4 import BeautifulSoup
def fetch_postings(url):
html = requests.get(url, headers={"User-Agent": "Mozilla/5.0"}).text
soup = BeautifulSoup(html, "html.parser")
out = []
for tag in soup.find_all("script", type="application/ld+json"):
try:
data = json.loads(tag.string)
except (json.JSONDecodeError, TypeError):
continue
items = data if isinstance(data, list) else [data]
for item in items:
if item.get("@type") == "JobPosting":
out.append(item)
return out
# Run on a schedule; diff against previous run; email new entries.
A production monitor also has to handle JavaScript-rendered pages, request failures, rate limits, duplicate records and changing schemas. That is materially more work than the example above. Our guide to monitoring careers pages compares this approach with the alternatives.
What this means for your job search
If an employer publishes valid structured data, it is available on the source page before or alongside whatever copies later appear elsewhere. That does not prove when another platform received the role. It does give you a reason to verify the employer's page rather than treating an aggregator timestamp as the vacancy's original clock.
The practical implication is to avoid relying on one discovery channel. Check the employer's canonical page before applying, and use structured data if you're building your own monitoring. Our comparison of alert approaches walks through the trade-offs.
What to do with it
JSON-LD JobPosting is one useful layer in modern job discovery. When a company publishes it correctly, search engines and monitoring tools can read the same declared fields. That availability does not reveal when another platform ingested or displayed the role.
For candidates, the technical detail matters less than the source: verify the role on the employer's page and apply while a suitable vacancy is fresh. Reaching it before the applicant queue or shortlist forms gives you a real timing and visibility advantage. If you're building monitoring yourself, check for valid JSON-LD first, then fall back carefully when it is absent or incomplete.