Schema Markup SOP

Just some notes:

Questions

  • How do we add schema per page?

Local/Contact info: use our Schema Generator: https://hub.ampv.com/schema/

  • Should be listed on homepage and all main landing pages

Areas Served

  • Should be loaded on geolocation pages.

Reviews

  • Not sure?

FAQs

  • Should be added to all pages with FAQs.

1. Purpose & Scope

This SOP standardizes how we implement JSON-LD structured data (schema markup) for home service clients — plumbers, electricians, HVAC companies, roofers, general contractors, landscapers, pest control, locksmiths, movers, and similar trades. Consistent schema helps these sites:

  • Qualify for rich results (star ratings, FAQ dropdowns, breadcrumbs) in search
  • Reinforce local relevance signals that support Google Business Profile and local pack rankings
  • Give search engines an unambiguous read on what the business is, what it does, where it serves, and what customers say about it

This SOP covers five schema types, which together handle the vast majority of home service sites:

  1. LocalBusiness (trade-specific subtype) — the business entity itself
  2. Service — individual service offerings
  3. FAQPage — Q&A content blocks
  4. BreadcrumbList — site navigation hierarchy
  5. Review / AggregateRating — customer feedback signals

Use the companion Schema Generator Tool (schema-generator.html) to produce the actual JSON-LD for each client — this SOP explains what data to collect, where each schema type goes, and how to QA it before it ships.


2. Before You Start: Information to Collect

Gather this from the client intake form, their Google Business Profile, and the live site. Missing or inconsistent data here is the #1 cause of rework later.

Business identity

  • Legal/DBA business name (exactly as it appears on GBP and the site footer)
  • Primary phone number (in the format the site displays it)
  • Website URL (canonical, with correct protocol/www preference)
  • Logo file (square, min 112x112px, hosted on their domain)
  • Year founded / founder name (optional but useful for Organization fields)

Address & service area

  • Most home service clients have both a public storefront/office address and a service area wider than that one location (e.g. an office in Mesa that also services Gilbert, Chandler, and Tempe). This is the default case — collect both:
    • Physical address (street, city, state, zip) if there’s a public storefront/office
    • Full list of cities/counties/zip codes actually served, even if it extends well beyond the office’s city
  • Only omit the address if the business is a genuine service-area business (SAB) with no public storefront (mobile-only operations, or a client who has intentionally hidden their address on Google Business Profile for privacy/safety). In that case do not publish a street address in schema — use areaServed only, matching what’s hidden/shown on GBP
  • When in doubt, check the client’s Google Business Profile: if GBP shows a public address, schema should include it; if GBP has the address hidden and only shows a service area, schema should match that
  • Geo coordinates (lat/long) if a physical location is being disclosed

Hours & category

  • Hours of operation per day (including 24/7 emergency service flags, common for plumbing/HVAC/restoration)
  • The most specific matching Schema.org business type (see Section 3 table) — avoid generic LocalBusiness when a trade-specific type exists

Services

  • Full list of services offered, each with a short description
  • Whether pricing is public (if so, note priceRange, e.g., $$)
  • Service area per service, if it differs from the general business service area

Reviews

  • Aggregate rating value and review count (pulled from Google, or from a review platform the client has rights to display)

Never fabricate or estimate ratings. Only mark up reviews that genuinely exist and are visible/verifiable on the page. Marking up reviews not visible on the page violates Google’s structured data guidelines and risks a manual action.

FAQ content

  • Actual FAQ copy already on (or being added to) the page. Schema must mirror visible on-page content word-for-word — no hidden or invented Q&A.

Site structure

  • Breadcrumb trail for each page type (Home > Services > [Service] > [City], etc.)

3. Choosing the Right Schema.org Type

Always use the most specific type available. Schema.org’s LocalBusiness hierarchy includes purpose-built subtypes for most trades — using them (instead of generic LocalBusiness) gives search engines a clearer signal and is a best practice we apply by default.

