A job posting can pass every validator, carry a perfect @type: JobPosting block, and still never show up in Google's job search results — or worse, show up for months after the role was filled. Google's own structured data documentation, last updated September 8, 2026, is specific about why: five properties get you eligible, one easy-to-skip property decides whether the listing behaves once it's live, and a separate list of policy reasons can pull it regardless of how clean the markup is.
The five properties that decide eligibility
Google's JobPosting structured data documentation lists a short required set, and it's stricter about what each one should not contain than most people expect. title means the job title alone — not the location, not a req code, not the salary bolted on to grab attention. hiringOrganization names the employer, nested as its own Organization object with at least a name, not folded into the job title as plain text.
| Property | Status | What it holds |
|---|---|---|
title | Required | Job title only |
description | Required | Full job details, HTML formatting allowed |
datePosted | Required | ISO 8601 publish date |
hiringOrganization | Required | Nested Organization object with at least a name |
jobLocation or jobLocationType | Required (one of the two) | A physical address, or TELECOMMUTE for a fully remote role |
That last row is the one people trip over. A remote-only posting doesn't need a fake office address — set jobLocationType to TELECOMMUTE instead and skip jobLocation entirely. Publishing an address for a role nobody actually works from is worse than publishing none, because it's the kind of mismatch between markup and page content that shows up later in Google's removal reasons.
Why validThrough outranks every required field in practice
Here's the part the required/recommended split doesn't communicate well: validThrough sits in the recommended column, but Google's own wording about it reads like a requirement with the label filed off.
Google's own line on this
"We don't allow expired job postings. Ideally you should remove expired job postings from your website." A listing without validThrough carries no expiration signal at all — which doesn't mean Google leaves it up forever, but it does mean you've handed over that decision instead of making it yourself.
Google gives three ways to retire a posting once it's filled. Set validThrough to a past date. Delete the page outright, so it returns a 404 or 410. Or strip the structured data while leaving the page live. All three work. Doing none of them is how a role that closed in March is still generating applications from confused candidates in September — not a hypothetical, just what "no expiration signal" looks like from the applicant's side.
Employment type and salary: recommended, rarely optional in practice
employmentType and baseSalary are both listed as recommended, not required, which undersells how much they change what a job seeker sees. employmentType accepts a fixed, case-sensitive set of values — get the casing wrong and the property is silently ignored rather than flagged.
Accepted employmentType values |
|---|
FULL_TIME |
PART_TIME |
CONTRACTOR |
TEMPORARY |
INTERN |
VOLUNTEER |
PER_DIEM |
OTHER |
PER_DIEM made the list. INTERNSHIP didn't — the value is INTERN. Schema.org's enum wasn't written with a copywriter in the room, and a value that reads perfectly reasonably in English can still fail to match anything Google's parser recognizes.
baseSalary is the property worth treating as required even though it technically isn't. Google's guidance is direct here: any figure entered has to reflect what the employer actually pays. No ranges pulled from a market-rate estimate. No "up to" numbers designed to look better than the real offer. That constraint is probably why so many postings leave the field out rather than get it wrong.
Leaving it out is still the worse call. Pay is one of the first filters a job seeker applies, and the same principle showed up already when we covered Product schema's price field: a property the spec marks optional can still be the one thing that decides whether a listing performs, not just whether it validates. A posting without a salary competes at a disadvantage against every listing next to it that has one.
The removal reasons that have nothing to do with your JSON-LD
A posting can be structurally flawless and still get pulled, because Google's policy list for job postings covers the page's actual content, not just the markup describing it. The reasons on record: incomplete job descriptions, listings for roles that don't exist or are misrepresented, no way to actually apply, page content that contradicts what the schema claims, profanity, and keyword-stuffed titles.
That last one has a concrete before-and-after in Google's own guidance.
Same role, two titles, one gets flagged
"Apply now for IT job—FRENCH speaker in Bucharest" gets flagged. "Market Specialist, French speaker" doesn't. Same role, same requirement — the difference is entirely about whether the title reads like a job title or like an ad written to win a search results page. If your listings still read like a 2009 Craigslist post, that's not a schema problem. The validator will pass it every time.
Checking a listing before it goes live
None of this shows up as a validation error. A JobPosting block missing validThrough, using INTERNSHIP instead of INTERN, or sitting on a page with a vague, three-sentence description will still parse as valid JSON-LD. Validity and eligibility are two different checks, and only one of them is about syntax.
Run the finished markup through our free Schema Validator to catch structural errors first. Then read back through the property table above for the things a syntax check can't see: the enum values, the salary honesty rule, and whether validThrough is set to anything at all.
Frequently asked questions
Is validThrough actually required for JobPosting schema?
Can I use a fake office address for a fully remote job?
What happens if I use INTERNSHIP instead of INTERN for employmentType?
Do I have to publish an exact salary in baseSalary?
Why would Google remove a job posting that passes a structured data validator?
What's the fastest way to remove an expired job posting from Google for Jobs?
Related articles
FAQ Schema in 2026: What Google's Deprecation Actually Changed
Google stopped showing FAQ rich results in May 2026, four years after quietly restricting them. Here's what changed, what to do with your existing markup, and why the AI-citation argument for FAQ schema doesn't hold up.
Structured DataProduct Schema Price: How to Add It Without Breaking Your Listings
The price fields Google actually checks, how to markup a price range across sellers, and the mismatch that quietly kills a listing.
Structured DataLocalBusiness Schema: What It Is and How to Add It to Your Site
What LocalBusiness markup does, the four fields a valid block needs, how to pick the right subtype, and the mistakes that quietly break rich results.
