Optimization Guide

Shopify Product Customization Structured Data: Engraving, Monogram & Personalization JSON-LD for AI Shopping Agents

AI shopping agents answer "personalized gifts for dad" and "engravable watches under $200" by reading structured data — not your storefront UI. If your engraving options live only in line-item property dropdowns, every AI shopping agent treats your customizable product as a commodity item with no personalization feature at all.

TL;DR Use additionalProperty on the Product type to declare customization options (engraving, monogram, embroidery). Include propertyID, option name, character limits, and available formats. Store configuration in Shopify product metafields so merchandising can update options without theme code changes. If engraving carries a surcharge, declare it explicitly — AI agents surface total cost, not base price.

Why Customization Signals Are Invisible Without Structured Data

Shopify line item properties — the standard mechanism for collecting engraving text or monogram initials at checkout — are entirely invisible to search crawlers and AI shopping agents. They live in the storefront JavaScript, not in the product page HTML or the products.json feed. This means a watch with a prominent "Add engraving — $15" input field looks structurally identical to a non-engravable watch in every AI shopping agent's product index.

The business consequence is significant. Gift and personalization queries are high-intent and often have lower price sensitivity — a user who types "personalized leather wallet for husband" is further down the purchase funnel than one who types "men's leather wallet." These queries route disproportionately to products with machine-readable personalization signals.

AI shopping agent query types that require customization signals

Query type Example Required signal
Personalized gift intent "personalized anniversary gift jewelry" customizationOptions additionalProperty present
Engravable product filter "engravable watches under $200" engravingAvailable: true additionalProperty
Monogram search "monogrammed leather bag wedding gift" monogramOptions or initialsCustomization property
Text personalization "custom text phone case with name" customTextAvailable + maxCharacters declared
Rush personalization "engravable gift ships in 2 days" Customization + shippingDetails with processing time

Where the gap shows up in Shopify's default JSON-LD

Shopify's native product JSON-LD generates a Product block with name, description, image, and offers. It does not include any line item property metadata, customization option declarations, or personalization feature flags — even if your product description says "add engraving at checkout" in large bold text.

Shopify default (no customization signal)
{
  "@type": "Product",
  "name": "Sterling Silver Pendant",
  "description":
    "Add engraving at checkout...",
  "offers": {
    "@type": "Offer",
    "price": "85.00"
  }
}
With customization structured data
{
  "@type": "Product",
  "name": "Sterling Silver Pendant",
  "additionalProperty": [{
    "@type": "PropertyValue",
    "propertyID": "engravingAvailable",
    "name": "Engraving",
    "value": "true"
  },{
    "@type": "PropertyValue",
    "propertyID": "engravingMaxChars",
    "name": "Max characters",
    "value": "20"
  }]
}

Customization JSON-LD Patterns

Minimum viable customization markup

The most impactful single addition is a boolean engravingAvailable additionalProperty. AI agents can use this as a filter condition even without character limit or font details:

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Sterling Silver Locket Pendant",
  "description": "Handcrafted sterling silver locket. Add engraving to the back — up to 20 characters.",
  "additionalProperty": [
    {
      "@type": "PropertyValue",
      "propertyID": "engravingAvailable",
      "name": "Engraving available",
      "value": "true"
    },
    {
      "@type": "PropertyValue",
      "propertyID": "engravingMaxChars",
      "name": "Max engraving characters",
      "value": "20"
    }
  ],
  "offers": {
    "@type": "Offer",
    "price": "85.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock"
  }
}

Full engraving product with surcharge and font options

