@softspark/ai-toolkit 2.4.1 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +32 -19
- package/CHANGELOG.md +23 -0
- package/README.md +11 -11
- package/app/.claude-plugin/plugin.json +1 -1
- package/app/agents/code-reviewer.md +6 -7
- package/app/agents/frontend-specialist.md +33 -2
- package/app/agents/seo-specialist.md +1 -1
- package/app/personas/frontend-lead.md +48 -5
- package/app/skills/a11y-validate/SKILL.md +377 -0
- package/app/skills/a11y-validate/reference/aria-patterns.md +259 -0
- package/app/skills/a11y-validate/reference/eaa-compliance.md +252 -0
- package/app/skills/a11y-validate/reference/mobile-eaa.md +329 -0
- package/app/skills/a11y-validate/reference/wcag-2-1-aa.md +285 -0
- package/app/skills/a11y-validate/reference/wcag-2-2-aa.md +221 -0
- package/app/skills/a11y-validate/scripts/a11y-scanner.py +639 -0
- package/app/skills/clean-code/reference/python.md +3 -3
- package/app/skills/design-engineering/SKILL.md +2 -5
- package/app/skills/review/SKILL.md +30 -6
- package/app/skills/seo-validate/SKILL.md +460 -0
- package/app/skills/seo-validate/reference/core-web-vitals.md +445 -0
- package/app/skills/seo-validate/reference/geo-aeo-patterns.md +259 -0
- package/app/skills/seo-validate/reference/geo-guidelines.md +248 -0
- package/app/skills/seo-validate/reference/schema-types.md +465 -0
- package/app/skills/seo-validate/reference/spa-ssg-patterns.md +351 -0
- package/app/skills/seo-validate/reference/w3c-guidelines.md +289 -0
- package/app/skills/seo-validate/scripts/seo-scanner.py +549 -0
- package/bin/ai-toolkit.js +4 -4
- package/kb/reference/architecture-overview.md +1 -1
- package/kb/reference/comparison.md +1 -1
- package/kb/reference/skills-catalog.md +3 -1
- package/llms-full.txt +10 -6
- package/manifest.json +3 -3
- package/package.json +2 -2
- package/scripts/config_cli.py +4 -10
- package/scripts/doctor.py +3 -3
- package/scripts/install_steps/ai_tools.py +1 -1
- package/scripts/plugin.py +1 -1
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# GEO — Generative Engine Optimization
|
|
2
|
+
|
|
3
|
+
Reference for `seo-validate` Category 6. Structuring content so AI answer engines (ChatGPT, Perplexity, Google AI Overviews, Bing Copilot, Claude) can extract, cite, and quote it accurately.
|
|
4
|
+
|
|
5
|
+
GEO is emerging practice, not a ranking algorithm with known penalties. **All findings in Category 6 are severity `INFO`** — guidance, not enforcement.
|
|
6
|
+
|
|
7
|
+
## Core Principles
|
|
8
|
+
|
|
9
|
+
1. **Structure over prose.** LLMs extract facts from structured blocks (headings, lists, tables, Q&A, schema) much better than from long paragraphs.
|
|
10
|
+
2. **Be citable.** Provide explicit sources, authors, dates, and facts that can be quoted verbatim.
|
|
11
|
+
3. **Answer the question.** Lead with the answer, then elaborate. "Inverted pyramid" journalism works for LLMs too.
|
|
12
|
+
4. **Semantic HTML over div soup.** AI parsers rely on semantic structure just like screen readers.
|
|
13
|
+
5. **Don't hide content behind JS.** Crawler-level LLM ingestion sees initial DOM; hidden tabs/accordions lose their content in extraction.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Content Structure Patterns
|
|
18
|
+
|
|
19
|
+
### Lead with the answer
|
|
20
|
+
|
|
21
|
+
LLMs often extract the first 1–2 sentences after a heading as the "answer" to the question that heading implies.
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<!-- Good -->
|
|
25
|
+
<h2>How long does shipping take?</h2>
|
|
26
|
+
<p>Standard shipping takes 3–5 business days in the US and 7–14 days internationally. Express options are 1–2 and 3–7 days respectively.</p>
|
|
27
|
+
<p>Orders placed before 2pm ET ship same-day. Delivery dates are confirmed at checkout based on your address.</p>
|
|
28
|
+
|
|
29
|
+
<!-- Bad (LLM extracts "we care about fast delivery" as the "answer") -->
|
|
30
|
+
<h2>How long does shipping take?</h2>
|
|
31
|
+
<p>At ExampleCo we care deeply about fast delivery, which is why we've invested in our logistics network...</p>
|
|
32
|
+
<p>(Buried eventually: 3–5 business days standard.)</p>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Explicit Q&A blocks
|
|
36
|
+
|
|
37
|
+
Q&A structure is the single highest-signal pattern for LLM extraction:
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<section class="faq">
|
|
41
|
+
<h2>Frequently Asked Questions</h2>
|
|
42
|
+
<div>
|
|
43
|
+
<h3>What is X?</h3>
|
|
44
|
+
<p>X is ...</p>
|
|
45
|
+
</div>
|
|
46
|
+
<div>
|
|
47
|
+
<h3>How much does X cost?</h3>
|
|
48
|
+
<p>X costs $... per ...</p>
|
|
49
|
+
</div>
|
|
50
|
+
</section>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Pair with `FAQPage` JSON-LD (see [schema-types.md](schema-types.md)).
|
|
54
|
+
|
|
55
|
+
### Tables for comparative data
|
|
56
|
+
|
|
57
|
+
Plans, pricing, specs, feature matrices:
|
|
58
|
+
|
|
59
|
+
```html
|
|
60
|
+
<table>
|
|
61
|
+
<caption>Plan comparison</caption>
|
|
62
|
+
<thead>
|
|
63
|
+
<tr><th>Feature</th><th>Free</th><th>Pro</th><th>Enterprise</th></tr>
|
|
64
|
+
</thead>
|
|
65
|
+
<tbody>
|
|
66
|
+
<tr><th scope="row">Users</th><td>1</td><td>10</td><td>Unlimited</td></tr>
|
|
67
|
+
<tr><th scope="row">Storage</th><td>5GB</td><td>100GB</td><td>Unlimited</td></tr>
|
|
68
|
+
</tbody>
|
|
69
|
+
</table>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
LLMs excel at extracting tabular data but struggle when the same info is written as prose.
|
|
73
|
+
|
|
74
|
+
### Lists for steps
|
|
75
|
+
|
|
76
|
+
Use `<ol>` for ordered steps, `<ul>` for unordered sets:
|
|
77
|
+
|
|
78
|
+
```html
|
|
79
|
+
<h2>How to reset your password</h2>
|
|
80
|
+
<ol>
|
|
81
|
+
<li>Go to the login page.</li>
|
|
82
|
+
<li>Click "Forgot password".</li>
|
|
83
|
+
<li>Enter your email. A reset link arrives within 2 minutes.</li>
|
|
84
|
+
<li>Click the link and choose a new password.</li>
|
|
85
|
+
</ol>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Pair with `HowTo` schema for critical procedures.
|
|
89
|
+
|
|
90
|
+
### Definition lists for glossaries
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<dl>
|
|
94
|
+
<dt>LCP</dt>
|
|
95
|
+
<dd>Largest Contentful Paint — time to render the largest visible element. Target: under 2.5 seconds.</dd>
|
|
96
|
+
|
|
97
|
+
<dt>INP</dt>
|
|
98
|
+
<dd>Interaction to Next Paint — longest interaction latency in a session. Target: under 200ms.</dd>
|
|
99
|
+
</dl>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Attribution & Citations
|
|
105
|
+
|
|
106
|
+
LLM answer engines (especially Perplexity, Google AI Overviews, Bing Copilot) prefer citable sources.
|
|
107
|
+
|
|
108
|
+
### Author bylines
|
|
109
|
+
|
|
110
|
+
```html
|
|
111
|
+
<article>
|
|
112
|
+
<h1>Article title</h1>
|
|
113
|
+
<p class="byline">
|
|
114
|
+
By <a rel="author" href="/authors/jane-doe">Jane Doe</a>,
|
|
115
|
+
<time datetime="2026-04-09">April 9, 2026</time>
|
|
116
|
+
</p>
|
|
117
|
+
<p>...</p>
|
|
118
|
+
</article>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Pair with `Article` schema including `author` and `datePublished`.
|
|
122
|
+
|
|
123
|
+
### Inline citations
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<p>
|
|
127
|
+
Google's Core Web Vitals include LCP, INP, and CLS
|
|
128
|
+
<cite><a href="https://web.dev/vitals/">web.dev/vitals</a></cite>.
|
|
129
|
+
</p>
|
|
130
|
+
|
|
131
|
+
<p>
|
|
132
|
+
According to the 2024 State of JS report, React adoption
|
|
133
|
+
is at 76%<sup><a href="#ref-1">[1]</a></sup>.
|
|
134
|
+
</p>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Quotes
|
|
138
|
+
|
|
139
|
+
Use `<blockquote>` with `cite` attribute, or `<q>` for inline:
|
|
140
|
+
|
|
141
|
+
```html
|
|
142
|
+
<blockquote cite="https://example.com/source">
|
|
143
|
+
<p>Direct quote here.</p>
|
|
144
|
+
<footer>— <cite>Source Author, Source Publication</cite></footer>
|
|
145
|
+
</blockquote>
|
|
146
|
+
|
|
147
|
+
<p>As Crockford put it, <q cite="https://example.com">JavaScript is the world's most misunderstood language</q>.</p>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## speakable Schema
|
|
153
|
+
|
|
154
|
+
Marks portions of a page suited for audio/voice answer engines (Google Assistant, Alexa, Siri).
|
|
155
|
+
|
|
156
|
+
```html
|
|
157
|
+
<script type="application/ld+json">
|
|
158
|
+
{
|
|
159
|
+
"@context": "https://schema.org",
|
|
160
|
+
"@type": "WebPage",
|
|
161
|
+
"speakable": {
|
|
162
|
+
"@type": "SpeakableSpecification",
|
|
163
|
+
"cssSelector": [".article-summary", "h1"]
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
</script>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
- `cssSelector`: CSS selectors for speakable content.
|
|
170
|
+
- `xpath`: XPath selectors (alternative).
|
|
171
|
+
|
|
172
|
+
Best for: news article summaries, FAQ answers, definitions.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## JS-Gated Content Anti-Patterns
|
|
177
|
+
|
|
178
|
+
LLM crawlers typically ingest the initial DOM. Content revealed by clicks/hovers/scrolls may not be captured.
|
|
179
|
+
|
|
180
|
+
### Avoid for critical content
|
|
181
|
+
|
|
182
|
+
```jsx
|
|
183
|
+
// Bad — key FAQ answers hidden
|
|
184
|
+
<Accordion>
|
|
185
|
+
<AccordionItem title="What does X cost?">
|
|
186
|
+
<p>X costs $...</p> {/* Hidden until clicked */}
|
|
187
|
+
</AccordionItem>
|
|
188
|
+
</Accordion>
|
|
189
|
+
|
|
190
|
+
// Good — content visible by default, collapsed via CSS (still in DOM)
|
|
191
|
+
<details>
|
|
192
|
+
<summary>What does X cost?</summary>
|
|
193
|
+
<p>X costs $...</p> {/* In DOM always — <details> is semantic */}
|
|
194
|
+
</details>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The native `<details>`/`<summary>` element is a rare exception — content is in the DOM, just visually collapsed.
|
|
198
|
+
|
|
199
|
+
### Tabs
|
|
200
|
+
|
|
201
|
+
Similar issue. If tab content is only rendered when active, hidden tabs are lost:
|
|
202
|
+
|
|
203
|
+
```jsx
|
|
204
|
+
// Bad — only active tab rendered
|
|
205
|
+
{activeTab === 'pricing' && <PricingContent />}
|
|
206
|
+
|
|
207
|
+
// Better — all rendered, hidden via CSS
|
|
208
|
+
<div hidden={activeTab !== 'pricing'}>
|
|
209
|
+
<PricingContent />
|
|
210
|
+
</div>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Per-Framework Notes
|
|
216
|
+
|
|
217
|
+
### Next.js / Remix / SvelteKit / Astro / Gatsby (SSR/SSG)
|
|
218
|
+
|
|
219
|
+
These render content server-side. GEO concerns are mostly about content structure, not rendering mode.
|
|
220
|
+
|
|
221
|
+
### SPAs without SSR (Vue, React CRA, Vite-SPA, Angular without Universal)
|
|
222
|
+
|
|
223
|
+
These don't render content for crawlers at all. **Category 7 (rendering) supersedes GEO** — fix the SPA crawlability first; GEO is moot if nothing is visible.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Checklist (Category 6 findings)
|
|
228
|
+
|
|
229
|
+
- [ ] FAQ-style content uses `FAQPage` schema.
|
|
230
|
+
- [ ] Summary content uses `speakable` schema.
|
|
231
|
+
- [ ] Paragraphs >400 words are broken up with sub-headings.
|
|
232
|
+
- [ ] Citations use `<cite>` and author bylines.
|
|
233
|
+
- [ ] Quoted content uses `<blockquote>`/`<q>` with `cite` attr.
|
|
234
|
+
- [ ] How-to content uses `<ol>` + `HowTo` schema.
|
|
235
|
+
- [ ] Comparative data uses `<table>` with proper headers.
|
|
236
|
+
- [ ] Glossary content uses `<dl>`/`<dt>`/`<dd>`.
|
|
237
|
+
- [ ] Semantic HTML (`<article>`, `<section>`, `<main>`, `<nav>`, `<aside>`) is used over `<div>`.
|
|
238
|
+
- [ ] Critical content is NOT hidden behind tabs/accordions (except native `<details>`).
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## References
|
|
243
|
+
|
|
244
|
+
- Princeton/Georgia Tech GEO paper (Aggarwal et al., 2023): https://arxiv.org/abs/2311.09735
|
|
245
|
+
- Schema.org speakable: https://schema.org/speakable
|
|
246
|
+
- Schema.org FAQPage: https://schema.org/FAQPage
|
|
247
|
+
- Schema.org HowTo: https://schema.org/HowTo
|
|
248
|
+
- Google Search Central (structured data guidelines): https://developers.google.com/search/docs/appearance/structured-data
|
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
# Schema.org JSON-LD Templates
|
|
2
|
+
|
|
3
|
+
Reference for `seo-validate` Category 3 (Structured Data). Required properties for the rich-result-eligible types, with JSON-LD templates.
|
|
4
|
+
|
|
5
|
+
Source: Schema.org vocabulary + Google Search Central rich-results requirements.
|
|
6
|
+
|
|
7
|
+
## Base Format
|
|
8
|
+
|
|
9
|
+
All JSON-LD is embedded in `<script type="application/ld+json">` blocks, usually in `<head>` or the top of `<body>`:
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<script type="application/ld+json">
|
|
13
|
+
{
|
|
14
|
+
"@context": "https://schema.org",
|
|
15
|
+
"@type": "...",
|
|
16
|
+
...
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Universal required properties** (checked by Category 3):
|
|
22
|
+
- `@context` — always `https://schema.org`.
|
|
23
|
+
- `@type` — valid Schema.org type name.
|
|
24
|
+
|
|
25
|
+
Multiple types on one page: use an array:
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<script type="application/ld+json">
|
|
29
|
+
[
|
|
30
|
+
{ "@context": "https://schema.org", "@type": "Organization", ... },
|
|
31
|
+
{ "@context": "https://schema.org", "@type": "WebSite", ... }
|
|
32
|
+
]
|
|
33
|
+
</script>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Article
|
|
39
|
+
|
|
40
|
+
For blog posts, news, editorial content.
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"@context": "https://schema.org",
|
|
45
|
+
"@type": "Article",
|
|
46
|
+
"headline": "Article headline (max 110 chars for Google rich results)",
|
|
47
|
+
"image": [
|
|
48
|
+
"https://example.com/16x9.jpg",
|
|
49
|
+
"https://example.com/4x3.jpg",
|
|
50
|
+
"https://example.com/1x1.jpg"
|
|
51
|
+
],
|
|
52
|
+
"datePublished": "2026-04-09T08:00:00+00:00",
|
|
53
|
+
"dateModified": "2026-04-10T12:00:00+00:00",
|
|
54
|
+
"author": [{
|
|
55
|
+
"@type": "Person",
|
|
56
|
+
"name": "Jane Doe",
|
|
57
|
+
"url": "https://example.com/authors/jane-doe"
|
|
58
|
+
}],
|
|
59
|
+
"publisher": {
|
|
60
|
+
"@type": "Organization",
|
|
61
|
+
"name": "ExampleCo",
|
|
62
|
+
"logo": {
|
|
63
|
+
"@type": "ImageObject",
|
|
64
|
+
"url": "https://example.com/logo.png"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"mainEntityOfPage": {
|
|
68
|
+
"@type": "WebPage",
|
|
69
|
+
"@id": "https://example.com/blog/article-slug"
|
|
70
|
+
},
|
|
71
|
+
"description": "Short description of the article"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Required** (Category 3 flags absence): `headline`, `author`, `datePublished`, `image`.
|
|
76
|
+
**Strongly recommended**: `dateModified`, `publisher`, `mainEntityOfPage`.
|
|
77
|
+
|
|
78
|
+
Subtypes: `NewsArticle`, `BlogPosting`, `TechArticle`, `OpinionNewsArticle`.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## FAQPage
|
|
83
|
+
|
|
84
|
+
Triggers rich FAQ results in SERP.
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"@context": "https://schema.org",
|
|
89
|
+
"@type": "FAQPage",
|
|
90
|
+
"mainEntity": [
|
|
91
|
+
{
|
|
92
|
+
"@type": "Question",
|
|
93
|
+
"name": "What is X?",
|
|
94
|
+
"acceptedAnswer": {
|
|
95
|
+
"@type": "Answer",
|
|
96
|
+
"text": "X is ..."
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"@type": "Question",
|
|
101
|
+
"name": "How much does X cost?",
|
|
102
|
+
"acceptedAnswer": {
|
|
103
|
+
"@type": "Answer",
|
|
104
|
+
"text": "X costs $..."
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Required**: `mainEntity` array with ≥2 `Question` items, each with `name` + `acceptedAnswer.text`.
|
|
112
|
+
|
|
113
|
+
Google restriction: FAQ rich results only shown for authoritative government/health sites as of August 2023 — but the markup still helps LLM extraction (GEO).
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## HowTo
|
|
118
|
+
|
|
119
|
+
For step-by-step instructional content.
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"@context": "https://schema.org",
|
|
124
|
+
"@type": "HowTo",
|
|
125
|
+
"name": "How to reset your password",
|
|
126
|
+
"description": "Steps to reset your account password",
|
|
127
|
+
"totalTime": "PT5M",
|
|
128
|
+
"supply": [
|
|
129
|
+
{ "@type": "HowToSupply", "name": "Email access" }
|
|
130
|
+
],
|
|
131
|
+
"tool": [
|
|
132
|
+
{ "@type": "HowToTool", "name": "Web browser" }
|
|
133
|
+
],
|
|
134
|
+
"step": [
|
|
135
|
+
{
|
|
136
|
+
"@type": "HowToStep",
|
|
137
|
+
"name": "Go to the login page",
|
|
138
|
+
"text": "Navigate to https://example.com/login",
|
|
139
|
+
"url": "https://example.com/login"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"@type": "HowToStep",
|
|
143
|
+
"name": "Click 'Forgot password'",
|
|
144
|
+
"text": "On the login page, click the 'Forgot password' link."
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Required**: `name`, `step` array with ≥2 `HowToStep` items.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## BreadcrumbList
|
|
155
|
+
|
|
156
|
+
Breadcrumb trails in SERP.
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"@context": "https://schema.org",
|
|
161
|
+
"@type": "BreadcrumbList",
|
|
162
|
+
"itemListElement": [
|
|
163
|
+
{
|
|
164
|
+
"@type": "ListItem",
|
|
165
|
+
"position": 1,
|
|
166
|
+
"name": "Home",
|
|
167
|
+
"item": "https://example.com/"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"@type": "ListItem",
|
|
171
|
+
"position": 2,
|
|
172
|
+
"name": "Blog",
|
|
173
|
+
"item": "https://example.com/blog"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"@type": "ListItem",
|
|
177
|
+
"position": 3,
|
|
178
|
+
"name": "Article Title"
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Required**: `itemListElement` array with `position`, `name`, and `item` (except last). Last item omits `item` since it's the current page.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Organization
|
|
189
|
+
|
|
190
|
+
Defines your company/brand for Knowledge Graph.
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"@context": "https://schema.org",
|
|
195
|
+
"@type": "Organization",
|
|
196
|
+
"name": "ExampleCo",
|
|
197
|
+
"url": "https://example.com",
|
|
198
|
+
"logo": "https://example.com/logo.png",
|
|
199
|
+
"sameAs": [
|
|
200
|
+
"https://twitter.com/exampleco",
|
|
201
|
+
"https://www.linkedin.com/company/exampleco",
|
|
202
|
+
"https://github.com/exampleco"
|
|
203
|
+
],
|
|
204
|
+
"contactPoint": [{
|
|
205
|
+
"@type": "ContactPoint",
|
|
206
|
+
"telephone": "+1-555-123-4567",
|
|
207
|
+
"contactType": "customer service",
|
|
208
|
+
"areaServed": "US",
|
|
209
|
+
"availableLanguage": ["en", "es"]
|
|
210
|
+
}]
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Required**: `name`, `url`, `logo`.
|
|
215
|
+
|
|
216
|
+
Subtypes for specific kinds: `Corporation`, `NGO`, `EducationalOrganization`, `LocalBusiness` (see below).
|
|
217
|
+
|
|
218
|
+
Typically placed once on the site, in a shared layout. `WebSite` schema can reference it via `publisher`.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Product
|
|
223
|
+
|
|
224
|
+
For e-commerce product pages.
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"@context": "https://schema.org",
|
|
229
|
+
"@type": "Product",
|
|
230
|
+
"name": "Product name",
|
|
231
|
+
"image": [
|
|
232
|
+
"https://example.com/product-1x1.jpg",
|
|
233
|
+
"https://example.com/product-4x3.jpg",
|
|
234
|
+
"https://example.com/product-16x9.jpg"
|
|
235
|
+
],
|
|
236
|
+
"description": "Product description",
|
|
237
|
+
"brand": {
|
|
238
|
+
"@type": "Brand",
|
|
239
|
+
"name": "Brand Name"
|
|
240
|
+
},
|
|
241
|
+
"sku": "SKU-12345",
|
|
242
|
+
"mpn": "MPN-12345",
|
|
243
|
+
"gtin13": "0123456789012",
|
|
244
|
+
"offers": {
|
|
245
|
+
"@type": "Offer",
|
|
246
|
+
"url": "https://example.com/products/sku-12345",
|
|
247
|
+
"priceCurrency": "USD",
|
|
248
|
+
"price": "49.99",
|
|
249
|
+
"priceValidUntil": "2027-01-01",
|
|
250
|
+
"availability": "https://schema.org/InStock",
|
|
251
|
+
"itemCondition": "https://schema.org/NewCondition"
|
|
252
|
+
},
|
|
253
|
+
"aggregateRating": {
|
|
254
|
+
"@type": "AggregateRating",
|
|
255
|
+
"ratingValue": "4.6",
|
|
256
|
+
"reviewCount": "142"
|
|
257
|
+
},
|
|
258
|
+
"review": [{
|
|
259
|
+
"@type": "Review",
|
|
260
|
+
"author": { "@type": "Person", "name": "Jane" },
|
|
261
|
+
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
|
|
262
|
+
"reviewBody": "Great product."
|
|
263
|
+
}]
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Required**: `name`, `image`, `offers` (with `price` + `priceCurrency` + `availability`).
|
|
268
|
+
**Strongly recommended for rich results**: `aggregateRating`, `review`, `brand`.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## LocalBusiness
|
|
273
|
+
|
|
274
|
+
For brick-and-mortar businesses (local SEO).
|
|
275
|
+
|
|
276
|
+
```json
|
|
277
|
+
{
|
|
278
|
+
"@context": "https://schema.org",
|
|
279
|
+
"@type": "LocalBusiness",
|
|
280
|
+
"@id": "https://example.com/#local-business",
|
|
281
|
+
"name": "ExampleCo Store",
|
|
282
|
+
"image": "https://example.com/store.jpg",
|
|
283
|
+
"url": "https://example.com",
|
|
284
|
+
"telephone": "+1-555-123-4567",
|
|
285
|
+
"address": {
|
|
286
|
+
"@type": "PostalAddress",
|
|
287
|
+
"streetAddress": "123 Main St",
|
|
288
|
+
"addressLocality": "San Francisco",
|
|
289
|
+
"addressRegion": "CA",
|
|
290
|
+
"postalCode": "94110",
|
|
291
|
+
"addressCountry": "US"
|
|
292
|
+
},
|
|
293
|
+
"geo": {
|
|
294
|
+
"@type": "GeoCoordinates",
|
|
295
|
+
"latitude": 37.7749,
|
|
296
|
+
"longitude": -122.4194
|
|
297
|
+
},
|
|
298
|
+
"openingHoursSpecification": [
|
|
299
|
+
{
|
|
300
|
+
"@type": "OpeningHoursSpecification",
|
|
301
|
+
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
|
302
|
+
"opens": "09:00",
|
|
303
|
+
"closes": "18:00"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"@type": "OpeningHoursSpecification",
|
|
307
|
+
"dayOfWeek": "Saturday",
|
|
308
|
+
"opens": "10:00",
|
|
309
|
+
"closes": "16:00"
|
|
310
|
+
}
|
|
311
|
+
],
|
|
312
|
+
"priceRange": "$$"
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Required**: `name`, `address`, `telephone`.
|
|
317
|
+
**Strongly recommended**: `openingHoursSpecification`, `geo`, `url`, `image`.
|
|
318
|
+
|
|
319
|
+
Use more specific subtypes when applicable: `Restaurant`, `Hotel`, `MedicalClinic`, `Store`, `AutoDealer`, etc.
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## WebSite (with SearchAction)
|
|
324
|
+
|
|
325
|
+
Enables sitelinks search box in SERP.
|
|
326
|
+
|
|
327
|
+
```json
|
|
328
|
+
{
|
|
329
|
+
"@context": "https://schema.org",
|
|
330
|
+
"@type": "WebSite",
|
|
331
|
+
"name": "ExampleCo",
|
|
332
|
+
"url": "https://example.com",
|
|
333
|
+
"potentialAction": {
|
|
334
|
+
"@type": "SearchAction",
|
|
335
|
+
"target": {
|
|
336
|
+
"@type": "EntryPoint",
|
|
337
|
+
"urlTemplate": "https://example.com/search?q={search_term_string}"
|
|
338
|
+
},
|
|
339
|
+
"query-input": "required name=search_term_string"
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Event
|
|
347
|
+
|
|
348
|
+
For conferences, concerts, webinars.
|
|
349
|
+
|
|
350
|
+
```json
|
|
351
|
+
{
|
|
352
|
+
"@context": "https://schema.org",
|
|
353
|
+
"@type": "Event",
|
|
354
|
+
"name": "Event name",
|
|
355
|
+
"startDate": "2026-06-15T09:00:00-07:00",
|
|
356
|
+
"endDate": "2026-06-15T17:00:00-07:00",
|
|
357
|
+
"eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode",
|
|
358
|
+
"eventStatus": "https://schema.org/EventScheduled",
|
|
359
|
+
"location": {
|
|
360
|
+
"@type": "Place",
|
|
361
|
+
"name": "Venue Name",
|
|
362
|
+
"address": { "@type": "PostalAddress", ... }
|
|
363
|
+
},
|
|
364
|
+
"image": ["https://example.com/event.jpg"],
|
|
365
|
+
"description": "...",
|
|
366
|
+
"offers": {
|
|
367
|
+
"@type": "Offer",
|
|
368
|
+
"url": "https://example.com/event",
|
|
369
|
+
"price": "99.00",
|
|
370
|
+
"priceCurrency": "USD",
|
|
371
|
+
"availability": "https://schema.org/InStock",
|
|
372
|
+
"validFrom": "2026-01-01T00:00:00-08:00"
|
|
373
|
+
},
|
|
374
|
+
"organizer": {
|
|
375
|
+
"@type": "Organization",
|
|
376
|
+
"name": "ExampleCo",
|
|
377
|
+
"url": "https://example.com"
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Required**: `name`, `startDate`, `location` (or `eventAttendanceMode: OnlineEventAttendanceMode`).
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## Recipe
|
|
387
|
+
|
|
388
|
+
For food recipes.
|
|
389
|
+
|
|
390
|
+
```json
|
|
391
|
+
{
|
|
392
|
+
"@context": "https://schema.org",
|
|
393
|
+
"@type": "Recipe",
|
|
394
|
+
"name": "Recipe name",
|
|
395
|
+
"image": ["..."],
|
|
396
|
+
"author": { "@type": "Person", "name": "Jane Doe" },
|
|
397
|
+
"datePublished": "2026-04-09",
|
|
398
|
+
"description": "...",
|
|
399
|
+
"prepTime": "PT15M",
|
|
400
|
+
"cookTime": "PT1H",
|
|
401
|
+
"totalTime": "PT1H15M",
|
|
402
|
+
"recipeYield": "8 servings",
|
|
403
|
+
"recipeIngredient": ["2 cups flour", "1 tsp salt"],
|
|
404
|
+
"recipeInstructions": [
|
|
405
|
+
{ "@type": "HowToStep", "text": "..." }
|
|
406
|
+
],
|
|
407
|
+
"nutrition": {
|
|
408
|
+
"@type": "NutritionInformation",
|
|
409
|
+
"calories": "250 calories"
|
|
410
|
+
},
|
|
411
|
+
"aggregateRating": {
|
|
412
|
+
"@type": "AggregateRating",
|
|
413
|
+
"ratingValue": "4.8",
|
|
414
|
+
"reviewCount": "42"
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## VideoObject
|
|
422
|
+
|
|
423
|
+
For video content.
|
|
424
|
+
|
|
425
|
+
```json
|
|
426
|
+
{
|
|
427
|
+
"@context": "https://schema.org",
|
|
428
|
+
"@type": "VideoObject",
|
|
429
|
+
"name": "Video title",
|
|
430
|
+
"description": "...",
|
|
431
|
+
"thumbnailUrl": ["https://example.com/thumb-16x9.jpg"],
|
|
432
|
+
"uploadDate": "2026-04-09T08:00:00+00:00",
|
|
433
|
+
"duration": "PT5M30S",
|
|
434
|
+
"contentUrl": "https://example.com/video.mp4",
|
|
435
|
+
"embedUrl": "https://example.com/embed/video"
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Common Mistakes (flagged by Category 3)
|
|
442
|
+
|
|
443
|
+
1. **Missing `@context`** or wrong value (e.g., `http://` instead of `https://`).
|
|
444
|
+
2. **Wrong `@type`** (e.g., `article` lowercase — must be `Article`).
|
|
445
|
+
3. **Dates not in ISO 8601** (`2026-04-09` good; `April 9, 2026` bad).
|
|
446
|
+
4. **Relative URLs** for `image`, `logo`, `url` — must be absolute.
|
|
447
|
+
5. **Missing required properties** per type (see each section above).
|
|
448
|
+
6. **Markup doesn't match visible content** — violates Google guidelines.
|
|
449
|
+
7. **Duplicate JSON-LD blocks** with conflicting data — consolidate into one.
|
|
450
|
+
8. **Fake reviews / made-up aggregate ratings** — violates Google guidelines.
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Testing
|
|
455
|
+
|
|
456
|
+
- Google Rich Results Test: https://search.google.com/test/rich-results
|
|
457
|
+
- Schema.org validator: https://validator.schema.org/
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## References
|
|
462
|
+
|
|
463
|
+
- Schema.org: https://schema.org/
|
|
464
|
+
- Google rich results: https://developers.google.com/search/docs/appearance/structured-data
|
|
465
|
+
- JSON-LD 1.1: https://www.w3.org/TR/json-ld11/
|