Massive ImpactMassive Impact

PLAYBOOK / STRUCTURED DATA

The Local Schema Pack

The Local Schema Pack

34-page guide · 30 min read · free

The most current schema documentation for local, professional, and service businesses, written against schema.org v30.0 (released March 2026).

Every type. Every relevant subtype. Every JSON-LD template. Plus the 2026 deprecations that broke half the schema playbooks online.


What's actually in this playbook

Six parts. Read in order if you are starting from zero. Skip to the part you need if you are extending an existing implementation.

Part 1 covers why schema matters now (AI Overview citations, not just rich results) and the Organization root that anchors everything. Part 2 is the full LocalBusiness taxonomy with all 31 direct subtypes. Part 3 covers service businesses after the ProfessionalService deprecation. Part 4 covers page-level schemas with the 2026 rich-results reality (HowTo gone, FAQ restricted). Part 5 covers Review, AggregateRating, and Person, the trust signals AI weights heaviest. Part 6 covers validation, deployment, and the 8 most common mistakes.

If you only have ten minutes, read Part 1 to understand the new stakes, then skim the LocalBusiness subtype map in Part 2 to find the right type for your business.


Part 1, Why Schema Matters in 2026 and the Organization Root

The new stakes

Schema markup used to be about rich results: stars in your Google listing, FAQ accordions in your search snippets, a knowledge panel on the right rail. Those were the visible payoff. In 2026, schema serves a second and now larger purpose: AI citation eligibility.

Three data points that reset how to think about it:

  • Pages with proper schema get cited 2.5 to 3.2 times more often by ChatGPT, Perplexity, Gemini, and Google AI Overviews than pages without.
  • AI Overviews show on more than half of Google searches, and the citations in those overviews come overwhelmingly from pages with structured data Google can parse cleanly.
  • 99% of AI citations come from pages already ranking in the top 10 organically. Schema is not a substitute for ranking; it is the lever that converts a top-10 ranking into an AI citation.

The shift: schema is no longer just a rich-result mechanism. It is the primary machine-readability layer that AI search engines use to extract, attribute, and cite content. Pages without schema still rank organically. Pages with schema get cited.

The 2026 reality check

Most schema advice on the internet is from 2022 to 2024 and is now wrong about three important things:

1, HowTo schema produces no rich results

Google deprecated HowTo rich results in September 2023 and finished phasing them out across desktop and mobile by 2025. The markup is now ignored by Google for visual search features. You can still use it (AI engines parse it for context) but expect zero rich result lift.

2, FAQ rich results are restricted to government and health sites

Google restricted FAQ rich results in 2023 to government and health authoritative sites. Marketing agency sites, local business sites, and SaaS sites do not get FAQ rich results regardless of how well-implemented the schema is. The schema still helps AI extraction; it just stopped earning the visible accordion in the SERP.

3, ProfessionalService was deprecated by schema.org

The general ProfessionalService type for catch-all use was deprecated due to confusion with the Service type. Specific subtypes (Dentist, Attorney, Electrician, Plumber, etc.) replaced it. Use LegalService as the umbrella for legal practices, MedicalBusiness for medical, HomeAndConstructionBusiness for trades. Part 3 covers the full replacement map.

If your current schema implementation relies on any of these three patterns, it needs to be rewritten.

Schema.org v30.0

The current schema.org version is v30.0, released March 19, 2026. Always reference the current version explicitly:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  ...
}
</script>

The @context field uses the canonical schema.org URL (without version number) so your markup stays current as schema.org ships new versions. The version number matters only when validating against a specific spec.

The Organization root

Almost every business website needs one root Organization block that lives on the homepage. This block is the anchor everything else links back to via @id references. Get it right once and the rest of your site can reference it consistently.

The minimum viable Organization block:

{
  "@context": "https://schema.org",
  "@type": "Organization",
  "@id": "https://example.com/#organization",
  "name": "Acme Coffee Roasters",
  "url": "https://example.com",
  "logo": {
    "@type": "ImageObject",
    "@id": "https://example.com/#logo",
    "url": "https://example.com/logo.png",
    "width": 600,
    "height": 200
  },
  "image": { "@id": "https://example.com/#logo" },
  "description": "Acme Coffee Roasters operates two specialty coffee cafes in Portland, Oregon.",
  "sameAs": [
    "https://www.facebook.com/acmecoffee",
    "https://www.instagram.com/acmecoffee",
    "https://www.linkedin.com/company/acme-coffee"
  ],
  "contactPoint": {
    "@type": "ContactPoint",
    "contactType": "customer service",
    "telephone": "+1-503-555-0100",
    "areaServed": "US",
    "availableLanguage": "English"
  }
}

