Schema markup for local businesses, also called structured data, is code you add to a page that labels your business information for machines. Four types cover most of the value for a local service business: LocalBusiness, Service, FAQPage, and Review. You can add it with an SEO plugin, through Google Tag Manager, or by hand, then confirm it works with the Schema Markup Validator and Google’s Rich Results Test.
What is structured data?
Structured data is information arranged like code to make it easier for machines to read. For reference, your address on a contact page is unstructured: a person reads “812 Millbrook Road” and knows it’s a street. Structured data wraps that same address in labels: this is the street, this is the city, this is the postal code. Schema markup is the shared vocabulary for those labels, maintained at schema.org, and JSON-LD is the format most sites write it in. Search engines and AI systems read the labels instead of interpreting the text.
Which schema types matter for a service business?
Four types do most of the work for a local service business. Schema.org lists more than 800, so it helps to know which ones to ignore.
| Type | What it tells a machine | Where it belongs | What you get |
| LocalBusiness, or a subtype like Plumber, Electrician, Dentist, or RoofingContractor | Who you are: name, address, phone, hours, service area, category | Homepage, contact page, each location page | The clearest signal that your site and your Google Business Profile describe the same business |
| Service | Each thing you do, as its own item with a name and a service area | Each service page | Lets a machine match “drain cleaning in Kirkwood” to that page instead of your homepage |
| FAQPage | The questions on the page and their answers | Service pages with a real FAQ section | Clean question-and-answer pairs for AI systems to pull from. Google no longer shows FAQ dropdowns in results (see the note on FAQPage) |
| Review and AggregateRating | Ratings for a specific service or product | Pages about the thing being reviewed | Star ratings in Google results, with one limit: Google won’t show stars for reviews of your own business posted on your own site |
Pick the most specific subtype that’s true. Plumber beats LocalBusiness, and HVACBusiness beats HomeAndConstructionBusiness. If no subtype fits, LocalBusiness itself is fine.
A note on FAQPage. In August 2023, Google limited FAQ rich results to government and health sites. In May 2026, it removed them for everyone, and the Rich Results Test stopped checking for them in June. The markup still validates, and it still puts your questions and answers in a shape AI systems read easily, which is what FAQ sections that get quoted by AI depend on. Leave it in place. Just don’t expect Google to show anything for it.
What does schema markup look like?
Here’s a complete LocalBusiness block for a fictional plumbing company. It’s easier to read if you think of it as a form filled out in code. Each line has a label on the left, a colon, and your answer on the right in quotes. When a group of lines is indented under a label, those lines belong to it, the way street, city, and zip belong to address. Short groups sometimes sit on a single line instead. That’s the same thing, packed tighter. The labels with a capital letter in the middle, like openingHoursSpecification, are schema.org’s official names. Don’t rename them. Copy them exactly so every machine reads them the same way.
The block goes in your page’s HTML, the code behind the page, wrapped in a tag that tells the browser not to display it: <script type=”application/ld+json”>.
{
“@context”: “https://schema.org”,
“@type”: “Plumber”,
“name”: “Halvorsen Plumbing & Drain”,
“url”: “https://www.halvorsenplumbing.example/”,
“telephone”: “+1-314-555-0142”,
“address”: {
“@type”: “PostalAddress”,
“streetAddress”: “812 Millbrook Road”,
“addressLocality”: “St. Louis”,
“addressRegion”: “MO”,
“postalCode”: “63110”,
“addressCountry”: “US”
},
“geo”: { “@type”: “GeoCoordinates”, “latitude”: 38.6270, “longitude”: -90.2650 },
“areaServed”: [
{ “@type”: “City”, “name”: “St. Louis” },
{ “@type”: “City”, “name”: “Kirkwood” }
],
“openingHoursSpecification”: {
“@type”: “OpeningHoursSpecification”,
“dayOfWeek”: [“Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”],
“opens”: “07:00”,
“closes”: “18:00”
},
“sameAs”: [“https://www.facebook.com/halvorsenplumbing”, “https://www.instagram.com/halvorsenplumbing”],
“makesOffer”: {
“@type”: “Offer”,
“itemOffered”: { “@type”: “Service”, “name”: “Drain cleaning” }
}
}
Reading it top to bottom:
- @context and @type say “the vocabulary is schema.org, and this business is a Plumber.” Swap in your own subtype.
- name, url, and telephone are what they sound like. The .example web address and the 555 phone number are placeholders, the same as “Jane Doe” on a sample form.
- address splits your street, city, state, zip, and country into separate answers, so a machine never has to guess where one ends and the next begins.
- geo is the map pin. Right-click your building in Google Maps and the two numbers appear at the top of the menu.
- areaServed lists the towns you cover, one entry each.
- openingHoursSpecification gives your hours in 24-hour time. If your Saturday hours differ, add a second entry alongside this one.
- sameAs lists your social profiles so machines know those profiles belong to the same business.
- makesOffer is your service list. Each service comes wrapped in an Offer, and inside it itemOffered names the Service. To list more than one, wrap the blocks in square brackets and separate them with commas, the way areaServed does.
Every answer in the block matches something a visitor can see on the page. Keep the labels, swap in your details, and you have a working start.
Three ways to add schema to your site
Use an SEO plugin. On WordPress, Yoast, Rank Math, and similar plugins generate LocalBusiness and Organization markup from a settings form. Fill in your details once and the plugin writes the code on every page. It takes about 20 minutes and you never touch code. It does a poor job with per-page Service markup and anything custom.
Use Google Tag Manager. Tag Manager can drop a JSON-LD block into a page without touching the site’s files. It’s the route when you can’t edit the template, or when marketing manages the code without a developer. One catch. Markup added this way loads through JavaScript. Google reads it, but not every AI crawler does, so treat it as a stopgap.
Hard-code it. Paste the JSON-LD into the page’s HTML, in the theme template or on individual pages. It loads with the page, every crawler sees it, and you control every field. It needs someone comfortable editing the site. This is how Posted Social builds websites: the schema goes in during the build, matched to the content on each page, so nothing gets bolted on later.
How do you check that it worked?
Two free tools, in this order, then one report.
Run the page through the Schema Markup Validator first. It checks your code against the full schema.org vocabulary and lists every property it found. Fix whatever it flags.
Then run it through Google’s Rich Results Test. This one checks only the types Google turns into visual results and tells you whether the page qualifies. A green result means the page is eligible. Google still decides what it shows.
Once the page is live, give it a few weeks and open Google Search Console. The Enhancements reports show structured data errors for the whole site, so you catch problems on pages you forgot about.
Three mistakes that undo the work
1. Marking up content that isn’t on the page. Schema describes what’s already on the page. It can’t add anything to it. If the code says you offer emergency service and the page doesn’t, Google’s guidelines call that a violation, and it can cost you rich results. And AI systems end up with two versions of your business to sort out. Every field should point to something a visitor can read.
2. Picking the wrong type. A roofing company marked up as Organization tells machines less than one marked up as RoofingContractor. Generic types aren’t wrong. They’re quieter. Get as specific as the truth allows.
3. NAP mismatch. NAP is your name, address, and phone number. If your schema says “Halvorsen Plumbing & Drain,” your Google Business Profile says “Halvorsen Plumbing,” and a directory lists an old phone number, machines can’t be sure those are one business. Copy your NAP from your Google Business Profile into the schema, character for character, and use that same version everywhere else.
Start with one page
Add LocalBusiness markup to your homepage this week. Match every field to the page and to your Google Business Profile. Validate it. Then add Service markup to your most important service page. That alone moves you toward showing up in AI search and it takes an afternoon. If you’d rather hand it off, Posted Social’s SEO service handles schema as part of the technical work, and you can contact Posted Social to talk through your site.