feat: enhance SurfSense with new skills, blog section, and improve SEO metadata
Some checks failed
Build and Push Docker Images / tag_release (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-24.04-arm, linux/arm64, arm64) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-latest, linux/amd64, amd64) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_web, ./surfsense_web/Dockerfile, web, surfsense-web, ubuntu-24.04-arm, linux/arm64, arm64) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_web, ./surfsense_web/Dockerfile, web, surfsense-web, ubuntu-latest, linux/amd64, amd64) (push) Has been cancelled
Build and Push Docker Images / create_manifest (backend, surfsense-backend) (push) Has been cancelled
Build and Push Docker Images / create_manifest (web, surfsense-web) (push) Has been cancelled

- Added multiple new skills to skills-lock.json from the repository `aaron-he-zhu/seo-geo-claude-skills`.
- Introduced `fuzzy-search` dependency in package.json for improved search functionality.
- Updated pnpm-lock.yaml to include the new `fuzzy-search` package.
- Enhanced SEO metadata across various pages, including canonical links and descriptions for better search visibility.
- Improved layout and structure of several components, including the homepage and changelog, to enhance user experience.
This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-04-11 23:38:12 -07:00
parent 61b3f0d7e3
commit 7ea840dbb2
120 changed files with 25729 additions and 352 deletions

View file

@ -0,0 +1,65 @@
# Schema Type Decision Tree
Guidelines for selecting the right schema types based on content, industry, and implementation priority.
---
## When to Use Which Schema
| Your Content | Primary Schema | Add If Applicable | Rich Result Eligibility |
|-------------|---------------|-------------------|----------------------|
| Blog post / article | Article | FAQ, HowTo, Speakable | Article carousel, FAQ rich result |
| Product page | Product | Review, Offer, AggregateRating | Product snippet with price/rating |
| Service page | Service | FAQ, LocalBusiness | Service snippet |
| How-to guide | HowTo | Article, FAQ | How-to rich result with steps |
| FAQ page | FAQPage | Article | FAQ accordion in SERP |
| Recipe | Recipe | Video, AggregateRating | Recipe carousel |
| Event | Event | Offer, Organization | Event snippet with date/location |
| Video | VideoObject | Article | Video carousel, key moments |
| Local business | LocalBusiness | Review, OpeningHoursSpecification | Local pack, knowledge panel |
| Person/author | Person | Organization | Knowledge panel |
| Organization | Organization | ContactPoint, Logo | Knowledge panel |
| Course | Course | Organization | Course rich result |
| Job posting | JobPosting | Organization | Google for Jobs listing |
| Breadcrumb | BreadcrumbList | (Always add alongside other schema) | Breadcrumb trail in SERP |
| Software/App | SoftwareApplication | Review, Offer | App snippet |
---
## Industry-Specific Schema Recommendations
| Industry | Essential Schema | High-Value Additions |
|----------|-----------------|---------------------|
| E-commerce | Product, BreadcrumbList, Organization | AggregateRating, FAQ, Review |
| SaaS | SoftwareApplication, FAQPage, Organization | HowTo, VideoObject, Review |
| Local Services | LocalBusiness, Service | FAQ, Review, Event |
| Publishing/Media | Article, Person, Organization | FAQ, Speakable, VideoObject |
| Education | Course, Organization | FAQ, HowTo, Event |
| Healthcare | MedicalWebPage, Organization | FAQ, Physician, MedicalClinic |
| Real Estate | RealEstateListing, Organization | LocalBusiness, FAQ |
| Restaurants | Restaurant, Menu | Review, Event, FAQ |
---
## Schema Implementation Priority
| Priority | Schema Types | Why |
|----------|-------------|-----|
| P0 -- Always | Organization, BreadcrumbList, WebSite (SearchAction) | Foundation for all sites |
| P1 -- Content | Article, FAQPage, HowTo | Direct rich result eligibility |
| P2 -- Commercial | Product, Review, AggregateRating, Offer | Revenue-impacting rich results |
| P3 -- Authority | Person, SameAs, Speakable | E-E-A-T signals, AI citation |
| P4 -- Specialized | Industry-specific types | Niche rich results |
---
## Schema Validation Quick Reference
| Issue | Impact | Fix |
|-------|--------|-----|
| Missing required property | Schema ignored by Google | Add all required fields (check schema.org) |
| Invalid date format | Warning, may lose rich result | Use ISO 8601: "2026-02-11" |
| Incorrect @type | Schema misinterpreted | Match @type exactly to schema.org |
| Self-referencing sameAs | Warning | sameAs should link to EXTERNAL profiles |
| Missing image for Article | Loses article rich result | Add image property with valid URL |
| Review without itemReviewed | Review not connected | Nest review inside Product/Service/etc. |