Six fields that earn their place:

  • @id with a fragment identifier (#organization) lets other schema blocks reference this Organization without duplicating it.
  • name is the canonical brand name (use it identically everywhere).
  • logo with explicit width and height is required for Knowledge Panel eligibility.
  • description is the same Direct Answer Block factual summary used elsewhere on the page.
  • sameAs links to your verified social profiles, which AI uses to confirm entity identity across the web.
  • contactPoint is the canonical contact info, separate from individual location pages.

The graph pattern

Once your site has multiple schema blocks (Organization on homepage, LocalBusiness on location pages, Service on service pages), tie them together using the @graph pattern. One JSON-LD script per page, with all the relevant blocks inside one @graph array:

{
  "@context": "https://schema.org",
  "@graph": [
    { "@type": "Organization", "@id": "https://example.com/#organization", ... },
    { "@type": "LocalBusiness", "@id": "https://example.com/portland/#location",
      "parentOrganization": { "@id": "https://example.com/#organization" },
      ... },
    { "@type": "WebPage", "@id": "https://example.com/portland/#webpage",
      "about": { "@id": "https://example.com/portland/#location" },
      ... }
  ]
}

Three benefits:

  1. One script tag per page instead of three or four.
  2. Cross-references via @id keep the entities linked without duplication.
  3. Cleaner validation since the validator sees the whole knowledge graph in one block.

The graph pattern is what production schema implementations look like. Single-block-per-script is the beginner pattern; expect to migrate to the graph pattern within the first month.


Part 2, LocalBusiness and the 31 Subtypes Mapped to Verticals

The LocalBusiness root

LocalBusiness is a direct child of Organization used for a business with a physical location (or a branch of a larger organization). If your business has an address a customer can visit, you want LocalBusiness or one of its subtypes, not plain Organization.

The core properties every LocalBusiness needs:

{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "@id": "https://example.com/portland/#location",
  "name": "Acme Coffee Roasters Portland",
  "url": "https://example.com/portland/",
  "telephone": "+1-503-555-0100",
  "priceRange": "$$",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "1820 NW 23rd Avenue",
    "addressLocality": "Portland",
    "addressRegion": "OR",
    "postalCode": "97210",
    "addressCountry": "US"
  },
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": 45.5348,
    "longitude": -122.6989
  },
  "openingHoursSpecification": [
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
      "opens": "06:30",
      "closes": "20:00"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Saturday", "Sunday"],
      "opens": "07:00",
      "closes": "20:00"
    }
  ],
  "image": "https://example.com/portland/cafe.jpg",
  "parentOrganization": { "@id": "https://example.com/#organization" }
}

Eight properties that earn their place:

  1. @id with #location fragment for this specific branch
  2. name with the location baked in ("Acme Coffee Roasters Portland")
  3. address as a full PostalAddress block with street, city, region, postal code, country
  4. geo with latitude and longitude (not optional; Google uses this heavily)
  5. telephone in E.164 format (+1-503-555-0100)
  6. priceRange in dollar-sign format ($, $$, $$$, $$$$)
  7. openingHoursSpecification per day or group of days (covers exceptions for holidays with a second block)
  8. parentOrganization reference back to the root Organization

The 31 direct subtypes

LocalBusiness has 31 direct subtypes in schema.org v30.0. Using the correct subtype is the single biggest AI-citation lever inside LocalBusiness because it tells AI precisely what kind of business you are.

The full list, mapped to when to use each:

Subtype Use when you are a...
AnimalShelter Pet rescue, animal shelter, SPCA chapter
ArchiveOrganization Archive, historical society, special library
AutomotiveBusiness Parent for auto-repair, dealers, rentals (use subtypes below instead)
ChildCare Daycare, preschool, after-school program
Dentist Dental practice
DryCleaningOrLaundry Dry cleaner, laundromat
EmergencyService Fire, ambulance, disaster-response service
EmploymentAgency Staffing agency, recruiter, placement service
EntertainmentBusiness Escape room, bowling alley, arcade, movie theater, comedy club
FinancialService Bank, credit union, financial planner, tax service
FoodEstablishment Restaurant, cafe, bakery, bar, food truck (subtypes: Restaurant, Bakery, BarOrPub, CafeOrCoffeeShop, FastFoodRestaurant, IceCreamShop, etc.)
GovernmentOffice City hall, DMV, courthouse
HealthAndBeautyBusiness Salon, spa, nail salon, barber (subtypes: BeautySalon, DaySpa, HairSalon, HealthClub, NailSalon, TattooParlor)
HomeAndConstructionBusiness Parent for trades (subtypes below are the ones to actually use)
InternetCafe Internet cafe, coworking with desk rentals
LegalService Law firm, notary, legal aid (supertype of Attorney)
Library Public or private library
LodgingBusiness Hotel, motel, B&B, hostel, resort (subtypes: BedAndBreakfast, Campground, Hostel, Hotel, Motel, Resort, VacationRental)
MedicalBusiness Doctor, clinic, medical supply store (subtypes: Dentist, Optician, Pharmacy, Physician, many more)
ProfessionalService DEPRECATED, use specific subtype instead (see Part 3)
RadioStation Radio broadcaster
RealEstateAgent Real estate agent, brokerage
RecyclingCenter Recycling drop-off
SelfStorage Storage unit facility
ShoppingCenter Mall, outlet center
SportsActivityLocation Gym, yoga studio, climbing gym, bowling alley (subtypes: BowlingAlley, ExerciseGym, GolfCourse, SkiResort, StadiumOrArena, more)
Store Retail store of any kind (subtypes: AutoPartsStore, BookStore, ClothingStore, ComputerStore, ConvenienceStore, DepartmentStore, ElectronicsStore, Florist, FurnitureStore, GardenStore, GroceryStore, HardwareStore, HobbyShop, HomeGoodsStore, JewelryStore, LiquorStore, MensClothingStore, MobilePhoneStore, MovieRentalStore, MusicStore, OfficeEquipmentStore, OutletStore, PawnShop, PetStore, ShoeStore, SportingGoodsStore, TireShop, ToyStore, WholesaleStore)
TelevisionStation TV broadcaster
TouristInformationCenter Visitor center
TravelAgency Travel agency, tour operator

Commonly-misused subtypes

Four subtypes are the most common "I used LocalBusiness when I should have used something more specific" mistakes:

1, Restaurant (not FoodEstablishment)

FoodEstablishment is a parent. If you serve food and have a physical location, use one of the leaf subtypes: Restaurant, Bakery, BarOrPub, CafeOrCoffeeShop, FastFoodRestaurant, IceCreamShop. The leaf types make specific menu and reservation properties available; the parent type does not.

