Question

JobPosting Schema: Job Listing Markup for Google for Jobs

8 min read

Short answer

JobPosting markup makes a job page eligible for Google's job search experience, the listing format Google says can feature "your logo, reviews, ratings, and job details" and lets job seekers "filter by various criteria like location or job title". Three rules come before any optional property: mark up one job per page, use TELECOMMUTE only for jobs that are fully remote, and take expired jobs down promptly. Google warns that failing to act on expired jobs "may result in a manual action."

Sources

  1. 1developers.google.com
  2. 2developers.google.com
  3. 3developers.google.com
  4. 4support.google.com
  5. 5support.google.com

Ask next

Do You Need to Mark Up Your Own Pages?

Google’s job posting structured data documentation notes that you can also integrate “by using a third party job site.” If your openings already flow to a job board or applicant tracking system that integrates with Google, the markup may already exist on that platform’s pages. Mark up your own careers pages when they are the canonical place a job is published, and check that the same job isn’t marked up under several URLs; for copies, Google asks you to “use canonical URLs on each copy of the page.”

The feature is not available everywhere. Google’s region list covers parts of Asia, Europe, the Middle East and North Africa, and all of Latin America and North America, among others. Check the region section of the documentation before planning around it for a specific country.

One Job, One Detail Page

Two policies set the page structure:

  • “The JobPosting markup must only be used on pages that contain a single job posting. We don’t allow the use of JobPosting markup in any other page, including pages that do not list any job.”
  • “Put structured data on the most detailed leaf page possible. Don’t add structured data to pages intended to present a list of jobs (for example, search result pages).”

A careers page that lists ten openings gets no JobPosting markup. Each opening needs its own detail page with its own markup, and the markup must sit on the page where the job description is readable.

Required Properties

Google lists five required properties: datePosted, description, hiringOrganization, jobLocation and title. A fully remote job can drop jobLocation when it carries applicantLocationRequirements, and validThrough becomes required whenever the job has an expiration date.

Property What Google asks for
<!–INLINECODE9–> "The title of the job (not the title of the posting)." No job codes, addresses, dates, salaries or company names
<!–INLINECODE10–> "The full description of the job in HTML format", covering responsibilities, qualifications, skills, working hours, education and experience requirements; it "can't be the same as the title"
<!–INLINECODE11–> "The original date that employer posted the job"
<!–INLINECODE12–> The company's name, "not the specific location that is hiring"; use <!–INLINECODE13–> for anonymous postings
<!–INLINECODE14–> "The physical location(s) of the business where the employee will report to work", with <!–INLINECODE15–> always included

Two of those notes change how job pages are maintained. datePosted is the original posting date, so refreshing it on a job that stays open misstates the data; if the job changes, update the content and notify Google instead. And the job search feature recognizes only <p>, <ul> and <li> in the description; it “doesn’t recognize header and character-level tags, such as <h1>, <strong>, and <em>“, although they are safe on the page.

Remote, Hybrid and On-Site Jobs

This is where markup can mislead job seekers, so Google’s rule is worth quoting in full: “Jobs marked as TELECOMMUTE must be fully remote. Don’t mark up jobs that allow occasional work-from-home, jobs for which remote work is a negotiable benefit, or have other arrangements that are not 100% remote.”

Arrangement Markup
On-site only <!–INLINECODE23–> with the work address
Fully remote, restricted to certain countries or regions <!–INLINECODE24–> plus <!–INLINECODE25–>
Can be done fully remotely or fully at a site, the applicant's choice <!–INLINECODE26–> plus <!–INLINECODE27–>, with <!–INLINECODE28–> if remote work is limited to certain places
Hybrid (some days in the office) <!–INLINECODE29–> only; describe the schedule in the description

Google’s own examples of the third row are a job that “can be performed at a physical work site located in Detroit, MI, or at home in the US”, and one that “can either be done remotely from the country of Canada or executed at a physical location in Detroit, MI”. The description must also say plainly that the job is 100% remote when TELECOMMUTE is used. If a remote job has no applicantLocationRequirements, Google says it “shows the job to anyone in the country specified in jobLocation“.

