← Back to blog

Local Schema for Service-Area Businesses: LocalBusiness vs Service vs Organization

Service-area businesses get local schema wrong all the time. LocalBusiness vs Service vs Organization explained, with paste-ready JSON-LD.

We audit a lot of plumbers, mobile vets, electricians, painters, and roving contractors. The pattern is brutal and consistent. They use LocalBusiness schema with a home address Google then renders publicly on their listing. They forget areaServed, so Google has no idea which cities they actually cover. They omit serviceType, so the AI search engines can't tell what they sell. Every one of these is a self-inflicted wound, and every one is fixable with thirty minutes and a text editor.

This post sorts out the three schema types that matter for a service-area business: LocalBusiness (you have a storefront customers walk into), Service with areaServed (you go to the customer), and Organization (your company-level identity). Paste-ready JSON-LD for each. Then how to combine them on a hybrid or multi-location business so Google sees one entity instead of three contradictory ones.

When to use which: the 30-second answer

Three questions. Answer each one, then read the matching section.

  1. Do customers walk into a physical address you list publicly? Yes - use LocalBusiness (or one of its subtypes like Plumber, Restaurant, Dentist).
  2. Do you go to the customer instead of the customer coming to you? Yes - use Service with areaServed. Hide the home address. Define the zone you cover.
  3. Do you have multiple locations, or do you want to anchor your brand identity? Yes - add Organization at the root and link the locations to it.

Most service-area businesses need pattern 2. Multi-location franchises and hybrid shops need a combination of all three. Single-storefront cafes only need pattern 1. Let's walk through each.

LocalBusiness: when you have a storefront

Use LocalBusiness when a real human customer can walk into a real public address during your stated hours. Coffee shops. Dental practices. Yoga studios. Brick-and-mortar retail. The defining trait is address plus openingHours plus the implication that the address is where the work happens.

Schema.org has subtypes for almost every vertical: Dentist, Restaurant, AutoBodyShop, BookStore, Bakery, Plumber (yes, Plumber is a LocalBusiness subtype - it works for storefront plumbers, just not for the mobile-only ones). Use the most specific subtype that fits. Google reads Dentist more confidently than the generic LocalBusiness.

Here is the paste-ready block. Replace the placeholders with your real values.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Dentist",
  "@id": "https://yourdomain.com/#localbusiness",
  "name": "Cedar Park Family Dental",
  "image": "https://yourdomain.com/storefront.jpg",
  "url": "https://yourdomain.com",
  "telephone": "+1-512-555-0177",
  "priceRange": "$$",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "1402 Whitestone Blvd",
    "addressLocality": "Cedar Park",
    "addressRegion": "TX",
    "postalCode": "78613",
    "addressCountry": "US"
  },
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": 30.5052,
    "longitude": -97.8203
  },
  "openingHoursSpecification": [
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday"],
      "opens": "08:00",
      "closes": "17:00"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Friday",
      "opens": "08:00",
      "closes": "13:00"
    }
  ],
  "sameAs": [
    "https://www.facebook.com/cedarparkdental",
    "https://www.instagram.com/cedarparkdental",
    "https://g.page/cedarparkdental"
  ]
}
</script>

Three notes on this block. The @id is a stable identifier you'll reuse later when you link other schema blocks together; keep it consistent across your site. The priceRange accepts the dollar-sign shorthand ($, $$, $$$) or a literal range like "$50-$200". The sameAs array is one of the properties most sites under-fill, and it matters more than people think. Link to your Facebook, Instagram, LinkedIn, Yelp, Google Business Profile, and any industry directory you're listed on. AI search engines lean on sameAs to confirm you're a real entity.

Service with areaServed: when you go to the customer

This is the one most plumbers, contractors, mobile groomers, locksmiths, mobile vets, and home-cleaning operations get wrong. They reach for LocalBusiness because the term sounds right, paste in their home address, and Google's listing now displays the founder's house number on the map. Worse, the listing has no areaServed, so when somebody three towns over searches "emergency plumber near me," Google has no signal that you'd actually drive there.

For a no-walk-in service business, use Service. The provider property points back to your Organization. The areaServed property defines where you'll go. The serviceType property explains what you actually do, in plain words a search engine can read. There's no address on the Service itself, and that's the whole point. You don't have a public storefront, so you don't publish one.