2, Plumber / Electrician / RoofingContractor (not HomeAndConstructionBusiness)

HomeAndConstructionBusiness is a parent. Use the leaf type for your specific trade: Plumber, Electrician, HVACBusiness, RoofingContractor, HousePainter, GeneralContractor, Locksmith, MovingCompany.

3, Attorney under LegalService (not ProfessionalService)

ProfessionalService is deprecated. LegalService is the current umbrella; Attorney is a specific subtype. Use Attorney for a lawyer or law firm. Use LegalService when the service offered is broader (legal aid, notary, paralegal services).

4, Specific medical subtypes (not MedicalBusiness)

Use the specific medical subtype: Dentist, Physician, Optician, Pharmacy, DiagnosticLab, Hospital, MedicalClinic. These make medical-specialty properties available and are weighted more heavily by Google for medical-specific rich results.

A complete EntertainmentBusiness example

Putting it together for an escape room venue:

{
  "@context": "https://schema.org",
  "@type": "EntertainmentBusiness",
  "@id": "https://example.com/portland/#location",
  "name": "Puzzle Haven Escape Rooms Portland",
  "url": "https://example.com/portland/",
  "telephone": "+1-503-555-0199",
  "priceRange": "$$",
  "description": "Puzzle Haven operates 6 themed escape rooms in downtown Portland for groups of 2 to 10 players. Rated 4.9 on Google across 1,240 reviews.",
  "image": [
    "https://example.com/portland/lobby.jpg",
    "https://example.com/portland/the-vault-room.jpg"
  ],
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "520 SW Yamhill Street",
    "addressLocality": "Portland",
    "addressRegion": "OR",
    "postalCode": "97204",
    "addressCountry": "US"
  },
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": 45.5189,
    "longitude": -122.6782
  },
  "openingHoursSpecification": [
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Tuesday", "Wednesday", "Thursday"],
      "opens": "15:00",
      "closes": "22:00"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Friday", "Saturday"],
      "opens": "12:00",
      "closes": "00:00"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Sunday",
      "opens": "12:00",
      "closes": "22:00"
    }
  ],
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": 4.9,
    "reviewCount": 1240,
    "bestRating": 5,
    "worstRating": 1
  },
  "parentOrganization": { "@id": "https://example.com/#organization" }
}

Every property earns its place: the specific subtype signals the business category, the address plus geo pair nails the location, the opening hours cover the real schedule with day-specific blocks, the aggregate rating anchors trust, the parent organization ties it to the root.


The rest of the Massive Impact library builds on patterns like this. See the full set at the Massive Impact resource library.

Part 3, Service Business Schema After the ProfessionalService Deprecation

What changed and why

Schema.org deprecated the catch-all ProfessionalService type because it caused confusion with the Service type. They were two different concepts living under one name: ProfessionalService was supposed to describe the business, and Service was supposed to describe the offering, but everyone used ProfessionalService for everything.

The fix is structural. Instead of one type, use three:

  1. Organization describes the business itself (the entity).
  2. A specific LocalBusiness subtype describes the physical location or branch.
  3. Service describes the actual offerings, with Offer for pricing.

Three types, three jobs, no overlap. Every service business website that used ProfessionalService for everything needs this restructure.

The replacement map

For every formerly common use of ProfessionalService, here is the current correct mapping:

Old (deprecated) Use these instead
Lawyer or law firm LegalService (umbrella) or Attorney (specific)
Accounting firm or CPA AccountingService
Financial advisor FinancialService
Notary Notary (under LegalService)
Dentist Dentist (under MedicalBusiness)
General contractor GeneralContractor (under HomeAndConstructionBusiness)
Electrician Electrician (under HomeAndConstructionBusiness)
Plumber Plumber (under HomeAndConstructionBusiness)
HVAC company HVACBusiness (under HomeAndConstructionBusiness)
Roofing contractor RoofingContractor (under HomeAndConstructionBusiness)
House painter HousePainter (under HomeAndConstructionBusiness)
Locksmith Locksmith (under HomeAndConstructionBusiness)
Moving company MovingCompany (under HomeAndConstructionBusiness)
Marketing agency Organization plus Service blocks (no specific LocalBusiness subtype exists)
Consulting firm Organization plus Service blocks
Software development agency Organization plus Service blocks

Three patterns by industry:

  • Trades and licensed professions have specific subtypes (Plumber, Electrician, Attorney, Dentist). Use the subtype.
  • Medical practices have MedicalBusiness and its many subtypes. Use the most specific one.
  • Agencies and consulting firms have no LocalBusiness subtype because they often do not have customer-facing physical locations. Use Organization plus separate Service blocks for each offering.

The Service block

Service is a separate type that describes a specific offering. Use it on service-detail pages (one Service block per page) or as an array of services on a hub page.

A complete Service block:

{
  "@context": "https://schema.org",
  "@type": "Service",
  "@id": "https://example.com/services/seo-audit/#service",
  "name": "SEO Audit",
  "serviceType": "SEO Audit",
  "description": "A 30-day comprehensive SEO audit covering technical health, content quality, backlink profile, competitor gaps, and a prioritized 90-day action plan.",
  "provider": {
    "@id": "https://example.com/#organization"
  },
  "areaServed": {
    "@type": "Country",
    "name": "United States"
  },
  "serviceOutput": "A 40-page audit report with prioritized recommendations and a 90-day implementation plan.",
  "offers": {
    "@type": "Offer",
    "price": "2500.00",
    "priceCurrency": "USD",
    "priceValidUntil": "2026-12-31",
    "availability": "https://schema.org/InStock",
    "url": "https://example.com/services/seo-audit/#book"
  },
  "termsOfService": "https://example.com/terms",
  "image": "https://example.com/images/seo-audit-cover.jpg"
}

