DDS Web Solutions
Practice Operations

How a dental group publishes one page per open job, and keeps job markup off the careers index

15 min

The short answer

For a dental group of about 3 to 50 or more offices, publish one page per open job and put JobPosting on that page only, matching the text a reader can see. The careers index lists the jobs and does not carry JobPosting. hiringOrganization is the group's company name, not the office. jobLocation is the office where the person reports. The same role at several offices is one page per office, or one page with several jobLocation entries. When a job closes, set validThrough in the past, remove the page so it returns 404 or 410, or remove the markup. Use the Indexing API for those job URLs, and keep a sitemap. Keep the careers pages separate from patient-facing office pages.

This guide is for a marketing lead at a dental group that hires hygienists, assistants, front desk staff, and dentists across offices and posts the openings on its own site. It covers the page structure, the markup, and the handoff when a requisition closes. This is marketing and web guidance. It is not legal or employment advice; check pay and posting rules with your counsel. The map of the other group jobs is marketing a multi-location practice or DSO.

Nothing below is a wage, a time-to-hire, or a count of applicants. If a number appears, it is a status code or a limit on Google's own pages, or a placeholder such as the street in the sample.

One index, one page per job

Three offices and fifty offices use the same split. A larger group has more rows. The careers index is a list. Each open job has a detail page. Job posting structured data says to put the markup on the most specific page that describes a single job, and not on a page meant to present a list of jobs, such as a search results page. The technical guidelines say the structured data has to appear on the same page as the description a job seeker can read. Most properties occur once, unless the documentation says a property can repeat.

When the same role is open at more than one office, pick one of the two patterns Google's page allows. One detail page per office, each with that office in jobLocation. Or one page with several jobLocation properties in an array. Google's page says that if the job has multiple locations, you add multiple jobLocation properties in an array, and that Google chooses which location to display from the job seeker's query. Do not do both for the same requisition and then leave the copies unconnected.

If the same posting already exists under several URLs, each copy needs a canonical URL. The job posting page says to use canonical URLs on each copy. How to specify a canonical URL describes rel=canonical as a strong signal, says to put a self-referential canonical on the preferred URL as well, and says not to name one URL in a sitemap and a different URL in rel=canonical. Link to the canonical from the careers index.

Do not build a stack of city pages that repeat one posting with the city swapped, in order to rank for those cities. Spam policies describe doorway abuse as pages created to rank for specific, similar queries, including many pages aimed at particular cities that funnel people to one page. The same policies describe scaled content abuse as many pages generated mainly to manipulate rankings, with little value for a reader, however the pages are produced. A real opening at a real office is a job page. A near-copy that only changes the city name is the pattern those policies describe.It says not to build that pattern.

What the markup has to include

Google's job posting page says the required properties have to be present for a posting to be eligible for the job experience, and that recommended properties can add detail. Structured data policies say not to mark up content a reader cannot see, to keep time-sensitive information current, and to put the markup on the page it describes. The same policies say content in JobPosting has to follow the job posting content policies. The salary in the markup and the salary on the page have to be the same, or you omit the property.

datePosted

Required

The date the employer first posted the job, in ISO 8601. A calendar date is enough. A date and time is also accepted. Use the date on the requisition, not the day the template was built.

description

Required

The full job description in HTML. It has to be a complete account of the job, including responsibilities, qualifications, skills, working hours, education, and experience. It cannot be the same text as the title. Paragraphs can use p, ul, and li. A br, a p, or a newline is the minimum break.

hiringOrganization

Required

The organization offering the job. Google's page says this is the company name, not the specific location that is hiring. For a dental group, that is the group's company name, not the office on Main Street. schema.org also allows an Organization or a Person here. This guide uses the company.

jobLocation

Required when you use it

The place the employee reports to work, such as an office, not the place the job was posted from. Include addressCountry. Google's page says the more address parts you include, the more useful the posting is. A fully remote job can omit this when applicantLocationRequirements is present.

