Sell More Using Structured Data in Your Vendure Webshop

Niels null

Niels

6 min read , ~4 ~hours to implement

Learn how to boost e-commerce sales with structured data in Vendure. Step-by-step recipe-style guide, including JSON-LD examples and best practices for product pages.

Sell More Using Structured Data in Your Vendure Webshop

Sell More Using Structured Data in Your Vendure Webshop

Why Structured Data Matters

We all want to sell more through our online stores, and everyone says structured data is more important than ever, especially with LLMs. As if structured data wasn’t useful a couple of years ago! I’m not going to go too much into that or pretend this guide is a silver bullet, but communicating to search engines what you sell or talk about is very helpful. It always has been and always will.

Structured data helps Google understand whether you have something people are looking for, and it helps you ensure that search engines correctly understand your products and content.

We’re not going to start by defining structured data, you probably already know what it is or can check any SEO guide. Here, we focus specifically on e-commerce and using JSON-LD, nothing else.

Ingredients

  • Access to a developer – Someone who can help you implement structured data if you cannot implement it yourself. Don't make developers grumpy; they appreciate clear instructions!
  • Google’s Rich Result Tester or Schema Markup Validator – Keep this open to test your structured data.
  • Understanding your tech stack – You’ll want to automate the JSON-LD for all pages. In our case, we use a headless setup with Vendure, AstroJS, and Directus CMS.

Preparation: Mise en Place

Before you start, audit your existing pages and products. Which pages are most important for SEO and conversion? Collect product data like:

  • Titles
  • Prices
  • Descriptions
  • Availability
  • Reviews
  • Images

This is your raw material for structured data. Think of it as washing and chopping your ingredients before cooking.

Vendure Users: Leverage Your Product Fields

If you’re running your shop on Vendure, the easiest and most reliable way to populate your JSON-LD is to reuse the existing product fields from Vendure. Most of the information you need, like name, description, price, images, and variants, is already available in the GraphQL schema.

By pulling directly from these fields, you ensure that your structured data is always up-to-date and consistent with your product catalog. No need for duplicate data entry or manual updates!

A great resource to explore the available product fields is Vendure’s official documentation on the GraphQL Product object:
Vendure GraphQL API: Product Object

Instructions: Adding JSON-LD to Product Pages

  1. Generate a base template – Include the necessary fields: name, price, SKU, availability, and reviews.
  2. Map product fields to schema.org properties – Ensure everything corresponds to the correct JSON-LD property.
  3. Automate injection via your tech stack – Let Vendure + Astro handle adding the JSON-LD to each product page.
  4. Test each page – Use Google’s Rich Results Test or Schema Markup Validator to ensure your structured data works correctly.

Generate a base template

Before you start, create a template that defines which fields will appear in your JSON-LD. At minimum, include:

  • name – The product’s title
  • description – Short, descriptive text
  • price – Numerical value of the product
  • sku – Unique stock keeping unit
  • availability – In stock, out of stock, etc.
  • images – At least one product image URL
  • aggregateRating – If available

Map Product Fields to schema.org Properties

Once your template is ready, you need to connect each product field to the corresponding schema.org property. This ensures Google interprets your data correctly.

Handling Variants in Vendure + JSON-LD

Are you selling products in different weights, sizes, or colors? In Vendure, those are variants (each with its own sku, price, and stock), exposed via the GraphQL API as variants (aka productVariants).

In structured data, the clearest, Google-approved way to represent this on one URL is to model the parent as a ProductGroup and each option as a Product under hasVariant, with a backlink from the child using isVariantOf.
Add variesBy to tell Google which dimensions change (e.g. "weight", "size", "color").

Why this approach?

So each entry in the feed is a variant. It groups everything cleanly, prevents duplicate or conflicting markup when all options live on the same page, and aligns with Google’s variant guidance introduced in 2024.

Vendure → JSON-LD Variant Mapping