View file

@ -0,0 +1,631 @@
# Schema.org JSON-LD Templates
Complete, copy-ready structured data templates for all major schema types. Customize the bracketed values to match your content.
## FAQPage Schema
For pages with frequently asked questions. Minimum 2 Q&A pairs required.
```json
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "[Question text - exactly as shown on page]",
"acceptedAnswer": {
"@type": "Answer",
"text": "[Complete answer text - must match visible content]"
}
},
{
"@type": "Question",
"name": "[Question 2]",
"acceptedAnswer": {
"@type": "Answer",
"text": "[Answer 2]"
}
},
{
"@type": "Question",
"name": "[Question 3]",
"acceptedAnswer": {
"@type": "Answer",
"text": "[Answer 3]"
}
}
]
}
```
**Requirements**: Questions must be complete questions, answers must be comprehensive, content must match visible page content.
---
## HowTo Schema
For step-by-step instructional content.
```json
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "[How-to title - what will users learn]",
"description": "[Brief description of what this tutorial teaches]",
"image": {
"@type": "ImageObject",
"url": "[Main image URL]",
"height": "[height in pixels]",
"width": "[width in pixels]"
},
"totalTime": "PT[X]H[Y]M",
"estimatedCost": {
"@type": "MonetaryAmount",
"currency": "USD",
"value": "[estimated cost or 0]"
},
"supply": [
{
"@type": "HowToSupply",
"name": "[Supply item 1]"
},
{
"@type": "HowToSupply",
"name": "[Supply item 2]"
}
],
"tool": [
{
"@type": "HowToTool",
"name": "[Tool 1]"
},
{
"@type": "HowToTool",
"name": "[Tool 2]"
}
],
"step": [
{
"@type": "HowToStep",
"position": 1,
"name": "[Step 1 title]",
"text": "[Step 1 detailed instructions]",
"url": "[Page URL]#step1",
"image": "[Step 1 image URL - optional]"
},
{
"@type": "HowToStep",
"position": 2,
"name": "[Step 2 title]",
"text": "[Step 2 detailed instructions]",
"url": "[Page URL]#step2",
"image": "[Step 2 image URL - optional]"
},
{
"@type": "HowToStep",
"position": 3,
"name": "[Step 3 title]",
"text": "[Step 3 detailed instructions]",
"url": "[Page URL]#step3",
"image": "[Step 3 image URL - optional]"
}
]
}
```
**Time format**: PT[X]H[Y]M where X = hours, Y = minutes. Example: PT1H30M = 1 hour 30 minutes.
---
## Article / BlogPosting / NewsArticle Schema
For blog posts, articles, and news content.
```json
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "[Article title - max 110 characters for best display]",
"description": "[Article summary or excerpt]",
"image": [
"[Featured image URL - 1200px wide recommended]",
"[Alternative image URL - 4:3 ratio]",
"[Alternative image URL - 16:9 ratio]"
],
"datePublished": "[ISO 8601 date: 2024-01-15T08:00:00+00:00]",
"dateModified": "[ISO 8601 date - same as published if never modified]",
"author": {
"@type": "Person",
"name": "[Author Full Name]",
"url": "[Author profile URL]",
"jobTitle": "[Author job title - optional]"
},
"publisher": {
"@type": "Organization",
"name": "[Publisher/Company Name]",
"logo": {
"@type": "ImageObject",
"url": "[Publisher logo URL - max 600px wide, 60px high]",
"width": "[width]",
"height": "[height]"
}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "[Canonical URL of this article]"
},
"articleBody": "[Full article text - optional but recommended]",
"wordCount": "[word count - optional]"
}
```
**Type variants**: Use `Article` for general articles, `BlogPosting` for blog posts, `NewsArticle` for news content, `TechArticle` for technical documentation.
---
## Product Schema
For e-commerce product pages.
```json
{
"@context": "https://schema.org",
"@type": "Product",
"name": "[Product Name]",
"image": [
"[Product image URL 1]",
"[Product image URL 2]",
"[Product image URL 3]"
],
"description": "[Product description]",
"sku": "[SKU code]",
"mpn": "[Manufacturer Part Number - optional]",
"brand": {
"@type": "Brand",
"name": "[Brand Name]"
},
"offers": {
"@type": "Offer",
"url": "[Product page URL]",
"priceCurrency": "USD",
"price": "[Price as number: 29.99]",
"priceValidUntil": "[Date price is valid until: 2024-12-31]",
"availability": "https://schema.org/InStock",
"seller": {
"@type": "Organization",
"name": "[Seller/Store Name]"
},
"shippingDetails": {
"@type": "OfferShippingDetails",
"shippingRate": {
"@type": "MonetaryAmount",
"value": "[shipping cost]",
"currency": "USD"
},
"shippingDestination": {
"@type": "DefinedRegion",
"addressCountry": "US"
}
}
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "[4.5]",
"reviewCount": "[89]",
"bestRating": "5",
"worstRating": "1"
},
"review": [
{
"@type": "Review",
"reviewRating": {
"@type": "Rating",
"ratingValue": "[5]",
"bestRating": "5"
},
"author": {
"@type": "Person",
"name": "[Reviewer Name]"
},
"reviewBody": "[Review text]",
"datePublished": "[Review date: 2024-01-15]"
}
]
}
```
**Availability options**: `InStock`, `OutOfStock`, `PreOrder`, `Discontinued`, `LimitedAvailability`, `OnlineOnly`, `InStoreOnly`, `SoldOut`
---
## LocalBusiness Schema
For local business pages with physical locations.
```json
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "[Business Name]",
"image": "[Business image or logo URL]",
"@id": "[Business page URL]",
"url": "[Website URL]",
"telephone": "[Phone number: +1-555-555-5555]",
"priceRange": "[$$$ or price range like $10-$50]",
"address": {
"@type": "PostalAddress",
"streetAddress": "[Street address]",
"addressLocality": "[City]",
"addressRegion": "[State/Province]",
"postalCode": "[ZIP/Postal code]",
"addressCountry": "US"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": "[latitude as number: 40.7128]",
"longitude": "[longitude as number: -74.0060]"
},
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "09:00",
"closes": "17:00"
},
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Saturday",
"opens": "10:00",
"closes": "15:00"
}
],
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "[4.5]",
"reviewCount": "[123]"
},
"servesCuisine": "[Cuisine type - for restaurants only]"
}
```
**Type variants**: Use more specific types when applicable: `Restaurant`, `Store`, `AutoRepair`, `HealthAndBeautyBusiness`, `LegalService`, etc.
---
## Organization Schema
For brand/company homepage.
```json
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "[Organization Name]",
"url": "[Website URL]",
"logo": "[Logo URL - recommended 112x112px or larger]",
"description": "[Company description]",
"sameAs": [
"[Facebook URL]",
"[Twitter URL]",
"[LinkedIn URL]",
"[Instagram URL]",
"[YouTube URL]"
],
"contactPoint": {
"@type": "ContactPoint",
"telephone": "[Phone number]",
"contactType": "customer service",
"email": "[Email address]",
"availableLanguage": ["English", "Spanish"],
"areaServed": "US"
},
"founder": {
"@type": "Person",
"name": "[Founder name - optional]"
},
"foundingDate": "[YYYY-MM-DD - optional]",
"address": {
"@type": "PostalAddress",
"streetAddress": "[Street address]",
"addressLocality": "[City]",
"addressRegion": "[State]",
"postalCode": "[ZIP]",
"addressCountry": "US"
}
}
```
---
## BreadcrumbList Schema
For navigation breadcrumbs.
```json
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "[Homepage URL]"
},
{
"@type": "ListItem",
"position": 2,
"name": "[Category Name]",
"item": "[Category URL]"
},
{
"@type": "ListItem",
"position": 3,
"name": "[Subcategory Name]",
"item": "[Subcategory URL]"
},
{
"@type": "ListItem",
"position": 4,
"name": "[Current Page Name]",
"item": "[Current Page URL]"
}
]
}
```
**Important**: Position numbers must be sequential starting from 1. Last item should be the current page.
---
## VideoObject Schema
For video content.
```json
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "[Video title]",
"description": "[Video description]",
"thumbnailUrl": "[Video thumbnail URL - minimum 160x90px]",
"uploadDate": "[ISO 8601 date: 2024-01-15T08:00:00+00:00]",
"duration": "PT[X]M[Y]S",
"contentUrl": "[Video file URL]",
"embedUrl": "[Video embed URL]",
"interactionStatistic": {
"@type": "InteractionCounter",
"interactionType": { "@type": "WatchAction" },
"userInteractionCount": "[view count]"
}
}
```
**Duration format**: PT[X]M[Y]S where X = minutes, Y = seconds. Example: PT5M30S = 5 minutes 30 seconds.
---
## Event Schema
For events, conferences, concerts, etc.
```json
{
"@context": "https://schema.org",
"@type": "Event",
"name": "[Event Name]",
"description": "[Event description]",
"image": "[Event image URL]",
"startDate": "[ISO 8601 date: 2024-06-15T19:00:00-05:00]",
"endDate": "[ISO 8601 date: 2024-06-15T22:00:00-05:00]",
"eventStatus": "https://schema.org/EventScheduled",
"eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode",
"location": {
"@type": "Place",
"name": "[Venue Name]",
"address": {
"@type": "PostalAddress",
"streetAddress": "[Street address]",
"addressLocality": "[City]",
"addressRegion": "[State]",
"postalCode": "[ZIP]",
"addressCountry": "US"
}
},
"offers": {
"@type": "Offer",
"url": "[Ticket purchase URL]",
"price": "[ticket price]",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"validFrom": "[Sale start date]"
},
"organizer": {
"@type": "Organization",
"name": "[Organizer name]",
"url": "[Organizer website]"
}
}
```
**Event status options**: `EventScheduled`, `EventCancelled`, `EventPostponed`, `EventRescheduled`, `EventMovedOnline`
**Attendance mode**: `OfflineEventAttendanceMode`, `OnlineEventAttendanceMode`, `MixedEventAttendanceMode`
---
## Course Schema
For online courses and educational content.
```json
{
"@context": "https://schema.org",
"@type": "Course",
"name": "[Course Name]",
"description": "[Course description]",
"provider": {
"@type": "Organization",
"name": "[Provider name]",
"sameAs": "[Provider URL]"
},
"offers": {
"@type": "Offer",
"category": "Paid",
"price": "[price]",
"priceCurrency": "USD"
},
"hasCourseInstance": {
"@type": "CourseInstance",
"courseMode": "online",
"courseWorkload": "PT[X]H",
"instructor": {
"@type": "Person",
"name": "[Instructor name]"
}
}
}
```
---
## Recipe Schema
For cooking recipes.
```json
{
"@context": "https://schema.org",
"@type": "Recipe",
"name": "[Recipe name]",
"image": "[Recipe image URL]",
"author": {
"@type": "Person",
"name": "[Author name]"
},
"datePublished": "[ISO 8601 date]",
"description": "[Recipe description]",
"prepTime": "PT[X]M",
"cookTime": "PT[X]M",
"totalTime": "PT[X]M",
"recipeYield": "[Servings: e.g., '4 servings']",
"recipeCategory": "[Category: e.g., 'Dinner']",
"recipeCuisine": "[Cuisine: e.g., 'Italian']",
"keywords": "[comma, separated, keywords]",
"nutrition": {
"@type": "NutritionInformation",
"calories": "[calories per serving]"
},
"recipeIngredient": [
"[Ingredient 1 with quantity]",
"[Ingredient 2 with quantity]",
"[Ingredient 3 with quantity]"
],
"recipeInstructions": [
{
"@type": "HowToStep",
"text": "[Step 1 instructions]"
},
{
"@type": "HowToStep",
"text": "[Step 2 instructions]"
}
],
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "[4.5]",
"reviewCount": "[number of reviews]"
}
}
```
---
## SoftwareApplication Schema
For software, apps, and tools.
```json
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "[Software name]",
"operatingSystem": "[Windows, macOS, iOS, Android, Web]",
"applicationCategory": "BusinessApplication",
"offers": {
"@type": "Offer",
"price": "[price or 0 for free]",
"priceCurrency": "USD"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "[4.5]",
"reviewCount": "[number of reviews]"
},
"screenshot": "[Screenshot URL - optional]",
"softwareVersion": "[version number]",
"fileSize": "[file size with units: e.g., '50MB']",
"datePublished": "[Release date]",
"downloadUrl": "[Download URL - optional]"
}
```
---
## Multiple Schema Types (Combined Array)
To include multiple schema types on one page, wrap them in an array:
```html
<script type="application/ld+json">
[
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "[Article title]",
"author": {
"@type": "Person",
"name": "[Author]"
}
},
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "[Question]",
"acceptedAnswer": {
"@type": "Answer",
"text": "[Answer]"
}
}
]
},
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "[URL]"
}
]
}
]
</script>
```
---
## Implementation Notes
- Always validate schema at https://validator.schema.org/ and https://search.google.com/test/rich-results
- Remove bracketed placeholders and replace with actual content
- Use absolute URLs, not relative paths
- Dates must be in ISO 8601 format
- Schema must match visible page content (Google policy requirement)
- No trailing commas in JSON (invalid syntax)