title

Required

The job title only, such as Registered Dental Hygienist. Do not put a requisition code, an address, a date, a salary, or the company name in this field. Do not swap in name. Keep the title readable, without a stack of exclamation marks or stars.

validThrough

Required when the posting expires

Google lists this with the recommended properties and says it is required for a posting that has an expiration date, in ISO 8601. If the posting never expires, or you do not know when it will, leave the property out. If the job is filled before that date, remove the posting. schema.org describes it as the date after which the item is not valid.

applicantLocationRequirements and jobLocationType

Recommended, and required for a fully remote job

Use jobLocationType with the value TELECOMMUTE only when the person may or must work remotely all of the time. The description has to say that. applicantLocationRequirements names where those applicants may be located, and at least one country is required for that case. A hygienist, assistant, or dentist who reports to an office is not this case. A central call team is this case only when that team never reports to an office.

baseSalary

Recommended

The actual base salary the employer provides, not an estimate. Google's page says only employers can provide it. unitText is one of HOUR, DAY, WEEK, MONTH, or YEAR. A range uses minValue and maxValue. The figure has to be visible on the page. Leave the property off until the group enters its own.

directApply

Recommended

True or false. schema.org says true when an application can be started from the URL on the posting. Google's page describes a short application on your page, without extra sign-in steps, or instructions that reach the company or its representative directly. Google also says you may not see an effect in Search right away. Do not set it true for a page that only teases the job.

employmentType

Recommended

One or more of these case-sensitive values: FULL_TIME, PART_TIME, CONTRACTOR, TEMPORARY, INTERN, VOLUNTEER, PER_DIEM, OTHER. Use the type the requisition actually is. More than one value can sit in an array.

identifier

Recommended

The hiring organization's own identifier for the job. For a group, that is the requisition ID, with the company name in the name field. It is not a substitute for the title, and it does not belong inside the title.

hiringOrganization is the organization or person offering the job. jobLocation is a place associated with the job, usually one. directApply is whether an application can be started from the posting's URL. Those three are the schema.org definitions. Google's page adds the company-versus-office rule, the addressCountry rule, and the direct-apply path described in the table.

schema.org JobPosting also has totalJobOpenings and workHours. Google's required and recommended lists on the job posting page do not include them. totalJobOpenings is a positive integer for how many positions that posting covers. The schema.org page says not to use it if the number of positions is unclear or not known. workHours is text for the typical hours, such as a named shift. Use either only when the visible posting already says the same thing. Organization structured data has no required properties. A logo on hiringOrganization is how a job page can point at the image the group wants associated with the company. Follow the logo notes on the job posting page if you add one.

A sample for one placeholder job

The block is a shape for one placeholder role at a placeholder group. The visible page can label the door "Example Dental Group - Midtown office." The hiringOrganization name stays "Example Dental Group." The address is 123 Example St, Example City. The region code EX is not a state. Replace it, and add the postal code that office uses. The dates are format placeholders, not a recommended length for a posting. There is no baseSalary. Put that property on a live page only when the employer has entered the actual figure, and the same figure is visible to the reader. Treat it as a starting shape, not a posting to publish as is.

{
  "@context": "https://schema.org/",
  "@type": "JobPosting",
  "title": "Registered Dental Hygienist",
  "description": "<p>Example Dental Group is hiring a Registered Dental Hygienist who reports to the Midtown office at 123 Example St, Example City.</p><p>Replace this paragraph with the full posting: responsibilities, qualifications, skills, working hours, education, and experience. The description has to be the complete job, in HTML, and it cannot be the same text as the title.</p><p>A reader applies on this page.</p>",
  "datePosted": "YYYY-MM-DD",
  "validThrough": "YYYY-MM-DDT00:00",
  "employmentType": "FULL_TIME",
  "directApply": true,
  "identifier": {
    "@type": "PropertyValue",
    "name": "Example Dental Group",
    "value": "RDH-EXAMPLE"
  },
  "hiringOrganization": {
    "@type": "Organization",
    "name": "Example Dental Group",
    "sameAs": "https://example.com",
    "logo": "https://example.com/images/logo.png"
  },
  "jobLocation": {
    "@type": "Place",
    "address": {
      "@type": "PostalAddress",
      "streetAddress": "123 Example St",
      "addressLocality": "Example City",
      "addressRegion": "EX",
      "addressCountry": "US"
    }
  }
}

