Structured Data Guide
Shopify Multi-Currency Price Schema: PriceSpecification for AI Agents
Shopify Markets lets you sell in GBP, EUR, AUD, and dozens of other currencies — but your JSON-LD likely only exposes one. AI shopping agents read structured data to answer "how much does this cost?" When priceCurrency is missing or wrong, agents recommend your products at the wrong price to the wrong region.
Offer blocks to your Product JSON-LD — one per Shopify Market — each with priceCurrency (ISO 4217 code) and eligibleRegion (DefinedRegion with country codes). This gives AI agents currency-accurate pricing for every market you sell into. Shopify's default JSON-LD outputs only one currency; you must add multi-currency blocks manually in product.liquid.
Why Multi-Currency Schema Matters for AI Agents
AI shopping agents like ChatGPT Shopping, Perplexity, and Google's AI Overviews answer queries such as "find me a leather wallet under £50." To answer correctly, the agent needs to know: (a) your wallet's GBP price, and (b) whether you ship to the UK. Both signals come from your structured data — not from your storefront UI, which the AI crawler may never see in its localized form.
The problem with single-currency JSON-LD on a multi-currency store:
- Your JSON-LD outputs
price: 59.00, priceCurrency: USDon your primary storefront - Your UK Market charges £48.00 — but that page lives at
yourstore.com/en-gb/products/wallet - AI crawlers indexing your primary storefront see only the USD price
- When a UK shopper asks ChatGPT "leather wallets under £50," your product shows up as $59 USD — or not at all, because the agent can't determine GBP equivalence
Adding multi-currency PriceSpecification blocks to your primary product page structured data solves this: one page, all currencies, region-constrained via eligibleRegion.
Schema.org Types for Multi-Currency Pricing
PriceSpecification properties
| Property | Type | Purpose |
|---|---|---|
price |
Number | Numeric price in the currency (no currency symbol) |
priceCurrency |
Text (ISO 4217) | 3-letter currency code: USD, GBP, EUR, AUD, CAD, JPY |
eligibleRegion |
DefinedRegion / Place | Geographic scope where this price applies |
valueAddedTaxIncluded |
Boolean | true for VAT-inclusive EU/UK prices; false for US tax-exclusive |
validFrom |
DateTime | Start of price validity (for promotional prices) |
validThrough |
DateTime | End of price validity (for time-limited offers) |
eligibleQuantity |
QuantitativeValue | Minimum purchase quantity for this price to apply |
DefinedRegion properties
| Property | Type | Use |
|---|---|---|
containsPlace |
Country (ISO 3166-1 alpha-2) | Array of country codes the region includes |
addressCountry |
Text | Single country code (simpler alternative to containsPlace) |
postalCode |
Text | For postal-code-level region definition (rarely needed) |
name |
Text | Human-readable name for the region (optional but helpful) |
Multi-Currency Offer Block: Complete JSON-LD Example
This example shows a product sold in three Shopify Markets: US (USD), UK (GBP), and EU (EUR). Each market gets its own Offer with the correct priceCurrency and eligibleRegion. All three are nested inside a single Product block using the offers array.
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Premium Leather Bifold Wallet",
"sku": "WALLET-LTH-BRN-001",
"offers": [
{
"@type": "Offer",
"priceCurrency": "USD",
"price": "59.00",
"availability": "https://schema.org/InStock",
"url": "https://acme-store.com/products/premium-leather-wallet",
"eligibleRegion": {
"@type": "DefinedRegion",
"name": "North America",
"containsPlace": [
{"@type": "Country", "identifier": "US"},
{"@type": "Country", "identifier": "CA"}
]
}
},
{
"@type": "Offer",
"priceCurrency": "GBP",
"price": "48.00",
"availability": "https://schema.org/InStock",
"url": "https://acme-store.com/en-gb/products/premium-leather-wallet",
"valueAddedTaxIncluded": true,
"eligibleRegion": {
"@type": "DefinedRegion",
"name": "United Kingdom",
"containsPlace": [
{"@type": "Country", "identifier": "GB"}
]
}
},
{
"@type": "Offer",
"priceCurrency": "EUR",
"price": "55.00",
"availability": "https://schema.org/InStock",
"url": "https://acme-store.com/en-eu/products/premium-leather-wallet",
"valueAddedTaxIncluded": true,
"eligibleRegion": {
"@type": "DefinedRegion",
"name": "European Union",
"containsPlace": [
{"@type": "Country", "identifier": "DE"},
{"@type": "Country", "identifier": "FR"},
{"@type": "Country", "identifier": "NL"},
{"@type": "Country", "identifier": "IT"},
{"@type": "Country", "identifier": "ES"}
]
}
}
]
}
Shopify Liquid Template Implementation
Shopify Markets uses subfolders (/en-gb/, /en-eu/) or subdomains for localized storefronts. The cleanest approach is to output the primary market currency on your main storefront, and let each localized storefront output its own market currency. For stores that want all currencies on one page (for crawlers indexing only the primary URL), use a Liquid object or metafield approach.
Single-storefront approach: primary currency + market hints
{% comment %} product.liquid — primary storefront with market currency hints {% endcomment %}
Shopify Markets subfolder approach: per-locale storefront
When your Shopify Markets setup creates /en-gb/products/handle URLs, Google and AI crawlers index those URLs separately. Each subfolder page's Liquid context has the correct localized currency. Use localization.country and cart.currency to output the region-appropriate price in JSON-LD:
{% comment %} product.liquid — Markets-aware multi-currency JSON-LD {% endcomment %}
ISO 4217 Currency Codes for Common Shopify Markets
| Market | Currency Code | Tax Included? | Shopify Markets Subfolder |
|---|---|---|---|
| United States | USD | No (tax-exclusive) | /en/ or primary |
| United Kingdom | GBP | Yes (VAT 20%) | /en-gb/ |
| European Union | EUR | Yes (VAT 19–25%) | /en-eu/ |
| Canada | CAD | No (GST/HST separate) | /en-ca/ |
| Australia | AUD | Yes (GST 10%) | /en-au/ |
| Japan | JPY | Yes (consumption tax 10%) | /ja/ |
| Switzerland | CHF | Yes (VAT 8.1%) | /de-ch/ |
| Norway | NOK | Yes (VAT 25%) | /nb/ |
| Sweden | SEK | Yes (VAT 25%) | /sv/ |
| New Zealand | NZD | Yes (GST 15%) | /en-nz/ |
VAT-Inclusive Pricing for EU and UK Markets
EU and UK law requires consumer-facing prices to include VAT. Your GBP and EUR prices on-site are already VAT-inclusive — but if your JSON-LD outputs a raw price without valueAddedTaxIncluded: true, AI agents and comparison engines may show the price without the VAT signal, making cross-border comparison inaccurate.
The valueAddedTaxIncluded property on Offer (or PriceSpecification) is a boolean:
- Set
truefor all EU, UK, AUS, JP, NO, SE, CH market prices - Set
false(or omit) for US, CA prices where tax is calculated at checkout - Google's Merchant Center validates this field — incorrect values cause product disapprovals in Shopping campaigns
For a EUR price of €55.00 inclusive of 19% German VAT, the pre-tax equivalent is €46.22. AI agents comparing "net prices" across stores will use valueAddedTaxIncluded to normalize correctly — essential for B2B queries where buyers are VAT-registered and care about net pricing.
Common Multi-Currency Schema Mistakes
| Mistake | Effect on AI Agents | Fix |
|---|---|---|
| Single USD-only Offer on all pages | AI agents recommend USD price to UK/EU shoppers; wrong currency shown | Add per-market Offer blocks with eligibleRegion |
| priceCurrency missing entirely | Validators flag error; agents assume USD by default — wrong for non-USD stores | Always include priceCurrency with 3-letter ISO 4217 code |
| Price includes currency symbol (£48.00) | Structured data parsing error; price field must be numeric only | Use money_without_currency Liquid filter; output 48.00 not £48.00 |
| VAT-inclusive EU prices without valueAddedTaxIncluded: true | Price comparison engines and AI agents show price without VAT signal; may flag as suspicious markup | Add valueAddedTaxIncluded: true on all EU/UK/AU Offer blocks |
| Multiple Offers with duplicate eligibleRegion | Ambiguity — AI agents don't know which price applies to a region | Ensure each country appears in exactly one Offer's eligibleRegion |
| Localized storefront URL mismatch in Offer.url | Agent links shopper to wrong-currency page | Match Offer.url to the market-specific URL (e.g. /en-gb/products/handle) |
CatalogScan Multi-Currency Schema Checks
CatalogScan's AI Readiness scan checks your product JSON-LD for multi-currency completeness. The scan flags: missing priceCurrency on any Offer block, numeric price values containing currency symbols, EU/UK Offers missing valueAddedTaxIncluded, and Offers without eligibleRegion on multi-market stores. Stores enabled for Shopify Markets but outputting only a single Offer receive a Markets currency gap warning in the scan report.
Related guides: Shopify schema markup overview · Product availability structured data · International SEO hreflang for Shopify · Payment method schema
FAQ
How do AI shopping agents read multi-currency prices from Shopify stores?
AI agents read your Product JSON-LD structured data. Without multi-currency Offer blocks with priceCurrency and eligibleRegion, agents see only the primary storefront currency (usually USD). Adding per-market Offer blocks lets agents deliver region-accurate pricing recommendations without visiting your localized subfolders.
What is PriceSpecification and how does it differ from a plain price field?
PriceSpecification is a structured schema.org type that adds conditions to a price: currency, geographic eligibility, VAT inclusion, quantity thresholds, and validity dates. A plain price field is a scalar number. For multi-currency stores, PriceSpecification with priceCurrency and eligibleRegion is the correct way to express currency-constrained pricing.
Does Shopify Markets automatically output multi-currency JSON-LD?
No. Shopify's default JSON-LD outputs one Offer with the current storefront currency. You must manually add per-market Offer blocks in product.liquid, either using metafields for market prices or by leveraging the localization.country Liquid object on Markets-enabled storefronts.
What does eligibleRegion do and why does it matter?
eligibleRegion on an Offer links the price to a specific geography. Without it, an AI agent can't determine which Offer applies to a given shopper's region. Use a DefinedRegion with containsPlace: [Country identifiers] to map each Offer to its Shopify Market's country list.
Should EU and UK prices include valueAddedTaxIncluded: true?
Yes. EU and UK consumer law requires displayed prices to include VAT. Set valueAddedTaxIncluded: true on all GBP and EUR Offer blocks. This lets AI agents and comparison engines normalize prices correctly and avoids Google Merchant Center validation errors for tax-inclusive markets.