Product schema generator
- Runs on your device
- Nothing uploaded
- Free, no sign-up
Everything is built in your browser. Nothing you type is sent anywhere. The checks follow Google's Product documentation as of October 2026, and a clean result here does not promise a rich result.
Worked example: one mug, both Google features
A small pottery shop sells a 12 oz mug for $28. It has one product photo, a UPC from the barcode sticker, and 38 reviews shown under the product. The form gets:
- Name: Kestrel 12 oz Stoneware Mug, image URL, a two sentence description, page URL
- Brand Kestrel Pottery, SKU KP-MUG-12-OAT, GTIN 012345678905
- Price 28.00, currency typed as lowercase usd, In stock, New, valid until 2027-06-30
- Average rating 4.7 out of 5 from 38 reviews
Output:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Kestrel 12 oz Stoneware Mug",
"image": "https://example.com/img/kestrel-mug-1x1.jpg",
"description": "Wheel-thrown stoneware mug with a speckled oat glaze. Holds 12 oz.",
"url": "https://example.com/shop/kestrel-mug",
"brand": {
"@type": "Brand",
"name": "Kestrel Pottery"
},
"sku": "KP-MUG-12-OAT",
"gtin12": "012345678905",
"offers": {
"@type": "Offer",
"url": "https://example.com/shop/kestrel-mug",
"price": 28,
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition",
"priceValidUntil": "2027-06-30"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": 4.7,
"reviewCount": 38
}
}
Three things happened that you would not see by reading the form. The 12 digit GTIN went into gtin12, after its check digit passed. The lowercase currency came out as USD. And because the rating uses the default 1 to 5 scale, bestRating and worstRating were left out, which is what Google assumes anyway. The one tip left was to add 4x3 and 16x9 crops of the photo. Load the sample product above to see the same mug with shipping, returns and a single review added.
Merchant listing or product snippet: what each needs
Google reads the same Product markup for two different features. A product snippet is the star rating and price line under a normal search result, and it suits review pages too. A merchant listing is the shopping style result, for pages where someone can actually buy the thing. The table is from Google's Product documentation as of October 2026.
| Property | Merchant listing | Product snippet | Notes |
|---|---|---|---|
name | Required | Required | The product name as shown on the page. |
image | Required | Not required | Absolute URLs. Several crops help. |
offers.price | Required, above 0 | One of offers, review or aggregateRating | 0 is fine for a snippet, not for a listing. |
offers.priceCurrency | Required | Recommended | Three letter ISO 4217 code. |
offers.availability | Recommended | Recommended | Pick one value, such as InStock or PreOrder. |
offers.priceValidUntil | Recommended | Recommended | A past date can get the result dropped. |
aggregateRating | Recommended | One of the three | Must reflect reviews visible on the page. |
review | Recommended | One of the three | Author must be a real person or team name. |
brand.name | Recommended | Not listed | One brand per product. |
gtin, mpn, sku | Recommended | Not listed | GTIN is digits only. SKU without spaces. |
shippingDetails | Recommended | Not listed | Cost, destination country and delivery days. |
hasMerchantReturnPolicy | Recommended | Not listed | Store wide policies are the preferred route. |
A merchant listing also needs a real Offer. An AggregateOffer with a low and high price only works for snippets, which is why this generator always writes a single Offer.
Price, currency and dates that trip people up
Most broken Product markup is not missing a field. It has a field in the wrong shape.
- Prices are bare numbers. "$28", "28 USD" and "1,299.00" all read badly. The generator strips symbols, treats a lone comma before one or two digits as a decimal comma (24,99), and drops other commas as thousands separators. It tells you when it did.
- Currencies are codes, not symbols. "$" could be several different currencies. Type USD, CAD or AUD. Common slips like UK for GBP are fixed with a warning.
- One price per page. If the same product shows in two currencies, Google wants a separate URL for each one.
- Dates go stale.
priceValidUntilis the one field that breaks on its own. If you set it, put a reminder in your calendar, or leave it out for prices with no end date. - The markup has to match the page. If a sale ends and the page says $34 while the JSON-LD still says $28, Google treats the markup as wrong.
Shipping and returns: offer level or store level
Google has been nudging shops toward setting shipping and return rules once, in Merchant Center or in Organization markup on the site, rather than repeating them in every product. Offer level fields still work, and they override the store rules for that one product. Use them when a product really is different: a bulky item with its own shipping cost, or a final sale item with no returns.
When you do add shipping here, the generator writes all three parts Google requires: a cost (0 means free), a destination country and a delivery time made of handling days, transit days or both. Delivery days are whole numbers. The shipping cost always uses the offer currency, so the two cannot drift apart.
Ratings and reviews you are allowed to mark up
Stars are the part people want most and the part most likely to get a site in trouble. Only mark up reviews that a visitor can read on the same page. Do not copy ratings from Amazon or another site, and do not write a review in your own shop's name. The single review field is for a real customer or an editorial review, and its author should be a name like Dana Whitfield, not "Best mug 2026" or "20% off today". If you have many reviews, add the average with the count, and leave the individual ones in your HTML.
What this generator will not do
- It builds one product with one offer. Product variants (sizes and colors as a
ProductGroup) and price ranges are not covered. - It does not fetch your page, so it cannot see whether the price or stock on the page match what you typed.
- It cannot check that an image URL loads, that a GTIN is registered to your brand, or that your reviews are real.
- Fields such as
material,size,pattern, energy labels and member prices are left out. Add them by hand if you need them. - Google's Rich Results Test is still the last word. A clean result here means the obvious mistakes are gone, not that a rich result will appear.
Product schema questions
Do I need offers, a review and a rating all at once?
No. A product snippet needs name plus at least one of offers, review or aggregateRating. A merchant listing needs name, image and an Offer with a price above 0. Ratings are optional for both, and you should only add them when real reviews are visible on the page.
Should the price be a number or a string?
Google accepts either, as long as it reads as a plain number. This generator outputs a number. What breaks things is formatting: a currency symbol, a space, or a thousands separator like 1,299.00 in the price field.
Which GTIN property should I use?
The one that matches the barcode length: gtin8, gtin12 for a UPC, gtin13 for an EAN, or gtin14. Type the digits and the generator picks the property and checks the last digit. Google wants the digits only, not a URL form.
Do I have to add shipping and return details to every product?
No. Both are optional. Google now recommends setting shipping and return policies once for your whole store, through Merchant Center or Organization markup, and using the offer level fields only when one product differs from the rest.
Can I put the generated JSON-LD in with JavaScript?
You can, and Google can render it, but for shopping results Google says markup in the initial HTML is more reliable, because prices and stock change often and rendered pages get crawled less often. Paste it into the page template if you can.
Why did my product rich result disappear after a while?
Common causes are a priceValidUntil date that has passed, a price or stock value in the markup that no longer matches the page, or reviews that are not actually shown on the page. Re-run the page through a validator after any price change.