directApply is true in the sample only because the placeholder says the reader applies on that page. If the live page sends people through extra sign-in steps, or never offers a way to apply, do not copy that true. A second office for the same requisition is a second jobLocation object in an array, or a second page, not a second copy of this block at a new city URL.

When the job closes

Google's job posting page says jobs that are no longer open have to be expired, and that failure to take timely action on expired jobs may result in a manual action. It gives three options. Populate validThrough and put that date in the past. Remove the page so a request returns a 404 or 410 status code. Or remove the JobPosting markup from the page. The content policies say expired postings are not allowed, and that if you prefer not to remove the page, validThrough has to be populated and in the past.

HTTP status codes say Google does not index URLs that return a 4xx status, and that URLs already indexed which return a 4xx are removed from the index. 404 (not found) and 410 (gone) are both in that 4xx group. The page says all 4xx codes except 429 are treated the same for that removal. A page that still returns a normal page, with the old markup, is not in that group.

The same job posting page says the page has to offer a way to apply. The troubleshooting entry for a missing apply option says to make sure there is a way for users to apply on the page. Content policies also exclude postings that require payment from applicants, postings with an incomplete description, and pages that load the job with obstructive text and images or excessive, distracting ads. JobPosting markup is only for a page that contains a single job. It is not for a page that lists no job.

The troubleshooting entry for expired jobs that are still live lists the usual causes: validThrough is missing or not in the past, the page is still live, the apply path leads to an expired posting, or the markup is still on the page. Fix the cause you actually have. Then use the Indexing API so Google is told the URL changed.

Getting the job URL crawled

Indexing API quickstart says the API can only be used to crawl pages with JobPosting, or with BroadcastEvent embedded in a VideoObject. Submissions go through spam detection. Attempts to abuse the API, including multiple accounts or other ways to exceed quota, may get access revoked. A careers index, an office page, and a blog post are not Indexing API URLs.

Using the Indexing API defines two notification types. URL_UPDATED tells Google there is a new URL to crawl or that content at a URL has changed. A successful call succeeds, which means Google may try to recrawl that URL soon. URL_DELETED asks Google to remove a URL. Before that call, the URL has to return 404 or 410, or the page has to carry a noindex meta tag. A successful removal call also succeeds, which means Google may remove the URL. A closed job that stays on a normal page, with validThrough moved into the past, is a content change: URL_UPDATED. URL_DELETED is for the page you removed or noindexed.

Quota is counted per URL. The using-api page says you can combine up to 100 calls in one HTTP request, and that if you combine 10 requests, they still count as 10 against quota. Do not open extra accounts to get around the limit. One URL in the body of a single update request is the ordinary case.

Google's job posting page still recommends a sitemap for coverage of the site, including when you use the Indexing API, because the Indexing API prompts a crawl sooner than a sitemap alone. The sitemap for job URLs should not include search results pages, list pages, or other dynamic pages. The URLs in it have to include the canonical page for each posting. For lastmod, that page says the value must be the last time the content at the URL changed. Build and submit a sitemap says Google uses lastmod when it is consistently and verifiably accurate, and that the value should reflect the last significant update, such as main content, structured data, or links. A copyright-date change is not that kind of update. Google's sitemap page calls a submission a hint, not a promise that every listed URL will be crawled.