For products where engraving carries a surcharge, declare the fee explicitly. Use priceSpecification to show the base price and engraving add-on separately:

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Personalized Leather Passport Holder",
  "description": "Full-grain leather passport holder. Choose from 3-letter monogram or custom text engraving. Debossed or foil stamp finish.",
  "material": "Full-grain leather",
  "additionalProperty": [
    {
      "@type": "PropertyValue",
      "propertyID": "customizationOptions",
      "name": "Customization types",
      "value": "Monogram (3 letters), Custom text (up to 15 characters)"
    },
    {
      "@type": "PropertyValue",
      "propertyID": "engravingFinish",
      "name": "Finish options",
      "value": "Debossed, Gold foil stamp, Silver foil stamp"
    },
    {
      "@type": "PropertyValue",
      "propertyID": "engravingSurcharge",
      "name": "Personalization fee",
      "value": "12.00",
      "unitCode": "USD"
    },
    {
      "@type": "PropertyValue",
      "propertyID": "productionLeadTime",
      "name": "Personalization lead time (business days)",
      "value": "2"
    }
  ],
  "offers": {
    "@type": "Offer",
    "price": "65.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "priceSpecification": [
      {
        "@type": "PriceSpecification",
        "price": "65.00",
        "priceCurrency": "USD",
        "name": "Base price (without personalization)"
      },
      {
        "@type": "PriceSpecification",
        "price": "77.00",
        "priceCurrency": "USD",
        "name": "Price with personalization"
      }
    ]
  }
}

Embroidery and textile customization

For apparel with embroidery options, include thread color constraints and size limits. The customizationArea property helps AI agents answer location-specific queries ("embroidered chest logo"):

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Classic Cotton Tote Bag",
  "additionalProperty": [
    {
      "@type": "PropertyValue",
      "propertyID": "embroideryAvailable",
      "name": "Embroidery available",
      "value": "true"
    },
    {
      "@type": "PropertyValue",
      "propertyID": "customizationArea",
      "name": "Embroidery placement options",
      "value": "Front center, Front left chest, Back top center"
    },
    {
      "@type": "PropertyValue",
      "propertyID": "embroideryMaxChars",
      "name": "Max embroidery characters",
      "value": "30"
    },
    {
      "@type": "PropertyValue",
      "propertyID": "embroideryThreadColors",
      "name": "Thread color count",
      "value": "18"
    },
    {
      "@type": "PropertyValue",
      "propertyID": "minimumOrderQuantity",
      "name": "Minimum quantity for embroidery",
      "value": "1"
    }
  ],
  "offers": {
    "@type": "Offer",
    "price": "28.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock"
  }
}

Shopify Liquid Implementation

Store customization configuration in product metafields so merchandising teams can enable or update options without theme code changes. This approach also makes the data available to your JSON-LD template via Liquid variables.

Recommended metafield structure

Namespace.keyTypeExample valuePurpose
custom.engraving_available Boolean true Master switch for engraving feature in JSON-LD
custom.engraving_max_chars Integer 20 Character limit for AI agent surfacing
custom.engraving_surcharge_usd Number (decimal) 12.00 Engraving fee for price specification
custom.engraving_options Single line text Monogram (3 letters), Custom text (15 chars) Human-readable option description
custom.engraving_lead_days Integer 2 Production time in business days

Liquid snippet for product JSON-LD

{% assign custom = product.metafields.custom %}
{% assign base_price = product.price | money_without_currency | remove: ',' %}
{% assign has_engraving = custom.engraving_available %}

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": {{ product.title | json }},
  "description": {{ product.description | strip_html | truncate: 500 | json }},
  {% if has_engraving %}
  "additionalProperty": [
    {
      "@type": "PropertyValue",
      "propertyID": "engravingAvailable",
      "name": "Engraving available",
      "value": "true"
    }
    {% if custom.engraving_max_chars != blank %}
    ,{
      "@type": "PropertyValue",
      "propertyID": "engravingMaxChars",
      "name": "Max engraving characters",
      "value": {{ custom.engraving_max_chars | json }}
    }
    {% endif %}
    {% if custom.engraving_options != blank %}
    ,{
      "@type": "PropertyValue",
      "propertyID": "customizationOptions",
      "name": "Customization types",
      "value": {{ custom.engraving_options | json }}
    }
    {% endif %}
    {% if custom.engraving_surcharge_usd != blank %}
    ,{
      "@type": "PropertyValue",
      "propertyID": "engravingSurcharge",
      "name": "Personalization fee",
      "value": {{ custom.engraving_surcharge_usd | json }},
      "unitCode": "USD"
    }
    {% endif %}
    {% if custom.engraving_lead_days != blank %}
    ,{
      "@type": "PropertyValue",
      "propertyID": "productionLeadTime",
      "name": "Personalization lead time (business days)",
      "value": {{ custom.engraving_lead_days | json }}
    }
    {% endif %}
  ],
  {% endif %}
  "offers": {
    "@type": "Offer",
    "price": {{ base_price | json }},
    "priceCurrency": {{ cart.currency.iso_code | json }},
    "availability": "https://schema.org/InStock"
    {% if has_engraving and custom.engraving_surcharge_usd != blank %}
    {% assign personalized_price = product.price | plus: custom.engraving_surcharge_usd | times: 100 | divided_by: 100.0 %}
    ,"priceSpecification": [
      {
        "@type": "PriceSpecification",
        "price": {{ base_price | json }},
        "priceCurrency": {{ cart.currency.iso_code | json }},
        "name": "Base price (without personalization)"
      },
      {
        "@type": "PriceSpecification",
        "price": {{ personalized_price | money_without_currency | remove: ',' | json }},
        "priceCurrency": {{ cart.currency.iso_code | json }},
        "name": "Price with personalization"
      }
    ]
    {% endif %}
  }
}