Five fields that earn their place:

  1. provider with @id reference back to the Organization, so AI knows who delivers the service.
  2. areaServed to make geographic targeting explicit (Country, State, City, or AdministrativeArea).
  3. serviceOutput in plain language so AI knows what the customer receives.
  4. offers.price with priceCurrency and priceValidUntil. Specific pricing beats vague pricing every time for AI extraction.
  5. offers.availability using one of the schema.org availability constants (InStock, LimitedAvailability, SoldOut, PreOrder).

Service hub pages with multiple offerings

For a hub page listing multiple services, use Organization plus an OfferCatalog:

{
  "@context": "https://schema.org",
  "@type": "Organization",
  "@id": "https://example.com/#organization",
  "name": "Acme Marketing Agency",
  "url": "https://example.com",
  "hasOfferCatalog": {
    "@type": "OfferCatalog",
    "name": "Marketing Services",
    "itemListElement": [
      {
        "@type": "Offer",
        "itemOffered": {
          "@type": "Service",
          "name": "SEO Audit",
          "description": "Comprehensive 30-day SEO audit...",
          "url": "https://example.com/services/seo-audit/"
        },
        "price": "2500.00",
        "priceCurrency": "USD"
      },
      {
        "@type": "Offer",
        "itemOffered": {
          "@type": "Service",
          "name": "Content Strategy",
          "description": "12-month editorial calendar with topic research...",
          "url": "https://example.com/services/content-strategy/"
        },
        "price": "5000.00",
        "priceCurrency": "USD"
      },
      {
        "@type": "Offer",
        "itemOffered": {
          "@type": "Service",
          "name": "Conversion Rate Optimization",
          "description": "90-day CRO sprint with A/B testing...",
          "url": "https://example.com/services/cro/"
        },
        "price": "8000.00",
        "priceCurrency": "USD"
      }
    ]
  }
}

The hub page gets one Organization-level block with the catalog. Each individual service page gets its own dedicated Service block (the more detailed one shown earlier).

Productized services

If your service is sold as a fixed-price package (not custom quoted), use Product instead of Service. Product schema makes Product rich results available in Google search; Service schema does not.

{
  "@type": "Product",
  "name": "SEO Audit Sprint",
  "description": "A 30-day SEO audit delivered as a fixed-price package: technical audit, content audit, backlink analysis, prioritized action plan.",
  "image": "https://example.com/seo-audit-cover.jpg",
  "brand": { "@id": "https://example.com/#organization" },
  "offers": {
    "@type": "Offer",
    "price": "2500.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "url": "https://example.com/services/seo-audit/#book"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": 4.8,
    "reviewCount": 38
  }
}

Two reasons to use Product over Service for productized offerings:

  1. Product rich results. Google shows price, rating, and availability directly in search results for Product schema. Service schema does not get the same treatment.
  2. AI extraction. AI engines extract Product attributes (price, brand, availability) as discrete data points, making the offering more cite-able in shopping-style queries.

The line: if you have a fixed price and a customer can buy without a sales call, use Product. If the offering needs custom scoping or a discovery conversation first, use Service.

Marketing agencies and consultancies (the no-LocalBusiness case)

Agencies and consulting firms often do not have customer-facing physical locations. The canonical pattern: skip the LocalBusiness subtype entirely and use Organization plus Service blocks.

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://example.com/#organization",
      "name": "Acme Marketing Agency",
      "url": "https://example.com",
      "logo": { "@id": "https://example.com/#logo" },
      "description": "Acme Marketing Agency builds SEO, content, and conversion programs for B2B SaaS companies.",
      "contactPoint": {
        "@type": "ContactPoint",
        "contactType": "sales",
        "email": "[email protected]",
        "availableLanguage": "English"
      },
      "sameAs": [...]
    },
    {
      "@type": "Service",
      "name": "SEO Audit",
      "provider": { "@id": "https://example.com/#organization" },
      ...
    }
  ]
}

No LocalBusiness, no address block on the Organization, no geo. The Organization handles entity identity; the Service blocks handle offerings; the customer's understanding of "where you are" comes from the agency's About page or contact form, not from a schema location.

This is the correct pattern for any service business without a customer-visit location: agencies, consultants, software dev shops, designers, accountants who only meet via Zoom.


Part 4, Page-Level Schemas: FAQ, Article, BreadcrumbList, Event, Course

These are the schemas that attach to specific page types rather than the business itself. The 2026 reality changed several of them. Use them anyway, just for different reasons.

FAQPage (still essential, even without rich results)

The current state: Google restricted FAQ rich results in 2023 to government and health authoritative sites. Marketing agency sites, local business sites, SaaS sites do not get the visible accordion in the SERP.

The reason to use FAQPage anyway: AI engines extract FAQ schema heavily. ChatGPT, Perplexity, Gemini, and Google AI Overviews all parse FAQPage structured data and use it to answer questions in citations. The visible rich result is gone for most sites; the AI extraction value is unchanged.

{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "@id": "https://example.com/portland/#faq",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What are Acme Coffee Roasters' Portland hours?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "The flagship cafe at 1820 NW 23rd Avenue is open daily from 6:30 AM to 8:00 PM. The second location at 4400 SE Hawthorne Boulevard is open 7:00 AM to 7:00 PM."
      }
    },
    {
      "@type": "Question",
      "name": "Does Acme Coffee deliver to offices?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes. The corporate subscription delivers freshly roasted beans to 84 Portland-area offices weekly, starting at $128 per month for a 5-pound bag."
      }
    }
  ]
}