Before you roll the template across offices, validate a few pages with the Rich Results Test, then use URL Inspection to see how Google renders them. The job posting page says a page has to be reachable, not blocked by robots.txt, a noindex tag, or a login, and that it may take several days after publishing for Google to find and crawl a page. Rich result reports in Search Console show structured data found on the site and whether it is valid. The help page says the reports are not a comprehensive list. They show a sample. A URL missing from the report is checked with URL Inspection, not assumed to be clean or missing.

If an applicant tracking system hosts the job page, the markup belongs on that hosted page, because the structured data has to sit on the page the seeker reads. Ask the vendor where that markup is entered and how a closed job is expired.A feed that only fills the careers index is not a substitute for markup on the detail page.

Careers pages and office pages

Office pages stay patient-facing. Address, hours, phone, and the services at that door are the job of the location page. A link to the careers index from the footer, or from the office page, is fine. The careers index does not replace the office page, and a job page does not replace it. Do not put JobPosting on an office location page. A patient looking for the door, and a candidate looking for a job, can both start from the same site. They should not land on one URL that tries to be both.

Dentist or LocalBusiness markup and JobPosting are separate. The office page keeps the location markup. The job page keeps JobPosting. How the office page is built is in location pages for a multi-office website. How doctor pages differ from office pages is in provider pages and practitioner profiles. A provider page is a person at a door. A job page is an open requisition. Do not merge them into one template that swaps the name.

Open job list checker

Check your open job list before the job pages and their markup go live.

Paste one office per line and one job per line. Company name is the group's company name, not the office name. Each open job gets its own page with its own markup, as One index, one page per job explains. The same role at several offices is one page per office, or one page that lists every office in the job location.

What the markup has to include covers the job title and the employment type values. When the job closes and Getting the job URL crawled cover taking a job down. Keep job markup off office pages (Careers pages and office pages), and see Red flags for common mistakes, such as job markup on the careers index or on a job that has closed. The sample uses made-up offices (oak-park, pine-hill, elm-street) and a made-up company, Example Dental Group.

If this browser allows it, a draft is saved on this device after you type. Nothing is sent to a server. Do not paste applicant names, phone numbers, emails, resumes, or patient data.

Optional. The hiringOrganization name: the group's company name, not the office.

Optional. The list page. JobPosting does not belong on this URL.

One office per line, up to 200. Format: office slug | office page URL. The URL is optional.

One job per line, up to 200. Format: requisition id | office slug | title | job page URL | date posted | valid through | status | employment type. Dates are YYYY-MM-DD. Valid through may also be YYYY-MM-DDTHH:MM, or blank when the posting never expires or you do not know when. Status is open or closed. Employment type is optional.

Optional. Used for the date checks. Leave blank to use this device's local date.

Summary

Example, not your offices. Today is 2026-11-11. 3 offices listed. 3 job rows. 2 open. 1 closed. 3 findings. 0 field errors.

Example

The rows below are an example, not your offices. oak-park, pine-hill, and elm-street are placeholder slugs. Example Dental Group is a placeholder company. The example uses Today 2026-11-11. What you paste replaces these tables.

Job rows

Example open job list. Not your offices. Columns are requisition, office, job page URL, status, action, notification type, and note.
Requisition Office Job page URL Status Action Notification type Note
RDH-101 oak-park https://example.com/careers/rdh-101-oak-park open Keep live. URL_UPDATED when the job page is published or its content changes. URL_UPDATED Same requisition on more than one job page URL. Pick one of the two patterns: one page per office, or one page with a jobLocation array. Copies share one canonical URL.
RDH-101 pine-hill https://example.com/careers/rdh-101-pine-hill open Keep live. URL_UPDATED when the job page is published or its content changes. URL_UPDATED Same requisition on more than one job page URL. Pick one of the two patterns: one page per office, or one page with a jobLocation array. Copies share one canonical URL.
FD-303 elm-street https://example.com/careers closed Expire today: set validThrough in the past, or remove the page so it returns 404 or 410, or remove the JobPosting markup. Then URL_UPDATED if the page stays up with validThrough in the past or the markup removed; URL_DELETED only after the URL returns 404 or 410 or carries noindex. URL_UPDATED or URL_DELETED