Customization Type Reference

Customization type Primary additionalProperty Supporting properties Typical surcharge
Engraving (text) engravingAvailable: true maxChars, font options, finish $10–$25
Monogram (initials) monogramAvailable: true letterCount (2 or 3), style (block/script/interlocked) $8–$20
Embroidery embroideryAvailable: true placement options, thread colors, maxChars $15–$40
Custom photo print photoCustomizationAvailable: true accepted formats (JPEG/PNG), min resolution (DPI) $0 (base product price includes it)
Custom text (apparel) customTextAvailable: true maxChars, available positions, font families $5–$15
Laser etching laserEtchingAvailable: true surface material constraints (metal/glass/wood) $12–$30

Common Mistakes to Avoid

Mistake AI agent consequence Fix
Customization described only in product description text Not parseable as a filter signal; product excluded from personalization queries Add additionalProperty array with explicit boolean flags
No surcharge declared in structured data AI agent surfaces base price; post-click price surprise reduces conversion Add engravingSurcharge PropertyValue and/or priceSpecification with/without personalization
Same metafield used for Shopify UI and JSON-LD without format guard Blank or null value in structured data if metafield not set Use Liquid != blank guards before each PropertyValue injection
productionLeadTime omitted for personalized products AI agent cannot answer "arrives before Saturday?" for customized orders Add productionLeadTime in business days and wire to OfferShippingDetails
Customization options on parent product only, not variant level AI agent doesn't know that only specific sizes or colors are engravable If engraving applies per-variant, add additionalProperty at variant offer level using AggregateOfferOffer nesting

Implementation Checklist

Frequently Asked Questions

What schema.org property should I use to mark a product as customizable?

Use additionalProperty on the Product type with propertyID: "engravingAvailable" and value: "true". This is not a native schema.org property, but AI shopping agents parse additionalProperty arrays and can use the boolean flag as a filter condition for personalization queries. Pair it with customizationOptions, engravingMaxChars, and engravingSurcharge for a complete signal.

Can AI shopping agents surface engravable products for gift queries?

Yes — when AI shopping agents process queries like "personalized gifts for dad" or "engravable watches under $200", they look for customization signals in structured data. Products with explicit engravingAvailable or customizationOptions additionalProperty entries are more likely to be surfaced than products that only mention customization in free-text descriptions.

How do I declare customization options in Shopify without an app?

Shopify line item properties collect customization input at checkout, but they're invisible to structured data. The cleanest approach for JSON-LD is to store customization metadata in product metafields (custom.engraving_available, custom.engraving_max_chars) and inject them into your product.liquid JSON-LD template with Liquid conditionals. This separates customization configuration from theme code.

Should I add a price surcharge for engraving in structured data?

Yes. If engraving carries a surcharge, declare it using Offer.priceSpecification with a named PriceSpecification for the base price and another for the personalized price. Alternatively, use additionalProperty with propertyID: "engravingSurcharge" and a numeric value. This reduces post-click price surprise and improves conversion quality from AI shopping recommendations.

What is the difference between product variants and customization options in structured data?

Variants (size, color) map to Offer-level structured data — each variant has its own price, availability, and SKU. Customization options (engraving text, monogram initials) are input fields collected at line-item time and should not create separate variants. In structured data, declare variants as AggregateOffer and customization options as additionalProperty on the parent Product.

Related Resources