Local Business Schema Guide: Complete Structured Data Implementation
Quick Summary
- What this covers: Implement LocalBusiness schema with hours, address, reviews, and service areas. Optimize for Google Maps, local pack, and knowledge panels.
- Who it's for: site owners and SEO practitioners
- Key takeaway: Read the first section for the core framework, then use the specific tactics that match your situation.
- LocalBusiness Schema Fundamentals
- Business Type Selection
- Address and Contact Details
- Opening Hours Implementation
- Reviews and Ratings
- Service Area Configuration
- Images and Media
- Price Range and Payment
- WordPress Implementation
- Validation and Testing
- Common Mistakes
- When This Fix Isn't Your Priority
LocalBusiness schema communicates critical location data to Google, business hours, service areas, contact methods, and review aggregates, enabling rich local search features like knowledge panels, local pack prominence, and enhanced map listings. Proper structured data implementation increases local visibility by 30-50% through improved ranking signals and featured result eligibility.
LocalBusiness Schema Fundamentals
LocalBusiness schema type extends Organization, inheriting general business properties while adding location-specific fields. Google recognizes 100+ LocalBusiness subtypes (Restaurant, Store, MedicalBusiness) for specialized businesses.
Core required properties for functional implementation:
@type: "LocalBusiness" or specific subtypename: Official business nameaddress: Physical location with structured PostalAddresstelephone: Primary phone numberurl: Website homepage
Recommended properties for enhanced features:
openingHoursSpecification: Operating hoursgeo: Latitude/longitude coordinatespriceRange: Cost indicator ($, $$, $$$)image: Business photosaggregateRating: Review ratingsservesCuisine: (Restaurants) Food type
JSON-LD format injects schema via <script> tags in page <head>:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Example Coffee Shop",
"address": {
"@type": "PostalAddress",
"streetAddress": "123 Main Street",
"addressLocality": "San Francisco",
"addressRegion": "CA",
"postalCode": "94102",
"addressCountry": "US"
},
"telephone": "+1-415-555-0123",
"url": "https://example.com"
}
</script>
Business Type Selection
Specific subtypes outperform generic "LocalBusiness" by signaling exact business category:
- Restaurant: Cafes, diners, bistros
- Store: Retail shops, clothing stores
- FoodEstablishment: Bakeries, fast food, bars
- ProfessionalService: Law firms, consulting, agencies
- HomeAndConstructionBusiness: Contractors, electricians, plumbers
- MedicalBusiness: Doctors, dentists, clinics
- AutomotiveBusiness: Repair shops, dealerships
- LodgingBusiness: Hotels, B&Bs, resorts
Reference Schema.org for complete subtype list: schema.org/LocalBusiness. Choose the most specific applicable type "ItalianRestaurant" beats "Restaurant" which beats "FoodEstablishment."
Multiple locations require separate LocalBusiness entries per physical location. Multi-location businesses should implement schema on each location page, not the homepage:
<!-- Location 1 page -->
<script type="application/ld+json">
{
"@type": "LocalBusiness",
"name": "Example Coffee - Downtown",
"address": { "streetAddress": "123 Main St", "addressLocality": "San Francisco" }
}
</script>
<!-- Location 2 page -->
<script type="application/ld+json">
{
"@type": "LocalBusiness",
"name": "Example Coffee - Marina",
"address": { "streetAddress": "456 Bay St", "addressLocality": "San Francisco" }
}
</script>
Address and Contact Details
PostalAddress structure requires five components for US addresses:
"address": {
"@type": "PostalAddress",
"streetAddress": "123 Main Street Suite 200",
"addressLocality": "San Francisco",
"addressRegion": "CA",
"postalCode": "94102",
"addressCountry": "US"
}
streetAddress includes building numbers, street names, and suite/unit numbers. addressLocality is the city name. addressRegion uses two-letter state codes (CA, NY, TX). postalCode follows local formatting (ZIP for US, postal codes for other countries).
International addresses adapt components:
"address": {
"@type": "PostalAddress",
"streetAddress": "10 Downing Street",
"addressLocality": "London",
"postalCode": "SW1A 2AA",
"addressCountry": "GB"
}
Telephone formatting should include country code with plus prefix:
"telephone": "+1-415-555-0123"
Avoid letters in phone numbers, format as digits with hyphens. Multiple contact methods use telephone (primary) and contactPoint for additional:
"telephone": "+1-415-555-0123",
"contactPoint": {
"@type": "ContactPoint",
"telephone": "+1-415-555-0199",
"contactType": "customer service"
}
Geo coordinates improve map accuracy:
"geo": {
"@type": "GeoCoordinates",
"latitude": 37.7749,
"longitude": -122.4194
}
Find coordinates via Google Maps: right-click location → select coordinates (copies to clipboard). Precision to 4 decimal places suffices (±11 meters accuracy).
Opening Hours Implementation
openingHoursSpecification defines operating hours per day:
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "08:00",
"closes": "18:00"
},
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Saturday",
"opens": "09:00",
"closes": "15:00"
}
]
Time format uses 24-hour notation (08:00 for 8 AM, 18:00 for 6 PM). Group consecutive days with identical hours to reduce verbosity.
Closed days omit from openingHoursSpecification, absence signals closed. If explicitly stating closure:
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Sunday",
"opens": "00:00",
"closes": "00:00"
}
24/7 operations span midnight:
"openingHoursSpecification": {
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
"opens": "00:00",
"closes": "23:59"
}
Seasonal hours require special event markup:
"specialOpeningHoursSpecification": {
"@type": "OpeningHoursSpecification",
"opens": "00:00",
"closes": "00:00",
"validFrom": "2026-12-25",
"validThrough": "2026-12-25"
}
This indicates Christmas closure without permanently modifying standard hours.
Reviews and Ratings
aggregateRating displays star ratings in search results:
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.5",
"reviewCount": "127"
}
ratingValue represents average rating (1-5 scale). reviewCount indicates total reviews. Google validates these numbers against discoverable reviews, inflating values risks penalties.
Individual reviews add credibility with review schema:
"review": [
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "John Smith"
},
"datePublished": "2026-02-01",
"reviewRating": {
"@type": "Rating",
"ratingValue": "5",
"bestRating": "5"
},
"reviewBody": "Excellent service and great coffee. Highly recommend!"
}
]
First-party reviews (hosted on your site) require visible review content matching schema. Don't markup reviews existing only in schema. Google detects and penalizes hidden reviews.
Third-party review aggregation should pull from Google Business Profile, Yelp, or industry-specific platforms. Update aggregateRating monthly to reflect current ratings.
Service Area Configuration
Service area businesses (plumbers, contractors, delivery) serve regions without requiring customers to visit:
"@type": "HomeAndConstructionBusiness",
"name": "ABC Plumbing",
"areaServed": [
{
"@type": "City",
"name": "San Francisco"
},
{
"@type": "City",
"name": "Oakland"
},
{
"@type": "City",
"name": "Berkeley"
}
]
Radius-based service areas specify distance:
"areaServed": {
"@type": "GeoCircle",
"geoMidpoint": {
"@type": "GeoCoordinates",
"latitude": 37.7749,
"longitude": -122.4194
},
"geoRadius": "50 miles"
}
Postal code ranges define service boundaries:
"areaServed": {
"@type": "PostalCodeRangeSpecification",
"postalCodeBegin": "94102",
"postalCodeEnd": "94199",
"addressCountry": "US"
}
Virtual businesses without physical addresses use serviceArea exclusively, omitting physical address schema to avoid confusion.
Images and Media
image property displays business photos in knowledge panels:
"image": [
"https://example.com/storefront.jpg",
"https://example.com/interior.jpg",
"https://example.com/products.jpg"
]
Image requirements:
- Minimum 1200px width
- 16:9, 4:3, or 1:1 aspect ratios
- JPEG or PNG format
- Show actual business (exterior, interior, products), not stock photos
Logo specification differentiates from general images:
"logo": "https://example.com/logo.png"
Logos should be square (1:1 ratio), minimum 112px, representing the official business mark.
Video content via VideoObject enhances engagement:
"video": {
"@type": "VideoObject",
"name": "Tour of Example Coffee Shop",
"description": "Virtual tour of our downtown location",
"thumbnailUrl": "https://example.com/video-thumb.jpg",
"uploadDate": "2026-02-01",
"contentUrl": "https://example.com/videos/tour.mp4"
}
Price Range and Payment
priceRange indicates cost level:
"priceRange": "$$"
Use 1-4 dollar signs: $ (inexpensive), $$ (moderate), $$$ (expensive), $$$$ (expensive). This appears in Google Maps and search results helping users filter by budget.
Payment methods via acceptedPaymentMethod:
"paymentAccepted": "Cash, Credit Card, Debit Card, Apple Pay"
Or structured format:
"acceptedPaymentMethod": [
"http://purl.org/goodrelations/v1#Cash",
"http://purl.org/goodrelations/v1#ByBankTransferInAdvance"
]
Menu links (restaurants) provide direct access:
"hasMenu": "https://example.com/menu"
Or structured menu schema:
"hasMenu": {
"@type": "Menu",
"url": "https://example.com/menu"
}
WordPress Implementation
Schema plugins automate LocalBusiness markup:
- Rank Math: Schema tab → Local Business → Fill form fields → Auto-generates JSON-LD
- Yoast SEO Local: Dedicated local business extension ($69/year)
- Schema Pro: Visual schema builder supporting LocalBusiness type
- All in One Schema.org: Free plugin with LocalBusiness templates
Manual implementation via theme functions:
function add_local_business_schema() {
$schema = [
'@context' => 'https://schema.org',
'@type' => 'LocalBusiness',
'name' => get_bloginfo('name'),
'address' => [
'@type' => 'PostalAddress',
'streetAddress' => '123 Main St',
'addressLocality' => 'San Francisco',
'addressRegion' => 'CA',
'postalCode' => '94102',
'addressCountry' => 'US'
],
'telephone' => '+1-415-555-0123',
'url' => home_url()
];
echo '<script type="application/ld+json">' . json_encode($schema) . '</script>';
}
add_action('wp_head', 'add_local_business_schema');
Custom fields enable schema editing via WordPress admin:
// Add custom fields for hours, ratings, etc. using ACF or CMB2
// Pull field values into schema generation function
$hours = get_field('business_hours');
$rating = get_field('average_rating');
Validation and Testing
Google's Rich Results Test validates schema syntax:
- Visit search.google.com/test/rich-results
- Enter URL or paste schema code
- Review errors and warnings
- Fix issues highlighted in red
- Retest until validation passes
Schema Markup Validator (schema.org validator) tests against official specifications:
- Visit validator.schema.org
- Paste schema code
- Check for specification compliance
- Address any warnings
Google Search Console monitors schema performance:
- Go to Enhancements → Unparsable structured data
- Review errors preventing rich result eligibility
- Fix flagged issues
- Request re-indexing via URL Inspection
Mobile-Friendly Test ensures schema functions on mobile:
- Visit search.google.com/test/mobile-friendly
- Enter URL
- Verify schema appears in rendered HTML
- Check mobile display of structured data
Preview tools show how schema displays:
- Google SERP Preview: See potential search result appearance
- Google Maps Preview: Check how business listing appears
- Facebook Open Graph Debugger: Verify social sharing (if using OpenGraph alongside schema)
Common Mistakes
Mismatched NAP (Name, Address, Phone) between schema and visible page content confuses Google. Schema must exactly match displayed information, no abbreviations, formatting differences, or variations.
Missing required properties cause validation failures. Every LocalBusiness requires at minimum: @type, name, address, and telephone. Omitting any prevents rich results.
Incorrect business type reduces relevance. Using generic "LocalBusiness" instead of specific subtype (Restaurant, MedicalBusiness) misses category-specific features.
Fake or inflated reviews in aggregateRating trigger manual penalties. Only markup genuinely collected reviews with verifiable sources.
Multiple schemas for same business on one page create conflicting data. Use one comprehensive LocalBusiness schema per page, not multiple partial implementations.
Take Action: Map Your Traffic Portfolio
Frameworks only pay off when they run against your numbers. The Find setup maps every channel you operate, what each costs, what each converts, and where the portfolio is concentrated, so decisions like the ones above start from your data instead of hypotheticals.
Key Recap
- LocalBusiness Schema Fundamentals:
© 2026 Polytraffic. Part of the Scale With Search network.