Findings

Example findings. Not your offices. Each row names the guide section that explains it.
Input line What was found Guide section
Line 1: RDH-101 | oak-park | Registered Dental Hygienist | https://example.com/careers/rdh-101-oak-park | 2026-11-01 | 2026-12-31 | open | FULL_TIME Note, not an error. Same requisition on more than one job page URL. Pick one of the two patterns: one page per office, or one page with a jobLocation array. Copies share one canonical URL. The red flags section names the same job on many URLs with no canonical. One index, one page per job
Line 2: RDH-101 | pine-hill | Registered Dental Hygienist | https://example.com/careers/rdh-101-pine-hill | 2026-11-01 | | open | FULL_TIME Note, not an error. Same requisition on more than one job page URL. Pick one of the two patterns: one page per office, or one page with a jobLocation array. Copies share one canonical URL. The red flags section names the same job on many URLs with no canonical. One index, one page per job
Line 3: FD-303 | elm-street | Front Desk Coordinator | https://example.com/careers | 2026-10-01 | 2026-10-31 | closed | FULL_TIME This job page URL is the careers index. JobPosting belongs on the single-job page, not the list. A list page should not include structured data for individual jobs. The Indexing API sender does not send notifications for the careers index. One index, one page per job

Who acts

Role names already on Who owns the list. Names only.

  • Open. Recruiting, Web team or agency, Indexing API sender, Search Console reader
  • Closed. Recruiting, Person who closes the requisition, Indexing API sender, Search Console reader

This CSV is a job list export for your own sheet. It is not a feed and not an Indexing API request.

Who owns the list

Recruiting owns which jobs are open. The web team owns the template. The person who closes the requisition expires the URL. Search Console and the Google Cloud project for the Indexing API stay with the group. A firm can have a seat. The group should not be locked out of either account.

Recruiting

The open-job list: role, office, requisition ID, the date posted, and the date the requisition closes. One row per open job per office.

Proof. An export the group can open without the firm.

Web team or agency

The template. One detail page per job. A careers index with no JobPosting. Markup that matches the visible title, description, office, and dates.

Proof. A job URL and the index URL, with the Rich Results Test saved for the job URL.

Person who closes the requisition

Expire that job the same day. Set validThrough in the past, remove the page so a request returns 404 or 410, or remove the JobPosting markup.

Proof. The row marked closed, plus the live status of that URL.

Indexing API sender

URL_UPDATED when a job page is published or its content changes. URL_DELETED only after the URL returns 404 or 410, or the page carries a noindex tag. No notifications for office pages, the careers index, or other non-job URLs.

Proof. The notification log for that URL, on the group's Google Cloud project.

Search Console reader

The rich result report for validity, and URL Inspection for a URL the report does not list. The report is a sample, not a full inventory.

Proof. The group owns the Search Console property. A vendor seat is not the only seat.

Write the names on the sheet the group keeps. One person can hold more than one of these seats. The seat that expires the job should not be "whoever next edits the site."

Questions for an agency

Put the same questions in the RFP. A useful answer names a URL, a file, or a person at the group. A weak answer describes "SEO for careers" without saying which page carries JobPosting. These are procurement questions. They are not legal advice and not a template. A wider scorecard, without a league table, is in how to choose a DSO dental marketing company.

1. Who owns the open-job list, and where does the export live?

A useful answer names

A named role at the group, and a file the group can open. One row per open job per office, with the requisition ID and the close date.

Ask a follow-up if you hear

A list that only the firm can see, or a careers index treated as the system of record.

2. Which URL is one job, and which URL is the index?