Three rules for the FAQ block:

  1. One FAQPage per page, with all the page's FAQs inside mainEntity as an array.
  2. Each Question.name must be a real question someone would type. No "What about pricing?" Use "How much does the corporate subscription cost?"
  3. Each acceptedAnswer.text must be self-contained. AI extracts the answer in isolation. If your answer says "see above," it does not work.

HowTo (deprecated for rich results)

The current state: Google deprecated HowTo rich results in September 2023 and finished phasing them out across desktop and mobile by 2025. The schema still validates and AI engines still parse it, but it no longer produces a visible HowTo card in the SERP.

The recommendation: do NOT spend new effort on HowTo schema. If you have it on existing pages, leave it. For new content, use a clear step-by-step structure in the page body itself (numbered headings, lists, images) and skip the HowTo schema. Save the schema attention for FAQPage, BreadcrumbList, and Article.

Article and BlogPosting

For blog posts, news articles, and editorial content. Article is the parent type; BlogPosting is the more specific subtype for blog content. Use BlogPosting for blog content; use NewsArticle for news content; use Article only when the content does not fit either of the more specific subtypes.

{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "@id": "https://example.com/blog/post-slug/#article",
  "headline": "How to choose the right escape room for first-timers",
  "description": "A practical guide to picking an escape room based on your group size, experience level, and the kind of experience you want.",
  "image": [
    "https://example.com/blog/post-slug/cover.jpg"
  ],
  "datePublished": "2026-04-15T09:00:00-07:00",
  "dateModified": "2026-04-22T14:30:00-07:00",
  "author": {
    "@type": "Person",
    "name": "Sarah Kowalski",
    "url": "https://example.com/team/sarah"
  },
  "publisher": {
    "@id": "https://example.com/#organization"
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://example.com/blog/post-slug/"
  },
  "wordCount": 1840,
  "articleSection": "Guides"
}

Six fields that earn their place:

  1. headline must match (or be very close to) the page title and the H1.
  2. datePublished in ISO-8601 format with timezone.
  3. dateModified updated whenever you make substantive edits to the article.
  4. author as a Person block, not a string. AI extracts author identity for attribution.
  5. publisher with @id reference back to the Organization, so AI ties the article to your brand.
  6. mainEntityOfPage to confirm the article is the primary entity on this URL.

BreadcrumbList shows the hierarchy of pages leading to the current page. Google still uses BreadcrumbList for the breadcrumb display in search results (one of the few visual rich results that survived 2024-2025).

{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "@id": "https://example.com/portland/cafe-menu/#breadcrumb",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://example.com/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Portland",
      "item": "https://example.com/portland/"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Menu",
      "item": "https://example.com/portland/cafe-menu/"
    }
  ]
}

Two rules:

  • Position numbers are 1-indexed and must be sequential.
  • The last item is the current page, with the full URL as the item value.

Add BreadcrumbList to every page deeper than the homepage. Two minutes of work per page; the breadcrumb display in Google SERPs survives.

Event (for classes, workshops, performances)

If your business runs scheduled events (classes, workshops, performances, recurring sessions, retreats), Event schema is the right type. Event rich results in Google still appear and drive direct bookings.

{
  "@context": "https://schema.org",
  "@type": "Event",
  "@id": "https://example.com/events/2026-summer-cupping/#event",
  "name": "Acme Coffee Summer Cupping Workshop",
  "description": "A 2-hour guided cupping of 6 single-origin coffees from our 2026 summer harvest. Limited to 12 attendees.",
  "startDate": "2026-06-15T18:00:00-07:00",
  "endDate": "2026-06-15T20:00:00-07:00",
  "eventStatus": "https://schema.org/EventScheduled",
  "eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode",
  "location": {
    "@type": "Place",
    "name": "Acme Coffee Roasters Portland Flagship",
    "address": {
      "@type": "PostalAddress",
      "streetAddress": "1820 NW 23rd Avenue",
      "addressLocality": "Portland",
      "addressRegion": "OR",
      "postalCode": "97210",
      "addressCountry": "US"
    }
  },
  "image": "https://example.com/events/2026-summer-cupping/cover.jpg",
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/events/2026-summer-cupping/#book",
    "price": "45.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "validFrom": "2026-04-01T00:00:00-07:00"
  },
  "organizer": {
    "@id": "https://example.com/#organization"
  },
  "performer": {
    "@type": "Person",
    "name": "Marcus Tan",
    "jobTitle": "Head Roaster"
  }
}

Eight fields that earn their place:

  1. startDate and endDate in ISO-8601 with timezone.
  2. eventStatus using one of the schema.org constants (EventScheduled, EventCancelled, EventPostponed, EventRescheduled, EventMovedOnline).
  3. eventAttendanceMode (OfflineEventAttendanceMode, OnlineEventAttendanceMode, or MixedEventAttendanceMode).
  4. location as a Place block (not just a string).
  5. offers with price, currency, availability, and a booking URL.
  6. organizer referencing the Organization.
  7. performer if there is a named host or instructor (drives Knowledge Panel for the performer).

Course (for educational offerings)

If you sell training, courses, certifications, workshops as a curriculum (not a one-off event), use Course. Course rich results in Google still appear.