TradeRecommended @type
PlumbingPlumber
ElectricalElectrician
HVACHVACBusiness
RoofingRoofingContractor
General contracting / remodelingGeneralContractor
PaintingHousePainter
LocksmithLocksmith
MovingMovingCompany
Pest controlPestControl (fallback: HomeAndConstructionBusiness)
Landscaping / lawn careHomeAndConstructionBusiness (no more specific subtype exists)
Cleaning servicesHomeAndConstructionBusiness (or LocalBusiness if not construction-adjacent)
Garage doors, flooring, fencing, etc. (no exact subtype)HomeAndConstructionBusiness

If none of Schema.org’s subtypes match the trade, fall back to HomeAndConstructionBusiness, then to LocalBusiness as a last resort. All of these subtypes inherit LocalBusiness properties, so addresstelephoneopeningHoursSpecificationareaServedaggregateRating, etc. all still apply.


4. Implementation by Page Type

4.1 Homepage

  • One LocalBusiness (trade-specific subtype) block with full business details
  • aggregateRating nested inside it if reviews are displayed on the homepage
  • BreadcrumbList only if the homepage itself shows a breadcrumb (usually not needed)

4.2 Service Pages (e.g., “Drain Cleaning,” “AC Repair”)

  • One Service block per page:
    • serviceType (plain-language name)
    • provider referencing the business (either repeat key LocalBusiness fields or use an @id reference — see Section 6)
    • areaServed for that specific service
    • description matching the visible page copy
  • BreadcrumbList reflecting Home > Services > [Service Name]
  • If the page has an FAQ section, add FAQPage matching that section exactly

4.3 Location / Service-Area Pages (e.g., “Plumber in Mesa, AZ”)

  • Reuse the main LocalBusiness schema, adjusting areaServed to the specific city/region if the page is genuinely dedicated to that area
  • BreadcrumbList: Home > Service Areas > [City]
  • Do not create a duplicate LocalBusiness entity per city page unless the client has a legitimately separate branch/location with its own address — doing so for a single business (storefront or SAB) creates duplicate/conflicting entity signals. One business, one LocalBusiness entity, with areaServed covering every city it works in.

4.4 About / Contact Pages

  • LocalBusiness (or reference the same entity via @id) with full NAP (name, address/service area, phone) and hours
  • BreadcrumbList: Home > About / Home > Contact

4.5 Blog / Resource Pages (if applicable)

  • Not covered by the core toolkit above; flag to Nick if a client needs Article/BlogPosting schema and we’ll extend the SOP

5. Step-by-Step Process

  1. Intake — Collect all data from Section 2. Confirm whether the client has a public address, a service area, or (most commonly) both — this determines which fields get published, and whether areaServed needs to cover cities beyond the storefront’s own city.
  2. Choose type — Pick the correct @type per Section 3.
  3. Generate — Open  https://hub.ampv.com/schema/, fill in the relevant tab(s) for the page you’re marking up, and copy the generated JSON-LD.
  4. Place the code — Insert each JSON-LD block inside a <script type="application/ld+json"> tag in the <head> (preferred) or before </body> of the relevant page. Do not stack unrelated schema types into a single <script> tag unless using @graph (see Section 6) — keep them as separate script blocks for clarity unless a graph is intentional.
  5. Cross-check against visible content — Every fact in the schema (name, phone, hours, FAQ text, review count) must match what a visitor actually sees on that page. This is the single most common cause of Google Search Console errors and spam flags.
  6. Validate — Run every page through:Fix all errors and review all warnings before publishing.
  7. Publish — Push to staging first if the client’s workflow supports it; otherwise deploy directly and re-validate on the live URL.
  8. Log it — Note the pages updated, schema types added, and date in ClickUp.
  9. Monitor — Check Google Search Console’s “Enhancements” reports (or equivalent, e.g. “Unparsable structured data,” “Reviews snippet,” “FAQ”) 1–2 weeks after publishing and again at the next reporting cycle.