A hybrid role marked as TELECOMMUTE puts the listing in front of people filtering for remote work who will then find an office requirement. Google’s misrepresentation policy lists “Providing false location data that does not match the actual location of the job” among its violation examples.

  • baseSalary is “The actual base salary for the job, as provided by the employer (not an estimate)”, and “Only employers can provide baseSalary.” Use minValue and maxValue for a range, and one of the case-sensitive unitText values HOUR, DAY, WEEK, MONTH or YEAR. Whether a posting must show a pay range is a legal question that depends on where the job and the applicants are; check it for each location.
  • employmentType takes case-sensitive values: FULL_TIME, PART_TIME, CONTRACTOR, TEMPORARY, INTERN, VOLUNTEER, PER_DIEM and OTHER. More than one can apply, for example ["FULL_TIME", "CONTRACTOR"].
  • directApply marks a short application flow on your page. Google says it is “still developing how we are using this information,” so “you may not see any appearance or effect in Google Search right away.” If applicants must click apply, complete a form and sign in more than once, Google says “you aren’t offering a direct apply experience.”
  • identifier is “The hiring organization’s unique identifier for the job.”
  • educationRequirements and experienceRequirements are beta properties. Google’s example uses EducationalOccupationalCredential with credentialCategory and OccupationalExperienceRequirements with monthsOfExperience, and repeats that you may not see an effect yet.

The logo shown with your jobs normally comes from your company’s Knowledge Graph card; Google explains how to suggest a different one, and how third-party job sites can supply a logo inside hiringOrganization. How the organization itself should be described is covered in Organization and Person schema.

A Complete Example

{
  "@context": "https://schema.org/",
  "@type": "JobPosting",
  "title": "Senior Software Engineer",
  "description": "<p>Join the platform team to design and run backend services.</p><ul><li>Build and maintain APIs in Python</li><li>Review code and mentor two junior engineers</li></ul><p>Requirements: five years of backend development experience. Schedule: three days a week in the Denver office, two days remote.</p>",
  "identifier": {
    "@type": "PropertyValue",
    "name": "Example Software Inc.",
    "value": "ENG-0042"
  },
  "datePosted": "2026-10-20",
  "validThrough": "2026-12-15T23:59:59-07:00",
  "employmentType": "FULL_TIME",
  "hiringOrganization": {
    "@type": "Organization",
    "name": "Example Software Inc.",
    "sameAs": "https://www.example.com"
  },
  "jobLocation": {
    "@type": "Place",
    "address": {
      "@type": "PostalAddress",
      "streetAddress": "200 Example Street",
      "addressLocality": "Denver",
      "addressRegion": "CO",
      "postalCode": "80202",
      "addressCountry": "US"
    }
  },
  "baseSalary": {
    "@type": "MonetaryAmount",
    "currency": "USD",
    "value": {
      "@type": "QuantitativeValue",
      "minValue": 130000,
      "maxValue": 160000,
      "unitText": "YEAR"
    }
  },
  "experienceRequirements": {
    "@type": "OccupationalExperienceRequirements",
    "monthsOfExperience": 60
  }
}

This is a hybrid role, so it has a jobLocation and no jobLocationType. The hybrid schedule is stated in the description, where the job seeker reads it. Use example.com addresses in templates and samples so a copied snippet never points at a real company.

When a Job Closes

Google gives three ways to expire a posting, any one of which works:

  1. Make sure validThrough “is populated and in the past.”
  2. “Remove the page entirely (so that requesting it returns a 404 or 410 status code).”
  3. “Remove JobPosting structured data from the page.”

Google’s content policy adds: “We don’t allow expired job postings.” If you keep closed jobs on the site, the validThrough date has to be in the past. A redirect is not one of the three listed options. If you don’t know when a job will close, leave validThrough out, and “If the job is filled before the expiration date occurs, remove the job posting.”

Expired jobs that stay live can trigger a Search Console message that Google quotes as “Structured data policy violation – JobPosting structured data on expired job”, and the fix ends with a reconsideration request.

Telling Google About New and Closed Jobs

For job posting URLs, Google recommends “using the Indexing API instead of sitemaps because the Indexing API prompts Googlebot to crawl your page sooner.” Use it to notify Google of a new or updated job URL and to request removal of a closed one. The Indexing API “can only be used to crawl pages with either JobPosting or BroadcastEvent embedded in a VideoObject”, so it is not a general fast-indexing tool for other content. Its quota page, updated October 16, 2026, sets a default of 200 publish requests per day per project, covering both URL_UPDATED and URL_DELETED, and says the API is available without payment.

Google still recommends a sitemap “for coverage of your entire site”, with accurate lastmod values; sitemap mechanics are covered in XML sitemaps. For sitemaps that list job URLs, Google adds: “Don’t include search results pages, list pages, or other dynamic pages in the sitemap.”

Catching Job Markup Problems Before Google Does

Job posting is on the Rich Results Test’s list of supported types, and Search Console has a Job postings report in its list of rich result reports. Test each template before release, then watch the report for invalid items after an ATS or template change. The checks no validator makes for you are the policy ones: a list page with markup, a hybrid job marked remote and a filled job still live, each of which breaks a rule quoted above. For the wider testing workflow, see the schema testing and validation tools guide.

Link profile