{
  "@context": "https://schema.org",
  "@type": "Course",
  "name": "Specialty Coffee Brewing 101",
  "description": "A 4-week online course teaching pour-over, AeroPress, and French press techniques.",
  "provider": {
    "@id": "https://example.com/#organization"
  },
  "hasCourseInstance": {
    "@type": "CourseInstance",
    "courseMode": "Online",
    "courseSchedule": {
      "@type": "Schedule",
      "duration": "P4W",
      "repeatFrequency": "Weekly",
      "repeatCount": 4
    },
    "instructor": {
      "@type": "Person",
      "name": "Marcus Tan"
    }
  },
  "offers": {
    "@type": "Offer",
    "price": "199.00",
    "priceCurrency": "USD",
    "category": "Paid"
  }
}

Course schema requires both Course and at least one CourseInstance. The CourseInstance describes a specific run of the course (mode, schedule, instructor). One Course can have multiple CourseInstances.

What page-level schemas to skip

Three schemas that are commonly recommended but produce no rich results and minimal AI value in 2026:

  • SiteNavigationElement: was supposed to help with sitelinks. Google ignores it now and picks sitelinks algorithmically.
  • Speakable: intended for voice assistants. Adoption is minimal; voice assistants pull from regular schema instead.
  • SearchAction on WebSite: still works for the Sitelinks Search Box but only on already-prominent brand sites. Smaller sites do not get the search box regardless.

These three are not harmful; they are just low-yield. Spend the implementation budget elsewhere first.


This pattern is one piece of a wider toolkit. Adjacent playbooks at the Massive Impact resource library.

Part 5, Review, AggregateRating, and Person: the Trust Signals AI Weights Heavily

Why trust signals get extra weight

AI search engines pull citations from many sources but weight credibility heavily. The schema-level signals that indicate credibility (real reviews, named authors, named team members, named partners) consistently bias citations toward the entities that have them.

Three schemas carry most of the trust signal weight in 2026:

  1. Review for individual customer reviews
  2. AggregateRating for the rolled-up rating across many reviews
  3. Person for named team members, authors, and contributors

AggregateRating

AggregateRating is the average rating across all reviews of an item or business. Add it to the LocalBusiness, Product, or Service block as a child property.

{
  "@type": "AggregateRating",
  "ratingValue": 4.9,
  "reviewCount": 1840,
  "bestRating": 5,
  "worstRating": 1
}

Four fields, all required for Google to use the rating in rich results:

  1. ratingValue as a number (4.9 not "4.9 stars")
  2. reviewCount as an integer count
  3. bestRating (the maximum possible rating, usually 5)
  4. worstRating (the minimum, usually 1)

Two rules that prevent silent ignore:

  • The rating must reflect actual reviews. Do not put 5.0 with 1,200 reviews if you have 38 reviews. Google can detect inflation by cross-checking against Google Business Profile and similar review platforms.
  • The rating must be visible on the page. If the schema says 4.9 stars from 1,840 reviews, the page must display that same number visibly. Schema-only ratings get flagged as deceptive.

Review (individual reviews)

For pages that quote individual customer reviews, mark each review with its own Review block. Use these inside LocalBusiness.review array, Product.review array, or Service.review array.

{
  "@type": "Review",
  "author": {
    "@type": "Person",
    "name": "Sarah K."
  },
  "datePublished": "2026-04-12",
  "reviewBody": "The cupping workshop changed how I think about coffee. Marcus walked us through 6 single-origins from the summer harvest and the differences were night and day. Worth every dollar.",
  "reviewRating": {
    "@type": "Rating",
    "ratingValue": 5,
    "bestRating": 5,
    "worstRating": 1
  }
}

Four rules:

  1. The review text must be real. Google has consequences for fake review markup, including silent suppression of all rich results from the site.
  2. Author name can be partial (first name + last initial) for privacy, but must correspond to a real reviewer.
  3. datePublished in ISO-8601, accurate to the day at minimum.
  4. reviewRating with the same bestRating and worstRating as the parent AggregateRating.

Three to six review blocks per page is the sweet spot. More than six does not improve extraction and adds page weight.

Person (named team members, authors, contributors)

Person schema attaches identity to humans associated with the business. AI engines use Person schema to attribute content (who wrote this article, who is the team member quoted in this testimonial, who is the certified expert behind this service).

{
  "@type": "Person",
  "@id": "https://example.com/team/sarah-kowalski/#person",
  "name": "Sarah Kowalski",
  "jobTitle": "Guest Experience Manager",
  "worksFor": {
    "@id": "https://example.com/#organization"
  },
  "url": "https://example.com/team/sarah-kowalski/",
  "image": "https://example.com/team/sarah-kowalski.jpg",
  "sameAs": [
    "https://www.linkedin.com/in/sarah-kowalski",
    "https://twitter.com/sarahkowalski"
  ],
  "alumniOf": "Rutgers University",
  "knowsAbout": [
    "Guest experience management",
    "Hospitality operations",
    "Staff training and development"
  ]
}

Five fields that earn their place:

  1. @id with a stable URL fragment for cross-references (the same Person can appear as author on blog posts and performer on event listings).
  2. worksFor with @id reference back to the Organization.
  3. sameAs linking to verified profiles (LinkedIn especially) so AI confirms the identity.
  4. image with a clear professional photo (square, 600x600 minimum).
  5. knowsAbout as an array of topics; AI uses this to evaluate expertise on a topic when deciding to cite.

How the three connect

The trust signals reinforce each other when properly linked:

  • The Organization links to its Person team members via employee or via Person's worksFor.
  • Articles attribute to a Person via author.
  • Events attribute to a Person via performer or organizer.
  • The same Person @id appears in all three places, so AI builds a consistent picture of who the named expert is and what they are associated with.
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://example.com/#organization",
      "name": "Acme Coffee Roasters",
      "employee": [
        { "@id": "https://example.com/team/marcus-tan/#person" }
      ]
    },
    {
      "@type": "Person",
      "@id": "https://example.com/team/marcus-tan/#person",
      "name": "Marcus Tan",
      "jobTitle": "Head Roaster",
      "worksFor": { "@id": "https://example.com/#organization" }
    },
    {
      "@type": "Event",
      "name": "Summer Cupping Workshop",
      "performer": { "@id": "https://example.com/team/marcus-tan/#person" },
      "organizer": { "@id": "https://example.com/#organization" }
    }
  ]
}