Two ways to express areaServed. The first is a list of city names, which is the cleaner option when your zone follows political boundaries:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Service",
  "@id": "https://yourdomain.com/#emergency-plumbing-service",
  "serviceType": "Emergency plumbing repair",
  "name": "24/7 Emergency Plumbing",
  "description": "Same-day repair for burst pipes, water heaters, sewer backups, and gas-line emergencies across the Austin metro.",
  "provider": {
    "@type": "Organization",
    "@id": "https://yourdomain.com/#organization",
    "name": "Hill Country Plumbing Co.",
    "url": "https://yourdomain.com",
    "telephone": "+1-512-555-0142",
    "logo": "https://yourdomain.com/logo.png"
  },
  "areaServed": [
    {"@type": "City", "name": "Austin", "containedInPlace": {"@type": "State", "name": "Texas"}},
    {"@type": "City", "name": "Round Rock", "containedInPlace": {"@type": "State", "name": "Texas"}},
    {"@type": "City", "name": "Cedar Park", "containedInPlace": {"@type": "State", "name": "Texas"}},
    {"@type": "City", "name": "Pflugerville", "containedInPlace": {"@type": "State", "name": "Texas"}}
  ],
  "hoursAvailable": {
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
    "opens": "00:00",
    "closes": "23:59"
  },
  "offers": {
    "@type": "Offer",
    "priceCurrency": "USD",
    "priceSpecification": {
      "@type": "PriceSpecification",
      "price": "129",
      "priceCurrency": "USD",
      "description": "Diagnostic visit, applied to repair if booked"
    }
  }
}
</script>

The second way is GeoCircle, which is more honest when your zone is "anywhere within 35 miles of our shop." A circle drawn on a map. Use this if you operate by radius rather than by named cities:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Service",
  "@id": "https://yourdomain.com/#mobile-vet-service",
  "serviceType": "In-home veterinary care",
  "name": "House-call veterinary visits",
  "description": "Wellness exams, vaccines, and end-of-life care performed in the pet's home.",
  "provider": {
    "@type": "Organization",
    "@id": "https://yourdomain.com/#organization",
    "name": "Roaming Paws Mobile Vet",
    "url": "https://yourdomain.com",
    "telephone": "+1-303-555-0188",
    "logo": "https://yourdomain.com/logo.png"
  },
  "areaServed": {
    "@type": "GeoCircle",
    "geoMidpoint": {
      "@type": "GeoCoordinates",
      "latitude": 39.7392,
      "longitude": -104.9903
    },
    "geoRadius": "35000"
  },
  "hoursAvailable": [
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
      "opens": "08:00",
      "closes": "18:00"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Saturday",
      "opens": "09:00",
      "closes": "14:00"
    }
  ]
}
</script>

geoRadius is in meters. 35000 means 35 kilometers, roughly 22 miles. Convert before you ship.

A few decisions worth flagging. Pick one form of areaServed per Service block; don't mix City objects and a GeoCircle in the same array. If you offer multiple distinct services with different prices or zones (residential plumbing vs commercial plumbing, wellness vs emergency vet), publish a separate Service block per offering. They all share one provider Organization. And hoursAvailable on a Service is when somebody can book the service, which can differ from when humans answer the phone. Be honest about both.

Organization: your company-level identity

Organization is the root entity. It's who you are at the company level. For a single-location coffee shop, you usually don't need a separate Organization block; your LocalBusiness block already does the job. For anything with more than one location, a hybrid shop with both walk-in and mobile, or a brand that wants to control how it appears in AI search results, you want a dedicated Organization block at the root.

Why: Organization carries the identity properties AI search engines actually pull on. sameAs linking out to LinkedIn, Wikipedia, Crunchbase, your industry directory listings. knowsAbout listing the topics you're an authority on (this one helps with AI Overview citations specifically). subOrganization pointing at each individual branch.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "@id": "https://yourdomain.com/#organization",
  "name": "Hill Country Plumbing Co.",
  "alternateName": "Hill Country Plumbing",
  "url": "https://yourdomain.com",
  "logo": {
    "@type": "ImageObject",
    "url": "https://yourdomain.com/logo.png",
    "width": 600,
    "height": 600
  },
  "telephone": "+1-512-555-0142",
  "email": "hello@yourdomain.com",
  "foundingDate": "2014-06-01",
  "founder": {
    "@type": "Person",
    "name": "Maria Delgado",
    "url": "https://yourdomain.com/about"
  },
  "knowsAbout": [
    "Emergency plumbing",
    "Tankless water heater installation",
    "Sewer line repair",
    "Gas line installation",
    "Slab leak detection"
  ],
  "sameAs": [
    "https://www.facebook.com/hillcountryplumbing",
    "https://www.linkedin.com/company/hill-country-plumbing",
    "https://www.yelp.com/biz/hill-country-plumbing-austin",
    "https://www.bbb.org/us/tx/austin/profile/plumber/hill-country-plumbing",
    "https://g.page/hillcountryplumbing"
  ],
  "subOrganization": [
    {"@id": "https://yourdomain.com/austin/#localbusiness"},
    {"@id": "https://yourdomain.com/round-rock/#localbusiness"}
  ]
}
</script>