Vendure (GraphQL) JSON-LD Property Notes
variant.product.name ProductGroup.name Parent product title.
variant.product.slug → page URL ProductGroup.url / @id Use the canonical product URL as the group’s url and @id.
variant.product.description ProductGroup.description General description shared by variants.
variant.product.featuredAsset ProductGroup.image One or more absolute image URLs.
variant.name Product.name (inside hasVariant) Variant-specific display name.
variant.sku sku Unique per variant (Vendure treats each variant as the actual purchasable SKU).
variant.price* + variants[].currencyCode offers.price + offers.priceCurrency Price belongs in an Offer; currency must be an ISO-4217 code (e.g. EUR). Vendure models money and currencies explicitly.
Stock signal (e.g. variant.stockOnHand > 0) offers.availability Use the Schema.org URLs like https://schema.org/InStock or https://schema.org/OutOfStock.
Distinguishing attributes (e.g. weight, color) variesBy (parent) + additionalProperty on each variant Use PropertyValue for arbitrary attributes; for common ones, you may use color, size, etc.

Example

{
  "@context": "https://schema.org",
  "@type": "ProductGroup",
  "name": "Example Product",
  "description": "Available in multiple weights.",
  "url": "https://example.com/product/example-product",
  "image": [
    "https://example.com/images/example-500g.jpg",
    "https://example.com/images/example-1kg.jpg"
  ],
  "variesBy": ["weight"],
  "hasVariant": [
    {
      "@type": "Product",
      "name": "Example Product 500g",
      "sku": "EX500G",
      "isVariantOf": {
        "@type": "ProductGroup",
        "@id": "https://example.com/product/example-product"
      },
      "offers": {
        "@type": "Offer",
        "price": "9.99",
        "priceCurrency": "EUR",
        "availability": "https://schema.org/InStock"
      },
      "additionalProperty": [
        { "@type": "PropertyValue", "propertyID": "weight", "value": "500 g" }
      ]
    },
    {
      "@type": "Product",
      "name": "Example Product 1kg",
      "sku": "EX1KG",
      "isVariantOf": {
        "@type": "ProductGroup",
        "@id": "https://example.com/product/example-product"
      },
      "offers": {
        "@type": "Offer",
        "price": "17.99",
        "priceCurrency": "EUR",
        "availability": "https://schema.org/InStock"
      },
      "additionalProperty": [
        { "@type": "PropertyValue", "propertyID": "weight", "value": "1 kg" }
      ]
    }
  ]
}

Automate Injection via Vendure

Manually adding JSON-LD to every product page is tedious and error-prone. Automate it using your stack, in our case it looks like this:

  • Vendure + Astro: Fetch product data via GraphQL and inject JSON-LD dynamically when generating pages, as mentioned above.
  • Headless CMS (e.g., Directus): Store custom fields and merge them into your JSON-LD template.
  • Server-Side Rendering: Render JSON-LD directly into the <head> during page generation.

Testing is Essential

Always test with:

Think of it as tasting your dish before serving it to guests, don’t serve broken markup!

Serving Suggestions: Next Steps

After implementing structured data:

  • Monitor performance in Google Search Console
  • Experiment with other schemas like FAQPage or HowTo for content pages

Chef’s Tips: Common Mistakes to Avoid

  • Always check JSON-LD syntax; one missing comma can break your markup

Example: Eifelgold Lavameel Structured Data

Here’s an exact JSON-LD example for the product Eifelgold Lavameel from Wormenkwekerij Wasse:


```json
<script type="application/ld+json">
{
  "@context": "https://schema.org/",
  "@type": "Product",
  "name": "Eifelgold lavameel 20 kg",
  "image": "https://storage.googleapis.com/shops-wkw-assets-prod/presets/0b/lavameel-20kg-22140_preview.webp",
  "description": "Bestel Eifelgold lavameel van topkwaliteit. 100% natuurlijk, rijk aan mineralen en perfect voor een gezonde moestuin. Snelle levering!",
  "offers": {
    "@type": "Offer",
    "price": "19.90",
    "priceCurrency": "EUR",
    "priceValidUntil": "2026-10-02T11:30:17+00:00",
    "availability": "http://schema.org/InStock"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.9",
    "bestRating": "5",
    "ratingCount": "29"
  }
}
</script>

This approach makes it easy to automate JSON-LD generation for all your products, keeping your structured data accurate and fully optimized for search engines. Please feel free to reach out if this made your selected developer, or yourself grumpy. We'll be able to implement it for you!

Enjoy these fun sources as well:

Google Variants SD

Vendure GraphQL API Types

Get in touch