View file

@ -0,0 +1,444 @@
# Schema Markup Validation Guide
Complete reference for validating, testing, and troubleshooting structured data.
## Validation Tools
### Google Rich Results Test
- **URL**: https://search.google.com/test/rich-results
- **Purpose**: Check if your schema is eligible for Google rich results
- **Tests**: Live URL or code snippet
- **Output**: Errors, warnings, eligible rich result types
### Schema.org Validator
- **URL**: https://validator.schema.org/
- **Purpose**: Validate against official Schema.org specification
- **Tests**: URL, code snippet, or microdata
- **Output**: Technical validation errors
### Google Search Console
- **Location**: Search Console → Enhancements section
- **Purpose**: Monitor rich results performance and errors at scale
- **Reports**: Rich results status, coverage, issues over time
---
## Common JSON-LD Syntax Errors
### Trailing Commas
**Error**: Invalid JSON syntax
```json
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Title", ← Trailing comma here
}
```
**Fix**: Remove the comma after the last property
```json
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Title"
}
```
### Missing Required Quotes
**Error**: Property names must be quoted
```json
{
@context: "https://schema.org"
}
```
**Fix**: Quote all property names
```json
{
"@context": "https://schema.org"
}
```
### Incorrect Date Format
**Error**: Invalid date format
```json
{
"datePublished": "01/15/2024"
}
```
**Fix**: Use ISO 8601 format
```json
{
"datePublished": "2024-01-15T08:00:00+00:00"
}
```
### Relative URLs Instead of Absolute
**Error**: Relative URLs are not allowed
```json
{
"image": "/images/photo.jpg"
}
```
**Fix**: Use absolute URLs
```json
{
"image": "https://example.com/images/photo.jpg"
}
```
### Incorrect Array Syntax
**Error**: Multiple values not in array
```json
{
"image": "url1.jpg", "url2.jpg"
}
```
**Fix**: Use array brackets for multiple values
```json
{
"image": ["url1.jpg", "url2.jpg"]
}
```
---
## Required vs Recommended Properties
### FAQPage Schema
| Property | Status | Notes |
|----------|--------|-------|
| @type | Required | Must be "FAQPage" |
| mainEntity | Required | Array of Question objects |
| Question.name | Required | The question text |
| Answer.text | Required | The answer text |
**Minimum**: 2 Q&A pairs
### HowTo Schema
| Property | Status | Notes |
|----------|--------|-------|
| @type | Required | Must be "HowTo" |
| name | Required | Title of the how-to |
| step | Required | Array of HowToStep objects |
| step.text | Required | Step instructions |
| image | Recommended | Improves visibility |
| totalTime | Recommended | Shows duration in results |
| supply | Recommended | Lists materials needed |
| tool | Recommended | Lists tools needed |
**Minimum**: 2 steps with text
### Article Schema
| Property | Status | Notes |
|----------|--------|-------|
| @type | Required | Article/BlogPosting/NewsArticle |
| headline | Required | Max 110 characters |
| image | Required | Minimum 1200px wide |
| datePublished | Required | ISO 8601 format |
| author | Required | Person or Organization |
| publisher | Required | Organization with logo |
| publisher.logo | Required | Max 600px wide, 60px high |
| dateModified | Recommended | Update when content changes |
| description | Recommended | Improves display |
### Product Schema
| Property | Status | Notes |
|----------|--------|-------|
| @type | Required | Must be "Product" |
| name | Required | Product name |
| image | Required | Product images |
| description | Recommended | Product description |
| offers | Recommended | Required for price display |
| offers.price | Recommended | Required for price display |
| offers.priceCurrency | Recommended | Required for price display |
| offers.availability | Recommended | Stock status |
| aggregateRating | Recommended | Required for star ratings |
| review | Recommended | Individual reviews |
| sku | Recommended | Product identifier |
| brand | Recommended | Brand information |
### LocalBusiness Schema
| Property | Status | Notes |
|----------|--------|-------|
| @type | Required | LocalBusiness or subtype |
| name | Required | Business name |
| address | Required | PostalAddress object |
| address.streetAddress | Required | Street address |
| address.addressLocality | Required | City |
| address.addressRegion | Required | State/province |
| address.postalCode | Required | ZIP/postal code |
| address.addressCountry | Required | Country code |
| geo | Recommended | Latitude/longitude |
| telephone | Recommended | Phone number |
| openingHoursSpecification | Recommended | Business hours |
| priceRange | Recommended | Price range indicator |
| aggregateRating | Recommended | Customer ratings |
### Organization Schema
| Property | Status | Notes |
|----------|--------|-------|
| @type | Required | Must be "Organization" |
| name | Required | Organization name |
| url | Required | Website URL |
| logo | Recommended | Brand logo |
| sameAs | Recommended | Social media profiles |
| contactPoint | Recommended | Contact information |
---
## Google Rich Result Eligibility Requirements
### FAQ Rich Results
**Eligibility checklist**:
- [ ] Minimum 2 Q&A pairs
- [ ] Questions are actual questions (contain "?")
- [ ] Answers are complete and comprehensive
- [ ] Content matches visible page content exactly
- [ ] Not a forum or Q&A page where users can submit answers
- [ ] Not advertising or promotional in nature
- [ ] Not for medical, legal, or financial advice without proper E-E-A-T
**Ineligible content**:
- Medical advice without credentials
- Legal advice
- Product/service comparisons that are promotional
- User-generated Q&A (use QAPage instead)
### How-To Rich Results
**Eligibility checklist**:
- [ ] Minimum 2 steps with clear instructions
- [ ] Complete process from start to finish
- [ ] Each step has meaningful text (not just a title)
- [ ] Not advertising or promotional
- [ ] Not harmful or dangerous content
- [ ] Steps are actionable and practical
**Ineligible content**:
- Single-step processes
- Recipes (use Recipe schema instead)
- Promotional tutorials
### Product Rich Results
**For price display**:
- [ ] Valid Product schema
- [ ] `offers` with `price` property
- [ ] `priceCurrency` specified
- [ ] `availability` status
**For review stars**:
- [ ] Valid `aggregateRating` OR individual `review`
- [ ] Minimum 1 review for individual review display
- [ ] Honest, unbiased reviews (not paid/incentivized)
**For product markup**:
- [ ] `name` property present
- [ ] At least one `image`
- [ ] Valid product type (not person, organization, etc.)
### Article Rich Results
**Eligibility checklist**:
- [ ] Valid Article/BlogPosting/NewsArticle schema
- [ ] High-quality, original content
- [ ] Proper `publisher` with valid logo
- [ ] Valid `author` information
- [ ] Images meet size requirements (1200px wide)
- [ ] Not short-form content (minimum ~300 words)
---
## Testing Workflow
### Initial Implementation
1. **Add schema to development/staging environment**
2. **Validate syntax at validator.schema.org**
- Paste code or test URL
- Fix all errors before proceeding
3. **Test at Google Rich Results Test**
- Check for Google-specific issues
- Verify eligible rich result types
4. **Visual inspection**
- View page source to confirm schema is present
- Check JSON formatting in browser
### Pre-Launch Testing
1. **Test on staging URL with Rich Results Test**
2. **Verify all required properties present**
3. **Confirm content matches visible page content**
4. **Check for policy violations**
5. **Test multiple schema types if combining**
6. **Validate images are accessible and meet size requirements**
### Post-Launch Monitoring
1. **Submit sitemap to Google Search Console**
2. **Monitor Enhancements reports**
- Check for validation errors
- Watch for policy violations
- Track rich result impressions
3. **Re-test pages if content changes**
4. **Update `dateModified` when updating content**
5. **Fix errors within 30 days to avoid rich result removal**
---
## Common Policy Violations
### Content Mismatch
**Violation**: Schema content doesn't match visible page content
**Example**: FAQ schema includes Q&A pairs not visible on page
**Fix**: Ensure all structured data reflects actual page content exactly
### Deceptive Content
**Violation**: Schema contains misleading information
**Example**: Product reviews that are fake or incentivized
**Fix**: Only include genuine, verifiable information
### Spammy Markup
**Violation**: Excessive or irrelevant schema
**Example**: Adding Product schema to every blog post
**Fix**: Only use schema types relevant to page content
### Hidden Content
**Violation**: Schema references content hidden from users
**Example**: FAQ answers only in schema, not visible on page
**Fix**: Make all schema content visible to users
### Promotional Content in FAQ
**Violation**: Using FAQ schema for promotional purposes
**Example**: Questions like "Why is [Brand] the best?"
**Fix**: Use neutral, informational questions
---
## Debugging Common Issues
### Schema Not Appearing in Rich Results Test
**Possible causes**:
- JSON syntax error (validate at validator.schema.org)
- Schema in incorrect location (should be in `<head>` or `<body>`)
- Script tag missing `type="application/ld+json"`
- Content served dynamically after page load (bot can't see it)
**Debug steps**:
1. View page source (not inspect element)
2. Search for `"@type"`
3. Copy JSON to validator.schema.org
4. Fix syntax errors
### Rich Results Not Showing in Search
**Possible causes**:
- Schema is new (can take days/weeks to appear)
- Page not indexed by Google
- Schema has errors in Search Console
- Content doesn't meet quality guidelines
- Competition for rich results is high
**Debug steps**:
1. Check Search Console → Enhancements
2. Use URL Inspection tool to request indexing
3. Verify schema passes Rich Results Test
4. Check for manual actions
### Warnings vs Errors
**Errors** (must fix):
- Invalid syntax
- Missing required properties
- Invalid property values
- Schema type doesn't exist
**Warnings** (should fix when possible):
- Missing recommended properties
- Suboptimal property values
- Non-standard extensions
- Property not recognized for this type
---
## Schema Maintenance Checklist
### Monthly
- [ ] Check Search Console for new errors
- [ ] Verify rich results are still appearing
- [ ] Update `dateModified` on changed content
### Quarterly
- [ ] Audit all schema implementations
- [ ] Test key pages with Rich Results Test
- [ ] Update any outdated information (prices, dates, etc.)
- [ ] Check for new schema types relevant to your content
### After Content Changes
- [ ] Update schema to match new content
- [ ] Update `dateModified` timestamp
- [ ] Re-validate with Rich Results Test
- [ ] Request re-indexing in Search Console if major changes
### After Site Migration
- [ ] Verify schema preserved on new URLs
- [ ] Update all absolute URLs in schema
- [ ] Submit new sitemap
- [ ] Monitor for errors in new domain's Search Console
---
## Quick Reference: Error Messages and Fixes
| Error Message | Cause | Fix |
|---------------|-------|-----|
| "Missing required field" | Required property not included | Add the required property |
| "Invalid date format" | Date not in ISO 8601 | Use format: 2024-01-15T08:00:00+00:00 |
| "URL is not absolute" | Relative URL used | Add full URL with https:// |
| "Unexpected token" | JSON syntax error | Check for missing quotes, brackets, commas |
| "This markup is not eligible for rich results" | Schema type or content doesn't qualify | Review eligibility requirements |
| "Image too small" | Image doesn't meet size requirements | Use image at least 1200px wide |
| "The attribute price is required" | Product missing price | Add offers.price property |
| "Logo must be 600x60 or smaller" | Publisher logo too large | Resize logo to meet requirements |
---
## Resources
- **Schema.org Documentation**: https://schema.org/
- **Google Search Central**: https://developers.google.com/search/docs/appearance/structured-data
- **Rich Results Test**: https://search.google.com/test/rich-results
- **Schema Validator**: https://validator.schema.org/
- **JSON-LD Playground**: https://json-ld.org/playground/