knowsAbout is the property most small businesses skip, and they shouldn't. List the five to ten topics your business actually has expertise in. Be specific. "Plumbing" is too generic. "Tankless water heater installation" is what people actually search, and what AI engines actually cite. Don't claim expertise you don't have; the AI engines cross-check against your actual content.

founder with a Person block adds an Expertise/Experience signal Google explicitly looks for. If your founder has a bio page, link to it via url and consider giving the Person its own block on the about page with credentials.

Combining them on a hybrid or multi-location site

A real business often needs more than one of these blocks. Picture a plumbing company with a physical office customers occasionally visit, plus mobile service trucks, plus three branch locations. Here's how to wire them together so Google reads them as one entity.

The trick is @id linking. Every block gets a stable @id URI (we use anchor-style IDs like #organization, #localbusiness, #service on the canonical domain). When you reference an entity from another block, you reference its @id, not its full inline definition. This keeps your markup DRY and tells the search engine "yes, the provider of this Service is the same Organization defined elsewhere on this domain."

Layout for a multi-location business:

A trimmed example showing the wiring (omitting properties already covered above):

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://yourdomain.com/#organization",
      "name": "Hill Country Plumbing Co.",
      "subOrganization": [
        {"@id": "https://yourdomain.com/austin/#localbusiness"},
        {"@id": "https://yourdomain.com/round-rock/#localbusiness"}
      ]
    },
    {
      "@type": "Plumber",
      "@id": "https://yourdomain.com/austin/#localbusiness",
      "name": "Hill Country Plumbing - Austin Office",
      "parentOrganization": {"@id": "https://yourdomain.com/#organization"},
      "address": { "...": "..." }
    },
    {
      "@type": "Service",
      "@id": "https://yourdomain.com/#emergency-plumbing-service",
      "serviceType": "Emergency plumbing repair",
      "provider": {"@id": "https://yourdomain.com/#organization"},
      "areaServed": [{"@type": "City", "name": "Austin"}]
    }
  ]
}
</script>

The @graph wrapper lets you ship multiple linked blocks in a single <script> tag. It's cleaner than scattering separate scripts across the page, and Google parses it the same way.

What to skip and what to validate

A few traps we see weekly in audits.

Don't double-up by publishing LocalBusiness and Service on the same page when the business has no walk-in location. Pick Service. The LocalBusiness block will tell Google your home address is a public storefront, and Google will publish it on Maps.

Don't leave areaServed empty or stuff it with thirty cities you don't actually serve. Google has gotten better at noticing when a service-area block claims half the state. List only the cities or zones you'll genuinely drive to.

Don't forget serviceType. Without it, the AI search engines have no clean property to match against a query like "in-home dog grooming Boulder."

Validate before you ship. Google's Rich Results Test tells you which rich-result features your block qualifies for. The Schema Markup Validator catches syntax errors and invalid properties. Run both. They're free, and the failure modes are obvious: missing required field, invalid type, malformed JSON.

ClearGrade ships the schema for you

If you'd rather not hand-edit JSON, ClearGrade's Schema Generator builds custom JSON-LD specifically for service-area businesses. Answer a handful of questions about your business (storefront or no, cities served, services offered, hours) and the generator outputs the right blocks with the right @id linking. Platform-tier customers get the embed code shipped to the site for them, validated, with the rich-result eligibility report attached.

We built this because we kept seeing the same broken pattern across hundreds of audits. Service-area businesses with LocalBusiness schema, no areaServed, and a Google listing showing the owner's home. The fix is mechanical. We've automated the mechanical part.

Decision tree: which schema do I use?

Three questions. One answer.

  1. Do customers walk into a public storefront? If yes, LocalBusiness (or its specific subtype like Dentist, Restaurant, Plumber). Continue.
  2. Do you go to the customer instead, or in addition? If yes, add a Service block with areaServed and serviceType. Don't put the home address on it.
  3. Do you have more than one location, or do you want to control your brand identity in AI search? If yes, add an Organization block at the root, link locations via subOrganization, link services via provider.

If you only answered yes to question 1, ship one LocalBusiness block. If you answered yes to question 2 only, ship one Service block (and optionally a slim Organization for sameAs and knowsAbout). If you answered yes to all three, ship the @graph pattern with all three types and @id linking.

That's the whole decision. Pick the pattern, copy the block above, swap your real values in, validate. You can have correct local schema live on your site by tomorrow morning.


One thing to do this week: open your homepage source, find your current schema block (or confirm there isn't one), and run it through Google's Rich Results Test. If it fails, or if it's the wrong type for your business, grade your site free at ClearGrade and we'll tell you exactly which schema you need and what's missing. Twenty-four hours, no credit card.

Want a real grade on your marketing?

Free 6-dimension audit. 24-hour turnaround. Top 3 quick wins ranked by impact.

Run my free audit →