@veyralabs/skills 0.2.0 → 0.4.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/README.md +65 -101
- package/bin/cli.js +20 -1
- package/commands/brandaudit.md +3 -0
- package/commands/competitornames.md +3 -0
- package/commands/domainforge.md +3 -0
- package/commands/namingguide.md +3 -0
- package/commands/shopify-dev.md +3 -0
- package/commands/shopify-store.md +3 -0
- package/commands/webcloner.md +5 -0
- package/install.sh +24 -1
- package/package.json +8 -2
- package/skills/shopify-suite/shopify-dev/SKILL.md +409 -0
- package/skills/shopify-suite/shopify-dev/references/app-architecture.md +322 -0
- package/skills/shopify-suite/shopify-dev/references/cli-workflows.md +257 -0
- package/skills/shopify-suite/shopify-dev/references/graphql-queries.md +298 -0
- package/skills/shopify-suite/shopify-dev/references/liquid-patterns.md +286 -0
- package/skills/shopify-suite/shopify-store/SKILL.md +283 -0
- package/skills/shopify-suite/shopify-store/references/app-stack.md +175 -0
- package/skills/shopify-suite/shopify-store/references/audit-framework.md +206 -0
- package/skills/shopify-suite/shopify-store/references/mcp-queries.md +216 -0
- package/skills/shopify-suite/shopify-store/references/product-optimization.md +266 -0
- package/skills/shopify-suite/shopify-store/references/seo-shopify.md +165 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# MCP Queries — shopify-store Reference
|
|
2
|
+
|
|
3
|
+
Ready-to-use GraphQL queries for Mode A (shopify-mcp connected).
|
|
4
|
+
All queries use the Admin API via the shopify-mcp `graphql` tool.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Products
|
|
9
|
+
|
|
10
|
+
### Get all products with SEO fields
|
|
11
|
+
```graphql
|
|
12
|
+
query GetProducts($cursor: String) {
|
|
13
|
+
products(first: 250, after: $cursor) {
|
|
14
|
+
pageInfo { hasNextPage endCursor }
|
|
15
|
+
nodes {
|
|
16
|
+
id
|
|
17
|
+
title
|
|
18
|
+
handle
|
|
19
|
+
status
|
|
20
|
+
descriptionHtml
|
|
21
|
+
seo { title description }
|
|
22
|
+
images(first: 5) {
|
|
23
|
+
nodes { id url altText }
|
|
24
|
+
}
|
|
25
|
+
variants(first: 100) {
|
|
26
|
+
nodes { id title sku price availableForSale }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Products missing SEO data
|
|
34
|
+
```graphql
|
|
35
|
+
query ProductsSEOAudit {
|
|
36
|
+
products(first: 250, query: "status:active") {
|
|
37
|
+
nodes {
|
|
38
|
+
id
|
|
39
|
+
title
|
|
40
|
+
seo { title description }
|
|
41
|
+
images(first: 1) {
|
|
42
|
+
nodes { altText }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Collections
|
|
52
|
+
|
|
53
|
+
### Full collection structure
|
|
54
|
+
```graphql
|
|
55
|
+
query GetCollections {
|
|
56
|
+
collections(first: 100) {
|
|
57
|
+
nodes {
|
|
58
|
+
id
|
|
59
|
+
title
|
|
60
|
+
handle
|
|
61
|
+
sortOrder
|
|
62
|
+
productsCount { count }
|
|
63
|
+
seo { title description }
|
|
64
|
+
image { altText url }
|
|
65
|
+
ruleSet {
|
|
66
|
+
rules { column relation condition }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Navigation (Menus)
|
|
76
|
+
|
|
77
|
+
```graphql
|
|
78
|
+
query GetMenus {
|
|
79
|
+
menus(first: 10) {
|
|
80
|
+
nodes {
|
|
81
|
+
id
|
|
82
|
+
title
|
|
83
|
+
handle
|
|
84
|
+
items {
|
|
85
|
+
id
|
|
86
|
+
title
|
|
87
|
+
url
|
|
88
|
+
type
|
|
89
|
+
items {
|
|
90
|
+
id
|
|
91
|
+
title
|
|
92
|
+
url
|
|
93
|
+
type
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Orders (last 90 days)
|
|
104
|
+
|
|
105
|
+
```graphql
|
|
106
|
+
query GetOrders {
|
|
107
|
+
orders(first: 250, query: "created_at:>2025-01-01") {
|
|
108
|
+
nodes {
|
|
109
|
+
id
|
|
110
|
+
totalPriceSet { shopMoney { amount currencyCode } }
|
|
111
|
+
lineItems(first: 10) {
|
|
112
|
+
nodes { quantity title sku }
|
|
113
|
+
}
|
|
114
|
+
customer { id email numberOfOrders }
|
|
115
|
+
createdAt
|
|
116
|
+
cancelledAt
|
|
117
|
+
financialStatus
|
|
118
|
+
fulfillmentStatus
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Metafields
|
|
127
|
+
|
|
128
|
+
### Get product metafields
|
|
129
|
+
```graphql
|
|
130
|
+
query GetProductMetafields($id: ID!) {
|
|
131
|
+
product(id: $id) {
|
|
132
|
+
metafields(first: 20) {
|
|
133
|
+
nodes {
|
|
134
|
+
namespace
|
|
135
|
+
key
|
|
136
|
+
value
|
|
137
|
+
type
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Set SEO metafield
|
|
145
|
+
```graphql
|
|
146
|
+
mutation SetMetafield($metafields: [MetafieldsSetInput!]!) {
|
|
147
|
+
metafieldsSet(metafields: $metafields) {
|
|
148
|
+
metafields { key value }
|
|
149
|
+
userErrors { field message }
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
Variables:
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"metafields": [{
|
|
157
|
+
"ownerId": "gid://shopify/Product/123",
|
|
158
|
+
"namespace": "seo",
|
|
159
|
+
"key": "description",
|
|
160
|
+
"value": "Your SEO description here",
|
|
161
|
+
"type": "single_line_text_field"
|
|
162
|
+
}]
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Installed Apps (via App Installations)
|
|
169
|
+
|
|
170
|
+
```graphql
|
|
171
|
+
query GetInstalledApps {
|
|
172
|
+
appInstallations(first: 50) {
|
|
173
|
+
nodes {
|
|
174
|
+
app {
|
|
175
|
+
title
|
|
176
|
+
handle
|
|
177
|
+
developerName
|
|
178
|
+
pricingSummary
|
|
179
|
+
}
|
|
180
|
+
launchUrl
|
|
181
|
+
uninstallUrl
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Shopify Analytics (basic)
|
|
190
|
+
|
|
191
|
+
```graphql
|
|
192
|
+
query GetShopInfo {
|
|
193
|
+
shop {
|
|
194
|
+
name
|
|
195
|
+
myshopifyDomain
|
|
196
|
+
plan { displayName partnerDevelopment }
|
|
197
|
+
currencyCode
|
|
198
|
+
timezoneAbbreviation
|
|
199
|
+
ianaTimezone
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
For revenue/conversion analytics, use the Reports API:
|
|
205
|
+
```graphql
|
|
206
|
+
query GetReports {
|
|
207
|
+
reports(first: 10, query: "report_type:custom") {
|
|
208
|
+
nodes {
|
|
209
|
+
id
|
|
210
|
+
name
|
|
211
|
+
category
|
|
212
|
+
shopifyQL
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Product Optimization — shopify-store Reference
|
|
2
|
+
|
|
3
|
+
Title formulas, description frameworks, and image standards for Shopify product pages.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Title Formulas
|
|
8
|
+
|
|
9
|
+
### Formula by product type
|
|
10
|
+
|
|
11
|
+
**Apparel:**
|
|
12
|
+
```
|
|
13
|
+
[Product Name] — [Key Attribute] | [Brand]
|
|
14
|
+
Blue Linen Shirt — Relaxed Fit | Studio Name
|
|
15
|
+
Oversized Hoodie — 400gsm Cotton | Brand
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Electronics / tech:**
|
|
19
|
+
```
|
|
20
|
+
[Brand] [Product Name] [Model/Key Spec]
|
|
21
|
+
Brand Wireless Headphones ANC Pro 45hr
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Home goods / furniture:**
|
|
25
|
+
```
|
|
26
|
+
[Product Name] — [Material/Style] — [Size if relevant]
|
|
27
|
+
Oak Dining Table — Solid Wood — 160cm
|
|
28
|
+
Linen Throw Pillow — Natural — 45x45cm
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Beauty / skincare:**
|
|
32
|
+
```
|
|
33
|
+
[Product Name] — [Key Ingredient/Benefit] | [Brand]
|
|
34
|
+
Vitamin C Serum — Brightening 20% | Brand
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Food / consumables:**
|
|
38
|
+
```
|
|
39
|
+
[Product Name] — [Size/Format/Origin]
|
|
40
|
+
Organic Olive Oil — 500ml Cold Press
|
|
41
|
+
Colombian Coffee — Medium Roast 250g
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Title rules
|
|
45
|
+
- 50-70 characters (shows fully in Google SERP and Shopify search)
|
|
46
|
+
- Lead with product name, not brand (unless brand is the purchase driver)
|
|
47
|
+
- Include the one attribute buyers filter by most (color, size, material)
|
|
48
|
+
- No: "NEW", "SALE", "BEST SELLER", "!", "100% authentic"
|
|
49
|
+
- No: all caps
|
|
50
|
+
- No: variant info in title (size S/M/L goes in variants, not title)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Meta Title Formulas
|
|
55
|
+
|
|
56
|
+
The meta title is separate from the product title in Shopify (Admin → SEO section).
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
[Product Name] [Key Attribute] — Buy Online | [Brand]
|
|
60
|
+
[Primary Keyword] — [Secondary Keyword] | [Brand]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Examples:
|
|
64
|
+
```
|
|
65
|
+
Linen Relaxed Shirt — Men's Summer Fashion | Studio Name
|
|
66
|
+
Wireless Noise Cancelling Headphones | Brand
|
|
67
|
+
Organic Olive Oil 500ml — Cold Pressed | Store Name
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Rules:
|
|
71
|
+
- 50-60 characters (Google truncates at ~60)
|
|
72
|
+
- Include primary keyword near the front
|
|
73
|
+
- Include brand at end (recognition, not keyword — separator `|` or `—`)
|
|
74
|
+
- Different from the product title (if they're identical, one is wasted)
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Description Framework
|
|
79
|
+
|
|
80
|
+
### SPECS → STORY → SOCIAL PROOF structure
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
[Opening line: main benefit or use case — 1 sentence]
|
|
84
|
+
|
|
85
|
+
[Specs block: what it's made of, dimensions, key features — short bullets]
|
|
86
|
+
|
|
87
|
+
[Story paragraph: who it's for, when to use it, why it matters — 2-3 sentences]
|
|
88
|
+
|
|
89
|
+
[Trust closer: shipping, returns, sizing guide link — 1 sentence]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Example (apparel)
|
|
93
|
+
|
|
94
|
+
```html
|
|
95
|
+
<p>A linen shirt built for warm weather — breathable, lightweight, and gets better with every wash.</p>
|
|
96
|
+
|
|
97
|
+
<ul>
|
|
98
|
+
<li>100% European linen</li>
|
|
99
|
+
<li>Relaxed fit, fits true to size</li>
|
|
100
|
+
<li>Available in 8 colors</li>
|
|
101
|
+
<li>Machine washable at 30°C</li>
|
|
102
|
+
</ul>
|
|
103
|
+
|
|
104
|
+
<p>Designed for easy summer days — works equally well with shorts or tailored trousers.
|
|
105
|
+
The fabric softens naturally over time without losing its shape.</p>
|
|
106
|
+
|
|
107
|
+
<p>Free shipping on orders over €50. 30-day free returns. <a href="/pages/size-guide">Size guide</a>.</p>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Example (electronics)
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<p>45 hours of active noise cancellation, zero compromise on sound quality.</p>
|
|
114
|
+
|
|
115
|
+
<ul>
|
|
116
|
+
<li>ANC: -35dB noise reduction</li>
|
|
117
|
+
<li>Battery: 45hr ANC on, 60hr ANC off</li>
|
|
118
|
+
<li>Charging: USB-C, 15min = 5hr playback</li>
|
|
119
|
+
<li>Connectivity: Bluetooth 5.3, multipoint (2 devices simultaneously)</li>
|
|
120
|
+
<li>Weight: 248g</li>
|
|
121
|
+
</ul>
|
|
122
|
+
|
|
123
|
+
<p>Designed for long work sessions and travel. The over-ear cushions are memory foam —
|
|
124
|
+
they seal out noise without pressure points after hours of wear.</p>
|
|
125
|
+
|
|
126
|
+
<p>2-year warranty. Free returns within 30 days. Ships in 1-2 business days.</p>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Description rules
|
|
130
|
+
- Minimum 150 characters, aim for 300-500 characters
|
|
131
|
+
- First 160 characters become the meta description fallback — make them strong
|
|
132
|
+
- Lead with benefit, not feature ("stays cool" not "made of linen")
|
|
133
|
+
- Bullets for specs, prose for story — mix formats
|
|
134
|
+
- Include dimensions/weight for anything where size matters
|
|
135
|
+
- No fluff: "quality product", "you'll love it", "great for everyone"
|
|
136
|
+
- No generic manufacturer text — rewrite it
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Meta Description Formulas
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
[Main benefit]. [Key specs/features]. [Trust signal or CTA].
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Examples:
|
|
147
|
+
```
|
|
148
|
+
Breathable linen shirt perfect for summer. Available in 8 colors, sizes XS-XXL. Free shipping over €50.
|
|
149
|
+
(134 chars)
|
|
150
|
+
|
|
151
|
+
Noise cancelling headphones with 45hr battery. Bluetooth 5.3, USB-C fast charge. 2-year warranty included.
|
|
152
|
+
(106 chars)
|
|
153
|
+
|
|
154
|
+
Cold-pressed organic olive oil from Spanish groves. 500ml bottle, harvested November 2024. Free delivery over €30.
|
|
155
|
+
(113 chars)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Rules:
|
|
159
|
+
- 120-160 characters
|
|
160
|
+
- Unique per product (not the same as title)
|
|
161
|
+
- Include a purchase-trigger: price signal, shipping benefit, time signal, social proof
|
|
162
|
+
- No clickbait ("You won't believe...")
|
|
163
|
+
- Ends with implicit CTA or benefit
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Image Standards
|
|
168
|
+
|
|
169
|
+
### Required images per product
|
|
170
|
+
|
|
171
|
+
| # | Image type | Purpose |
|
|
172
|
+
|---|-----------|---------|
|
|
173
|
+
| 1 | Hero / packshot | Main listing image — product centered, clean background |
|
|
174
|
+
| 2 | Lifestyle in context | Shows scale, use, aspiration |
|
|
175
|
+
| 3 | Detail / texture | Close-up of key material or feature |
|
|
176
|
+
| 4+ | Variant images | One per color/style variant |
|
|
177
|
+
|
|
178
|
+
### Technical specs
|
|
179
|
+
|
|
180
|
+
| Spec | Recommended | Minimum |
|
|
181
|
+
|------|-------------|---------|
|
|
182
|
+
| Dimensions | 2048×2048px | 800×800px |
|
|
183
|
+
| Format | JPEG (80-85% quality) | — |
|
|
184
|
+
| Aspect ratio | 1:1 (square) | Consistent per product |
|
|
185
|
+
| Background (main image) | White #FFFFFF or very light gray | Clean neutral |
|
|
186
|
+
| File size | < 500KB after optimization | < 1MB |
|
|
187
|
+
|
|
188
|
+
### Alt text formulas
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
Main image: [Brand] [Product Name] [Key Attribute]
|
|
192
|
+
"Studio Name Blue Linen Shirt Relaxed Fit"
|
|
193
|
+
|
|
194
|
+
Lifestyle: [Product Name] [Context]
|
|
195
|
+
"Linen Shirt worn at outdoor dinner"
|
|
196
|
+
|
|
197
|
+
Detail: [Product Name] [What the detail shows]
|
|
198
|
+
"Linen Shirt fabric texture close-up"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Rules:
|
|
202
|
+
- Describe what's in the image, not the product name repeated
|
|
203
|
+
- Don't start with "Image of" or "Photo of" — Google already knows it's an image
|
|
204
|
+
- Include color for variant images
|
|
205
|
+
- Max 125 characters
|
|
206
|
+
|
|
207
|
+
### Variant images
|
|
208
|
+
|
|
209
|
+
Every color variant needs its own image — minimum the hero shot on the correct color.
|
|
210
|
+
Shopify auto-switches image when customer selects a color variant if images are tagged with variant.
|
|
211
|
+
|
|
212
|
+
In Shopify admin: product images → click image → assign to variant.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Collection Descriptions
|
|
217
|
+
|
|
218
|
+
Short, keyword-rich, benefit-first:
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
[What's in the collection — 1 sentence]. [Count or variety signal]. [Differentiator].
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Examples:
|
|
225
|
+
```
|
|
226
|
+
Men's shirts in linen, cotton, and blends for every season. 40+ styles, new arrivals weekly.
|
|
227
|
+
Free shipping on orders over €50.
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
Wireless headphones from entry-level to professional grade. Tested and reviewed by our audio team.
|
|
232
|
+
30-day trial period on every model.
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Rules:
|
|
236
|
+
- 2-4 sentences
|
|
237
|
+
- Include primary keyword naturally
|
|
238
|
+
- Avoid "our collection of" or "we offer" — lead with what's in it
|
|
239
|
+
- Update seasonally for campaign collections
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Variant Naming
|
|
244
|
+
|
|
245
|
+
### Color naming
|
|
246
|
+
|
|
247
|
+
Use recognizable color names, not marketing names:
|
|
248
|
+
- "Navy Blue" not "Ocean Depths"
|
|
249
|
+
- "Forest Green" not "Emerald Whisper"
|
|
250
|
+
- "Off-White" not "Morning Mist"
|
|
251
|
+
|
|
252
|
+
Exception: luxury or high-differentiation brands where color naming IS part of the brand language.
|
|
253
|
+
|
|
254
|
+
### Size naming
|
|
255
|
+
|
|
256
|
+
Consistent across catalog:
|
|
257
|
+
- Apparel: XS, S, M, L, XL, XXL (not Extra Small, Small, etc.)
|
|
258
|
+
- Shoes: numeric EU sizing (42, 43...) not US mixed
|
|
259
|
+
- Home: dimensions in cm or specific names ("Small / 45×45cm")
|
|
260
|
+
|
|
261
|
+
### Option order
|
|
262
|
+
|
|
263
|
+
Color before size (most common filter order):
|
|
264
|
+
- Option 1: Color
|
|
265
|
+
- Option 2: Size
|
|
266
|
+
- Option 3: Material (if needed)
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# SEO — Shopify-Specific Issues
|
|
2
|
+
|
|
3
|
+
Shopify has structural SEO issues that generic SEO guides miss. This covers the ones that actually matter.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Duplicate Content (Shopify's biggest SEO problem)
|
|
8
|
+
|
|
9
|
+
### The /products/ vs /collections/*/products/ problem
|
|
10
|
+
|
|
11
|
+
Shopify serves every product at two URLs:
|
|
12
|
+
- `https://store.com/products/blue-shirt`
|
|
13
|
+
- `https://store.com/collections/shirts/products/blue-shirt`
|
|
14
|
+
|
|
15
|
+
Shopify auto-canonicalizes collection-path URLs to the `/products/` URL. This is correct behavior — do not override it. But verify it's working:
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<!-- Should appear on /collections/shirts/products/blue-shirt -->
|
|
19
|
+
<link rel="canonical" href="https://store.com/products/blue-shirt">
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If a custom theme or app overrides this, you get duplicate content penalties.
|
|
23
|
+
|
|
24
|
+
### Tag pages getting indexed
|
|
25
|
+
|
|
26
|
+
Shopify creates URLs for every tag: `/collections/shirts/t-shirts`, `/collections/shirts/blue`.
|
|
27
|
+
These are thin pages with subset content — they dilute link equity and create duplicates.
|
|
28
|
+
|
|
29
|
+
Fix: add to `robots.txt` (Shopify 2.0 allows custom robots.txt):
|
|
30
|
+
```
|
|
31
|
+
Disallow: /collections/*+*
|
|
32
|
+
```
|
|
33
|
+
Or noindex via theme liquid:
|
|
34
|
+
```liquid
|
|
35
|
+
{% if current_tags %}
|
|
36
|
+
<meta name="robots" content="noindex, follow">
|
|
37
|
+
{% endif %}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Variant URLs
|
|
41
|
+
|
|
42
|
+
`/products/blue-shirt?variant=123456` creates near-duplicate pages per variant.
|
|
43
|
+
Shopify canonicalizes these to the main product URL automatically. Do not disable this.
|
|
44
|
+
|
|
45
|
+
### Pagination
|
|
46
|
+
|
|
47
|
+
`/collections/shirts?page=2` — Shopify removed `rel="next"/"prev"` pagination support in 2019. Google handles these via `?page=N` parameters. Do not noindex paginated pages — you'll lose product indexing.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Structured Data
|
|
52
|
+
|
|
53
|
+
### Product schema (must-have)
|
|
54
|
+
|
|
55
|
+
Shopify themes should output this on every product page. Check if yours does:
|
|
56
|
+
|
|
57
|
+
```html
|
|
58
|
+
<script type="application/ld+json">
|
|
59
|
+
{
|
|
60
|
+
"@context": "https://schema.org",
|
|
61
|
+
"@type": "Product",
|
|
62
|
+
"name": "{{ product.title }}",
|
|
63
|
+
"description": "{{ product.description | strip_html | escape }}",
|
|
64
|
+
"image": "{{ product.featured_image | img_url: '800x' }}",
|
|
65
|
+
"sku": "{{ product.selected_or_first_available_variant.sku }}",
|
|
66
|
+
"brand": {
|
|
67
|
+
"@type": "Brand",
|
|
68
|
+
"name": "{{ product.vendor }}"
|
|
69
|
+
},
|
|
70
|
+
"offers": {
|
|
71
|
+
"@type": "Offer",
|
|
72
|
+
"priceCurrency": "{{ cart.currency.iso_code }}",
|
|
73
|
+
"price": "{{ product.selected_or_first_available_variant.price | divided_by: 100.0 }}",
|
|
74
|
+
"availability": "{% if product.available %}https://schema.org/InStock{% else %}https://schema.org/OutOfStock{% endif %}",
|
|
75
|
+
"url": "{{ shop.url }}{{ product.url }}"
|
|
76
|
+
}
|
|
77
|
+
{% if product.metafields.reviews.rating %}
|
|
78
|
+
,"aggregateRating": {
|
|
79
|
+
"@type": "AggregateRating",
|
|
80
|
+
"ratingValue": "{{ product.metafields.reviews.rating.value }}",
|
|
81
|
+
"reviewCount": "{{ product.metafields.reviews.rating_count }}"
|
|
82
|
+
}
|
|
83
|
+
{% endif %}
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### BreadcrumbList (improves SERP appearance)
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<script type="application/ld+json">
|
|
92
|
+
{
|
|
93
|
+
"@context": "https://schema.org",
|
|
94
|
+
"@type": "BreadcrumbList",
|
|
95
|
+
"itemListElement": [
|
|
96
|
+
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "{{ shop.url }}" },
|
|
97
|
+
{ "@type": "ListItem", "position": 2, "name": "{{ collection.title }}", "item": "{{ shop.url }}{{ collection.url }}" },
|
|
98
|
+
{ "@type": "ListItem", "position": 3, "name": "{{ product.title }}" }
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
</script>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Title and Meta Description Formulas
|
|
107
|
+
|
|
108
|
+
### Product pages
|
|
109
|
+
```
|
|
110
|
+
Title (50-60 chars): [Product Name] — [Key Attribute] | [Brand]
|
|
111
|
+
Example: "Blue Linen Shirt — Relaxed Fit | Mariano Studio"
|
|
112
|
+
|
|
113
|
+
Meta description (120-160 chars): [Benefit]. [Key features]. [CTA with differentiator].
|
|
114
|
+
Example: "Breathable linen shirt perfect for summer. Available in 8 colors, sizes XS-XXL. Free shipping over €50."
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Collection pages
|
|
118
|
+
```
|
|
119
|
+
Title: [Collection Name] — [Category] | [Brand]
|
|
120
|
+
Example: "Men's Shirts — Linen & Cotton | Mariano Studio"
|
|
121
|
+
|
|
122
|
+
Meta description: [What's in the collection]. [Count/variety]. [Differentiator].
|
|
123
|
+
Example: "Browse our collection of 40+ men's shirts in linen, cotton, and blends. New arrivals weekly. Free returns."
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Homepage
|
|
127
|
+
```
|
|
128
|
+
Title: [Brand] — [One-line value proposition]
|
|
129
|
+
Example: "Mariano Studio — Sustainable Linen Clothing for Men"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Technical SEO Checklist
|
|
135
|
+
|
|
136
|
+
| Issue | Check | Fix |
|
|
137
|
+
|-------|-------|-----|
|
|
138
|
+
| Canonical tags | View source on product + collection URL | Should point to /products/ URL |
|
|
139
|
+
| Tag page indexation | Search site:store.com/collections inurl:t- | Add noindex or robots.txt disallow |
|
|
140
|
+
| Duplicate H1 | Check if theme puts product title in H1 twice | One H1 per page |
|
|
141
|
+
| Image alt texts | Inspect img tags on product pages | Fill via Shopify admin or bulk with metafields |
|
|
142
|
+
| Page speed | PageSpeed Insights on 3 pages | Remove heavy apps, optimize images |
|
|
143
|
+
| Sitemap | yourdomain.com/sitemap.xml | Should exist and include products + collections |
|
|
144
|
+
| robots.txt | yourdomain.com/robots.txt | Should not block /products/ or /collections/ |
|
|
145
|
+
| 404 errors | Google Search Console > Coverage | 301 redirect old URLs |
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Common Shopify SEO Mistakes
|
|
150
|
+
|
|
151
|
+
**Mistake: Disabling the Shopify sitemap**
|
|
152
|
+
The auto-generated sitemap at `/sitemap.xml` is good. Don't replace it with a custom one unless you have a specific reason. Many apps do this and break indexation.
|
|
153
|
+
|
|
154
|
+
**Mistake: Using a page builder for all pages**
|
|
155
|
+
Page builders like PageFly output custom HTML structures that often miss semantic tags (H1, structured data, canonical). Check that builder-created pages still have proper SEO markup.
|
|
156
|
+
|
|
157
|
+
**Mistake: Changing product handles**
|
|
158
|
+
`/products/old-handle` → `/products/new-handle` without a redirect = 404 = lost rankings.
|
|
159
|
+
Shopify doesn't auto-redirect when you change a handle. Add a URL redirect in admin: Settings → Policies → URL Redirects.
|
|
160
|
+
|
|
161
|
+
**Mistake: Publishing all variants as separate products**
|
|
162
|
+
One product with 5 color variants is better than 5 separate products. Consolidates link equity, avoids duplicate content.
|
|
163
|
+
|
|
164
|
+
**Mistake: Keeping "/a/collections/" filtering in index**
|
|
165
|
+
Some filter apps create `/collections/shirts?filter.p.product_type=Formal` URLs. These should be noindexed or disallowed.
|