Product Schema Setup for E-commerce Stores
Why Google doesn't show the product price in search results?
You've written a great description, uploaded photos, set a fair price — but in search results you still see only a blue link without extra information. The reason is missing microdata. Google simply doesn't know the product has a price, discount, or rating. Product Schema is a JSON-LD script on the product page that explicitly tells the search engine this data. Without it, Google has to guess and often gets it wrong. The result is a regular snippet instead of a rich one. According to research, rich snippets increase CTR by 15–30%, and in our projects the average increase was 22%. That means every fifth extra click is free traffic, saving your contextual advertising budget.
What is Product Schema and how does it work?
It's structured data following the Schema.org standard placed on the product page. Google uses it to generate rich snippets. Microdata is invisible to users, but for search robots it's an instruction: "Here's what this product is, how much it costs, if it's in stock, and what buyers think."
Here's a complete JSON-LD block for a laptop:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "ASUS ROG Strix G16 Laptop",
"sku": "ROG-G16-RTX4070",
"gtin13": "4711081694342",
"description": "Gaming laptop with RTX 4070, latest gen Intel Core i7, and 16-inch 240Hz display.",
"brand": {
"@type": "Brand",
"name": "ASUS"
},
"image": [
"https://example.ru/images/rog-strix-1.jpg",
"https://example.ru/images/rog-strix-2.jpg"
],
"offers": {
"@type": "Offer",
"url": "https://example.ru/notebooks/asus-rog-strix-g16",
"priceCurrency": "RUB",
"price": "149990",
"priceValidUntil": "one month from publication date",
"itemCondition": "https://schema.org/NewCondition",
"availability": "https://schema.org/InStock",
"seller": {
"@type": "Organization",
"name": "TechStore"
}
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.7",
"bestRating": "5",
"worstRating": "1",
"reviewCount": "47"
},
"review": [
{
"@type": "Review",
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"author": { "@type": "Person", "name": "Alex K." },
"datePublished": "recently",
"reviewBody": "Great laptop for gaming, quiet and cool under moderate load."
}
]
}
Note: price is passed as a string without currency, availability uses URL schema. Google does not accept "price": "149 990" or "availability": "in stock". Only strict syntax. JSON-LD markup is 10 times easier to implement than RDFa and fully supported by Google.
How to markup products with variations (size, color)
If a product has modifications — different shoe sizes or cover colors — use the ProductGroup type. Inside hasVariant list all options with their own prices and availability.
{
"@context": "https://schema.org",
"@type": "ProductGroup",
"name": "Nike Air Max 90 Sneakers",
"hasVariant": [
{
"@type": "Product",
"name": "Nike Air Max 90 White — size 42",
"offers": { "@type": "Offer", "price": "8990", "availability": "InStock" },
"additionalProperty": [
{ "@type": "PropertyValue", "name": "Color", "value": "White" },
{ "@type": "PropertyValue", "name": "Size", "value": "42" }
]
}
]
}
This guarantees that Google will show in the snippet exactly the variant the user is viewing. For products with many variations (e.g., clothing with sizes from XS to XXL) this approach is mandatory — without markup Google often shows a generic page, reducing clickability.
Dynamic generation in Laravel: a practical example
Manually marking up every page is impractical. On one project with 5000 products, we automated generation via a service class. Here's how it looks:
class ProductSchemaGenerator
{
public function generate(Product $product): array
{
return [
'@context' => 'https://schema.org',
'@type' => 'Product',
'name' => $product->name,
'sku' => $product->sku,
'description' => $product->meta_description ?? strip_tags($product->description),
'image' => $product->images->pluck('url')->toArray(),
'brand' => ['@type' => 'Brand', 'name' => $product->brand->name],
'offers' => [
'@type' => 'Offer',
'price' => number_format($product->price / 100, 2, '.', ''),
'priceCurrency' => 'RUB',
'availability' => $product->in_stock
? 'https://schema.org/InStock'
: 'https://schema.org/OutOfStock',
'priceValidUntil' => now()->addMonth()->format('Y-m-d'),
'seller' => ['@type' => 'Organization', 'name' => config('app.name')]
],
'aggregateRating' => $product->reviews_count > 0 ? [
'@type' => 'AggregateRating',
'ratingValue' => number_format($product->average_rating, 1),
'reviewCount' => $product->reviews_count
] : null
];
}
}
Key points: price is passed in kopecks (divided by 100), price valid for one month, aggregateRating added only if reviews exist. This code easily integrates into any Blade template or Vue component. A similar approach can be implemented on any platform — WordPress, OpenCart, Bitrix.
How to avoid errors when setting up microdata?
Even experienced developers make typical mistakes. Here's a table of the most common errors and their consequences:
| Error | Consequence | Solution |
|---|---|---|
Empty price or availability fields |
Markup ignored | Remove the property if no data |
| Price mismatch between page and JSON-LD | Google doesn't use schema | Sync data through a single source |
reviewCount: 0 when no reviews |
Reduced trust in markup | Remove aggregateRating entirely |
| Incorrect price format (with currency symbol) | Validation error | Pass number as string without currency |
Additionally, use Google's Rich Results Test to check each page before publishing. This helps identify issues before they appear in search results.
How long does setup take and what's included?
Implementation time depends on catalog complexity. Estimated timelines:
| Project Type | Duration | Description |
|---|---|---|
| Catalog up to 100 products, no variations | 1 day | Basic JSON-LD generation, manual insertion |
| Catalog up to 5000 products with simple variations | 2-3 days | Service class development, testing |
| Large store (10,000+ products, multiple variations) | 3-5 days | Full automation, ProductGroup, CMS integration |
What's included: development of a generator on your stack (Laravel, Vue/React, any CMS), implementation on all product page types, testing via Google tools, and documentation for markup maintenance. We guarantee correct operation for one month after implementation. Investment in microdata pays off through CTR growth in the first months.
Our experience: over 7 years specializing in e-commerce SEO markup, implemented Product Schema for 120+ online stores. Average CTR increase after implementation — 22%.
Request a consultation — we'll evaluate your project and propose the optimal solution. Get a free audit of your current microdata: we'll find errors and show you how to improve.