A useful answer names

A detail URL that has JobPosting, and an index URL that lists jobs and has none. The markup matches the title, description, office, and dates on the detail page.

Ask a follow-up if you hear

JobPosting on the index, on a search results view, or on a page that lists more than one job.

3. What string is in hiringOrganization, and which address is in jobLocation?

A useful answer names

The group's company name in hiringOrganization. The office where the person reports in jobLocation, with addressCountry, matching the address on the page.

Ask a follow-up if you hear

The office name in hiringOrganization, or a headquarters address on a job that reports to a different door.

4. When a requisition closes, which removal option do you use, and who does it that day?

A useful answer names

One of the three: validThrough in the past, the page removed so it returns 404 or 410, or the JobPosting markup removed. A named person, the same day.

Ask a follow-up if you hear

The page stays up with the old markup until someone notices, or a promise that Google will drop it on its own.

5. If the same posting is on more than one URL, what is the canonical?

A useful answer names

One canonical URL, with rel=canonical on each copy, and that same URL in the sitemap. Internal links point at the canonical.

Ask a follow-up if you hear

The same job on a URL per city, with no canonical, or a different URL in the sitemap than in rel=canonical.

6. Who owns Search Console and the Google Cloud project, and which URLs get an Indexing API call?

A useful answer names

The group owns both. Notifications go only to pages that carry JobPosting, as URL_UPDATED or URL_DELETED. A sitemap of those job URLs is still submitted.

Ask a follow-up if you hear

The firm owns the only Search Console seat, or the API is used for office pages, blog posts, or the careers index.

Red flags

These are checks on a careers template or on a proposal. They do not name or rank any firm.

  1. 1. JobPosting is on the careers index.

    Google's troubleshooting page calls this structured data on the wrong page. A list page should not include structured data for individual jobs. The markup belongs on the single-job page.

  2. 2. The office name is in hiringOrganization.

    Google's required-properties section says this field is the company name, not the specific location that is hiring. The office belongs in jobLocation and in the visible address.

  3. 3. A closed job is still marked up.

    Google's content policies do not allow expired job postings. If the page stays up, validThrough has to be in the past, or the markup has to come off. Leaving it up can draw a manual action.

  4. 4. baseSalary holds an estimate.

    Google's page says baseSalary is the actual base salary the employer provides, not an estimate, and that only employers can provide it. The number also has to be visible on the page. Omit the property until the group enters its own figure.

  5. 5. The same job sits on many URLs with no canonical.

    Google's job posting page says to put a canonical URL on each copy. The canonical guide says rel=canonical is a strong signal, and that the sitemap should not name a different URL for the same page.

  6. 6. Many city pages repeat the same job with small edits.

    Spam policies describe doorway abuse, pages built to rank for similar queries, and scaled content abuse, many pages made mainly to manipulate rankings. A real opening at a real office is a different thing from a city page that only swaps the city name.

  7. 7. The Indexing API is used for pages that are not jobs.

    The quickstart says the API can only be used to crawl pages with JobPosting, or with BroadcastEvent embedded in a VideoObject. Office pages, the careers index, and ordinary marketing URLs are outside that.

Checklist

Twelve checks before you treat the careers template as ready. Ticks stay in this browser only.

Careers and job markup checklist

12 items

What DDS Web Solutions builds

DDS Web Solutions builds practice websites. Our team has been building websites since 2014, and we have served 100+ practices. Offices are in Sacramento and San Mateo. The products are Smyly, SmileTrak, and ToothRank. The planning page is DSO and multi-location marketing. A scorecard for hiring a firm is how to choose a DSO dental marketing company.

Sources

Wording on these pages can change, so confirm the live page. This is marketing guidance, not legal advice.

Explore Our Services

Next step

Need help turning reading into results?

Our team specializes in dental and healthcare marketing. Get a quote and we will scope a plan that fits your practice.