6. Technical Notes & Best Practices

  • One entity, one @id. When a business appears in multiple schema blocks on the same page (e.g., LocalBusiness and Service.provider), use @id anchors (e.g., "@id": "https://example.com/#business") and reference them instead of repeating full data, to avoid duplicate/inconsistent entity signals across a page.
  • @graph for multi-type pages. When a single page legitimately needs more than one schema type (e.g., Service + FAQPage + BreadcrumbList), combine them under one @graph array in a single script block rather than three disconnected blocks — this makes the entity relationships explicit.
  • NAP consistency. Name, Address, Phone in schema must match the site footer, Google Business Profile, and any directory listings exactly (same formatting, abbreviations, etc.).
  • Address and service area aren’t mutually exclusive. Most home service businesses have a real office/storefront and serve a much wider area — include both address and areaServed in that case. Only drop address entirely for a genuine SAB where Google Business Profile also has the address hidden; in that case use areaServed with a GeoCircle or a list of City/AdministrativeArea entities instead of a street address.
  • Don’t mark up reviews you don’t have rights to display, and don’t aggregate third-party reviews (e.g., Google reviews) into your own AggregateRating unless you have a legitimate mechanism (like a widget with a valid license/API) — for most clients, embed only reviews genuinely shown on the page.
  • Keep FAQ schema in sync with content edits. If a client’s team edits FAQ copy on the page without telling us, the schema goes stale and Google can flag it as unrepresentative. Add a reminder in the client’s editorial workflow.
  • Avoid schema spam. Don’t add types the page doesn’t substantively support (e.g., HowTo on a page with no actual steps) purely to chase rich results — Google’s spam policies explicitly cover this and it can trigger manual actions.

7. QA Checklist (complete before marking a schema task “done”)

  • Correct, most-specific@typeused for the business
  • Address and/orareaServedcorrectly reflect the client’s actual footprint (both included when the business has a storefront that also serves a wider area; address omitted only for a genuine SAB with no public address)
  • NAP matches GBP, footer, and directories exactly
  • Hours match what’s posted on GBP and the site
  • All FAQ schema text matches visible on-page text verbatim
  • All review/rating data is real, current, and visible on the page
  • Breadcrumb trail matches the actual site navigation/URL structure
  • No orphaned or duplicateLocalBusinessentities across pages (use@idreferences)
  • Passes Google Rich Results Test with zero errors
  • Passes Schema.org Validator with zero errors
  • Screenshot or note saved of validator pass for the client file
  • Change logged in client tracking sheet with date and pages affected

8. Maintenance Cadence

TriggerAction
Client rebrands, changes phone/address, or adds a locationUpdate schema same week
New service added to siteAdd corresponding Service schema at launch
FAQ content editedRe-sync FAQPage schema immediately
Quarterly account reviewRe-run Rich Results Test on top 5 pages per client
Google structured data guideline changesRe-review this SOP and update as needed (flagged in the SEO Decision Log)

9. Appendix: Field Reference

LocalBusiness (and trade subtypes)

@typenameimage@idurltelephonepriceRangeaddress (omit only for a pure SAB), geoopeningHoursSpecificationareaServed (include alongside address whenever the service area extends beyond the storefront’s city), aggregateRatingreviewsameAs (social/directory profile URLs)

Service

@type: ServiceserviceTypenamedescriptionprovider (@id reference to the business), areaServedurl

FAQPage

@type: FAQPagemainEntity (array of Question objects, each with name and an acceptedAnswer of @type: Answer with text)

BreadcrumbList

@type: BreadcrumbListitemListElement (array of ListItem objects, each with positionnameitem URL)

AggregateRating / Review

AggregateRatingratingValuereviewCount (or ratingCount), bestRatingworstRating
Reviewauthor (Person), reviewRating (ratingValue), reviewBodydatePublished


Use schema-generator.html to produce compliant JSON-LD for all five types above without hand-writing code. See that tool for field-by-field generation.