Four blocks, three entities, eight @id references. AI builds a graph: Acme employs Marcus, Marcus runs the workshop, the workshop is at Acme.

What NOT to do with trust schemas

Three failure modes that get sites silently ignored or visibly penalized:

1, Self-serving ratings without a real review system

Putting AggregateRating with 4.9 stars on a brand-new page with no underlying review platform. Google detects the absence of corroborating signals (no Google Business Profile reviews, no Yelp, no Trustpilot) and discards the rating.

2, Inflated review counts

Inflating review counts to look bigger triggers manual review. Google has done occasional sweeps for fake review markup; affected sites lose all rich results across their entire domain.

3, Person blocks for fictional staff

Person schema for a "Sarah" who does not exist as a real employee or named author. AI engines cross-check Person identity against LinkedIn and other public sources. Persons with no verifiable existence get treated as fabrication and the schema discounted.

The pattern: trust signals work because they are verifiable. Fake trust signals do not just fail to work; they actively damage the site's standing.


Part 6, Validation, Deployment, and the 8 Mistakes That Make Schema Invisible

This is the part that turns a valid playbook into shipped schema that actually shows up in AI Overviews and rich results. Validation, deployment paths, monitoring, and the eight failure patterns to avoid.

Where to put schema in the page

Three placement options. One is right; two will silently lose markup.

  1. <script type="application/ld+json"> in the <head> or <body>. This is the recommended approach. Google, Bing, ChatGPT, Perplexity, and Gemini crawlers all parse JSON-LD blocks consistently from either location. Head is conventional; body works too.
  2. Microdata or RDFa attributes inline on HTML. Still supported by Google but not preferred. AI crawlers have inconsistent extraction across these formats. Avoid for any new build.
  3. JSON-LD inserted after page render via JavaScript. Risky. Google has improved JS rendering but AI crawlers (especially the Perplexity and ChatGPT bots) often skip rendered content. If schema only appears post-render, expect it to be missed by half the surfaces you want citations from.

The rule: server-side render JSON-LD into the HTML response. Do not depend on client-side hydration.

One graph per page or many blocks?

Two valid patterns:

Pattern A, single @graph per page

All entities for the page in one <script> tag using @graph array with @id cross-references. Cleaner. Easier to validate. Easier to maintain when entities reference each other (Article references its Person author, Event references its Organization, etc).

Pattern B, multiple separate <script> blocks

Each entity in its own <script type="application/ld+json"> block. Easier to template (each component renders its own block). Crawlers handle this fine but you lose the cross-reference benefit unless you maintain consistent @id across blocks.

For a new build, Pattern A. For a CMS where each component renders independently, Pattern B with strict @id discipline.

Validation tools (use all four for a new deployment)

1, Google Rich Results Test

URL: search.google.com/test/rich-results

What it tests: whether the page produces rich results that Google currently supports (the 35 visual rich result types). It does NOT test whether the schema is parseable in general; it tests Google's specific subset.

Use it to confirm: rich result eligibility, required field presence, image references resolve, business hours format correctness.

It will not flag: extra schema that is correct but does not produce a rich result (most Organization schema, Person schema, knowsAbout arrays, etc).

2, Schema.org Validator

URL: validator.schema.org

What it tests: whether the JSON-LD is structurally valid against the schema.org spec. Catches type errors, missing required properties, malformed JSON, invalid date formats.

Use it to confirm: structural validity of every schema you ship, regardless of whether it produces a rich result.

This is the broader validator. Run it first, then run Google's tool for the rich-result-eligible subset.

3, Yandex Structured Data Validator

URL: webmaster.yandex.com/tools/microtest/

Useful as an independent third opinion. Catches some property errors that the other two miss.

4, Manual JSON-LD parse test

In a browser console:

JSON.parse(document.querySelector('script[type="application/ld+json"]').textContent)

If this throws, the JSON is malformed. Crawlers will skip the entire block. This is the fastest first-line check before sending to any validator.

Deployment by stack

Static sites (Astro, Next.js static, Hugo, 11ty)

Inject the JSON-LD as a string in the page template. For Astro:

---
const schema = {
  "@context": "https://schema.org",
  "@graph": [/* ... */]
};
---
<script type="application/ld+json" set:html={JSON.stringify(schema)} />

For Next.js, render in the page component using <Script> or directly in <Head>:

<Script
  id="schema-graph"
  type="application/ld+json"
  dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>

WordPress

Three options, ranked:

  1. Yoast SEO Premium (recommended): generates Organization, WebSite, and BreadcrumbList automatically; supports custom JSON-LD per page via the schema editor. Yoast's defaults are spec-compliant in 2026.
  2. Rank Math: similar to Yoast, with a more aggressive auto-generation approach. Good defaults but verify against the schema.org validator before trusting.
  3. Custom JSON-LD via the theme's wp_head hook: full control, no plugin overhead, but requires PHP and discipline to keep up with spec changes.

Avoid plugins that auto-generate FAQ or HowTo schema unless you can disable those (both are no longer eligible for rich results in most cases and add page weight for nothing).

Shopify

Use the Shopify SEO app ecosystem (Smart SEO, JSON-LD for SEO, etc) for Product and Organization. Shopify's built-in Product structured data is incomplete; add a third-party schema layer for complete Product + Offer + AggregateRating blocks.

Headless CMS

Render JSON-LD at the framework layer, not the CMS layer. Keep schema generation as page-render logic so type-safety and validation can be enforced at build time.

Monitoring after deployment

Three signals to watch for the first 8 weeks after deploying schema:

  1. Search Console > Enhancements: Google reports which structured data types it parsed and any errors per URL. Check weekly.
  2. Search Console > Performance > filter by Search Appearance > Rich result type: confirms which rich results are actually appearing in SERPs and on which queries.
  3. AI search citations: manually check ChatGPT, Perplexity, and Gemini for queries you should rank for. Pages with proper schema typically start getting cited within 3 to 6 weeks of publish, sometimes faster.

If Search Console reports zero rich results 6 weeks after deploy and validation passes, the issue is usually a deeper signal (low E-E-A-T, thin content, low domain authority) rather than a schema bug. Schema is a multiplier, not a base.

The 8 mistakes that make schema invisible to crawlers

Mistake 1, Schema that contradicts visible page content

Schema says price is $99. Page says $149. Schema says rating is 4.9. Page shows 4.6. Schema says open until 9pm. Page hours block shows close at 6pm.

Google explicitly downweights or ignores schema that contradicts visible content. The fix: make schema generation read from the same source of truth as the visible page.

Mistake 2, Missing or broken @id cross-references

Multiple entities in a graph but no @id on any of them, or @id values that do not match across blocks. Crawlers cannot link the entities and treat each as standalone. The benefit of the connected graph is lost.

The fix: every reusable entity (Organization, Person, Place, Service) gets an @id. Use the canonical URL plus a fragment (#organization, #person, #service-cupping-workshop) consistently across the site.

Mistake 3, Inconsistent NAP across schema, GMB, and citations

Name, Address, Phone in your schema must match Google Business Profile and major citation directories exactly. "Acme Coffee Roasters Inc." in one place, "Acme Coffee Roasters" in another, "Acme Coffee" in a third. Each variation is a confidence hit.

The fix: pick one canonical name (whatever GMB shows) and use it everywhere. Phone format and address format also must match (no ZIP+4 in one place and 5-digit ZIP in another).

Mistake 4, Wrong LocalBusiness subtype

Defaulting to LocalBusiness for everything when a more specific subtype exists. A dental clinic marked as LocalBusiness rather than Dentist loses the disambiguation that makes the listing eligible for Dentist-specific rich results and AI vertical bias.

The fix: use Part 2's subtype map. The most specific available subtype always wins.

Mistake 5, Adding deprecated rich result schema

Still publishing HowTo schema (deprecated 2023, fully phased out 2025) or FAQPage schema on a non-government, non-health page expecting rich results. Wastes page weight and signals to crawlers that the site is operating from outdated playbooks.

The fix: HowTo, skip entirely. FAQPage, only if the site is gov/health, OR keep it for the AI extractability benefit but do not expect rich results.

Mistake 6, Self-rated AggregateRating with no review system

AggregateRating of 4.9 stars on a page with no Google reviews, no Yelp, no Trustpilot, no actual review system anywhere. Google detects the absence of corroborating signals and silently discards.

The fix: only mark up reviews and ratings that actually exist. If you have 38 Google reviews averaging 4.6, mark up 4.6 with reviewCount 38. Match reality.

Mistake 7, JSON-LD that does not parse

A trailing comma. An unescaped quote inside a description. A missing closing brace. The crawler hits the error and silently abandons the entire block. No error appears in Search Console because the schema effectively does not exist.

The fix: validate every JSON-LD block with the manual parse test before deploy. Use a build-time validator. Never hand-edit JSON-LD in production.

Mistake 8, Schema only on the homepage

Marking up the Organization on the homepage and stopping there. Every page on the site benefits from at least Organization (via @id reference) and BreadcrumbList. Service pages need Service. Article pages need Article + Person. Individual product pages need Product. The homepage alone is one entry point; deep pages are where most AI citations originate.

The fix: schema as part of the page template, not a one-off. Every page type has its required schemas; include them as part of the template.

Final pre-launch checklist

Before considering a schema rollout complete:

  • Organization root rendered in head, with full address, contact, sameAs links, and logo
  • Correct LocalBusiness subtype (or service/professional pattern) on the homepage and contact page
  • BreadcrumbList on every page below the homepage
  • Page-type-specific schema on every template (Article, Product, Service, Event, Course)
  • Person schema for every named author and team member, with @id, worksFor, sameAs
  • Review and AggregateRating only where real reviews exist, matching the visible numbers
  • All schema validates in both validator.schema.org and Google's Rich Results Test
  • All @id values consistent and resolvable across the graph
  • No deprecated schemas (HowTo, generic ProfessionalService) anywhere
  • Monitoring set up in Search Console; weekly check on the Enhancements report
  • AI citation check (ChatGPT, Perplexity, Gemini) at the 4-week and 8-week marks

Schema is the most under-used citation lever in 2026. The sites that get this right are the sites that show up in AI Overviews when their competitors do not. Ship it carefully, validate it ruthlessly, and let the citations compound.


There is more where this came from. For deeper playbooks on AI search, content distribution, and structured data strategy, visit winmassiveimpact.com


The rest of the guide is yours, free.

Enter your email to keep reading and get the PDF to keep.

No spam. One email unlocks every Massive Impact resource.

What you did with the website, they did not have that level of architecture to it, and I think that just is helping it climb.
Andre, Massive Impact client

Tip the first domino

One move can change everything.

Book a call and we will show you the smallest right move for your business. No pressure, no jargon.