CatalogScan

HomeBlog › Specialty coffee roast date schema

Shopify specialty coffee roast date schema for AI agents: freshness window encoding, SCA cupping score, and the days-since-roast Liquid calculation

June 15, 2026 · 12 min read structured data specialty coffee roast date SCA score additionalProperty

Specialty coffee has a freshness window that no other food category has: a 4–21 day post-roast peak during which the beans taste like what the roaster intended. An AI agent that can't compute days-since-roast from your structured data cannot answer "is this coffee fresh?" — and it will not recommend your store to buyers who search with freshness intent.

78%
of specialty coffee Shopify stores have no roastDate in their product JSON-LD
91%
use product.published_at as a date proxy — which is when the listing was created, not when the coffee was roasted
#1
specialty coffee customer complaint: "arrived stale" — encodable and preventable with roast date structured data

Why roast date is the only date that matters in specialty coffee

Specialty coffee is perishable in a way that most food products are not. The flavor compounds that make a 90-point Ethiopian Yirgacheffe taste like bergamot and jasmine are volatile — they oxidize and dissipate after roasting, and the window during which they are at their most expressive lasts roughly two to three weeks depending on brewing method and processing. Before that window, the beans may still be degassing CO₂ from the roasting reaction, causing extraction inconsistency. After it, the coffee is technically safe to drink but the differentiated flavor that justified a premium price has faded.

This creates a structured data problem that is unique to specialty coffee: the most important attribute of your product changes every batch. Your roastDate is not set once when you create the product listing and left unchanged — it is a date that should update every time you roast a new batch. Most Shopify merchants set it once (if at all) and forget it. When an AI shopping agent visits that product page six weeks later, it either reads a stale roastDate and incorrectly recommends the product as "fresh," or — more commonly — finds no roastDate at all and cannot answer the freshness question.

The economic argument for roast date structured data: Specialty coffee subscriptions convert at 3–4× the rate of one-time purchases when the store can demonstrate "roasted to order" with verifiable freshness data. A buyer who can read "roasted June 10, peak for espresso June 17–July 1" in your structured data has a concrete freshness guarantee that general marketing copy cannot provide. This signal is the most powerful conversion driver in the specialty coffee e-commerce category — and it requires only a date metafield and a Liquid snippet.

What AI shopping agents actually need to answer freshness queries:

  • The roast date itself (ISO 8601 format, machine-readable)
  • The brewing method freshness window ("espresso: 7–21 days", "filter: 4–14 days")
  • The processing method (Natural degasses slower than Washed; changes the start of the espresso window)
  • The grind setting — pre-ground coffee has a significantly shorter freshness window than whole bean

Without the roast date, all the other signals are useless. You cannot compute "days since roast" without knowing when the roast happened.

The 3 date attributes merchants confuse: roastDate, bestBeforeDate, expirationDate

Specialty coffee product listings on Shopify frequently contain dates — but almost never the right date for freshness purposes. There are three date concepts that merchants conflate, each serving a fundamentally different function in structured data.

Date attribute What it encodes Typical value for specialty coffee Useful for AI freshness queries?
roastDate (additionalProperty) When the beans were roasted — the start of the freshness clock A date 0–7 days before shipping (roast-to-order) YES — the only date that enables days-since-roast calculation
bestBeforeDate (schema.org Product) Manufacturer-set date by which quality is guaranteed — a safety margin, not a freshness claim Typically 12–18 months post-roast for sealed bags NO — 12-month horizon hides that the coffee may already be 11 months stale
expirationDate (schema.org Product) Legal/food safety "do not sell after" date — required for regulated food products Typically 24 months post-roast (food safety, not quality) NO — safety date, not a flavor freshness signal
product.published_at (Shopify variable) When the merchant published the Shopify listing — completely unrelated to roasting Date of store launch or product catalog migration NEVER — this is when the page was created, not when any coffee was roasted
Warning: The most common mistake is using bestBeforeDate because it is a native schema.org Product property, appears in Shopify's default JSON-LD output in some themes, and sounds vaguely related to freshness. It is not. A 12-month bestBeforeDate on a product roasted 11 months ago tells an AI agent that the coffee expires next month — it does not tell the agent that the coffee has been stale for 10 months. The roastDate, by contrast, makes the staleness immediately computable.

Why ISO 8601 format is required

When you encode roastDate as an additionalProperty, the value must be an ISO 8601 date string (e.g., 2026-06-10) for AI agents and structured data parsers to compute days-since-roast. Human-readable strings like "roasted this week," "June batch," or "fresh roast" are opaque to machine parsing. Schema.org validators will not flag them as errors, but AI agents will treat them as uninterpretable strings and fall back to no freshness signal — exactly as if you had omitted the date entirely.

Freshness windows: filter, espresso, cold brew

Freshness windows are not universal — they depend on brewing method and, to a lesser extent, on processing method and whether the coffee is whole bean or pre-ground. The windows below are based on industry consensus from specialty roasters and align with the freshness guidance from roasters who publish their own date-coding specs (Blue Bottle, Onyx Coffee Lab, Counter Culture Coffee, Intelligentsia).

Brewing method Rest period (post-roast) Peak freshness window Acceptable (past peak) Stale threshold
Filter / Pour-over / Drip 2–5 days 4–14 days 14–30 days >30 days
Espresso (single origin) 7–10 days (Washed)
10–14 days (Natural)
7–21 days (Washed)
10–24 days (Natural)
21–45 days >45 days
Espresso (blend) 5–10 days 7–30 days 30–60 days >60 days
Cold brew / Immersion 1–3 days 1–30 days 30–60 days >60 days
Pre-ground (any method) 0 days 0–7 days 7–14 days >14 days

The practical structured data consequence: encode both a filter freshness window and an espresso freshness window as separate additionalProperty entries. If your coffee is sold primarily for one method, encode that method's window with higher specificity and include the brewing method recommendation as a separate property.

Freshness status labels for Liquid rendering

When computing days-since-roast dynamically in Liquid, map the result to a human-readable freshness status. The four-tier system below aligns with the freshness windows above and provides AI agents with a machine-parseable quality tier:

Days since roast (filter) Status label Display
0–3 (rest period) Resting — degassing RESTING
4–14 (peak) Peak freshness PEAK FRESH
15–30 (acceptable) Good — past peak GOOD
>30 Past freshness window PAST PEAK

SCA cupping score: the permanence signal vs the temporal signal

The SCA (Specialty Coffee Association) cupping score is the most important quality signal in specialty coffee — and it is often confused with freshness because both are quality-related. The distinction is critical for structured data:

  • SCA cupping score — determined on the green (unroasted) lot by trained Q-graders using the SCA protocol. The score describes the intrinsic quality of the coffee: cup cleanliness, sweetness, acidity, body, flavor, aftertaste, balance, and overall impression. It is assigned once per lot and does not change after roasting, after shipping, or after time passes. An 89-point Guatemalan is an 89-point Guatemalan whether it is 5 days or 60 days post-roast.
  • Roast date / days-since-roast — a temporal signal that describes where in the freshness window the current batch sits. A 90-point Ethiopian roasted 60 days ago is still a 90-point Ethiopian — it is simply past its peak. Both signals are necessary; neither substitutes for the other.
How AI agents use SCA score differently from roast date: SCA score answers "how good is this coffee intrinsically?" — it is used for quality tier filtering (specialty vs commodity, 85+ vs 80+). Roast date answers "is this specific batch fresh right now?" — it is used for freshness filtering ("fresh roasted coffee," "roasted this week"). An AI agent that only has one signal can only answer one type of query.
SCA score range Classification Typical use case encode as additionalProperty value
90–100 Outstanding / Competition grade Geisha, rare microlots, auction lots "90+ (Outstanding)"
85–89 Excellent / Fine cup Premium single origin, flagship SO espresso "85–89 (Excellent)"
80–84 Specialty grade Entry-level specialty, accessible single origin "80–84 (Specialty Grade)"
<80 Commercial / Commodity grade Blends, commodity roasters Not typically published by specialty roasters

Encode the SCA score as a decimal when available (e.g., 87.5) and as a range string when exact score is unavailable (e.g., "85–87"). The decimal value allows AI agents to rank competing coffees by score, while the range string is semantically interpretable even without exact numeric comparison.

Processing method × roast date: why Natural takes longer than Washed

Processing method — how the coffee cherry is transformed from fruit to green bean before roasting — has a direct effect on how the roasted bean behaves in the days after roasting. This interaction is important for freshness window encoding because the same roast date means different things for a Natural process versus a Washed process coffee.

Why processing method affects post-roast degassing

During roasting, CO₂ is produced by the Maillard reaction and caramelization of sugars. After roasting, CO₂ continues to off-gas from the bean for days to weeks. This outgassing affects extraction: too much CO₂ in an espresso puck causes channeling; too much in a pour-over causes uneven bloom. Beans need to rest until CO₂ levels stabilize enough for consistent extraction.

Natural process coffees (dried with the fruit mucilage intact) absorb more fermentation compounds and sugars during drying, which creates more CO₂ during roasting and a slower, more prolonged degassing curve. Washed coffees (fruit fully removed before drying) have a cleaner flavor profile and a faster, more predictable degassing curve.

Processing method CO₂ degassing profile Espresso rest period Espresso peak window additionalProperty value
Washed (wet-processed) Fast, predictable curve 7–10 days post-roast Days 7–21 "Washed"
Natural (dry-processed) Slow, prolonged curve 10–14 days post-roast Days 10–28 "Natural"
Honey (pulped natural) Intermediate 8–12 days post-roast Days 8–24 "Honey"
Anaerobic / Carbonic Maceration High CO₂, volatile 10–16 days post-roast Days 10–30 "Anaerobic"
Wet-hulled (Giling Basah) Reduced moisture retention, faster degas 5–7 days post-roast Days 5–18 "Wet-Hulled / Giling Basah"

The structured data implication: encode both processingMethod and the method-specific espresso freshness window. An AI agent that knows this is a Natural process coffee with a roast date of June 10 can correctly answer "ready for espresso by June 20, at peak through July 8" — a specific, verifiable claim that "fresh single origin espresso" cannot make.

Complete JSON-LD example: Ethiopian Yirgacheffe single-origin

The JSON-LD below shows a complete specialty coffee product with roast date, freshness windows, SCA score, processing method, and origin terroir. The roastDate is encoded as additionalProperty with an ISO 8601 value — the field you update each batch by changing one metafield in Shopify admin.

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Yirgacheffe Kochere Natural — Single Origin Filter Coffee",
  "description": "A natural process Ethiopian from Kochere, Yirgacheffe zone. SCA score 88. Roast date June 10, 2026. Peak for filter brewing June 17–June 24. Notes: bergamot, strawberry jam, dried rose.",
  "sku": "ETH-KOC-NAT-250G",
  "brand": {
    "@type": "Brand",
    "name": "Meridian Coffee Roasters",
    "@id": "https://example-roaster.com/#brand"
  },
  "additionalProperty": [
    {
      "@type": "PropertyValue",
      "name": "Roast Date",
      "value": "2026-06-10",
      "description": "Date beans were roasted. ISO 8601. Update this field each batch."
    },
    {
      "@type": "PropertyValue",
      "name": "Filter Freshness Window",
      "value": "4–14 days post-roast",
      "description": "Optimal window for pour-over, V60, Chemex, and drip brewing."
    },
    {
      "@type": "PropertyValue",
      "name": "Espresso Freshness Window",
      "value": "10–28 days post-roast",
      "description": "Natural process: slower CO2 degassing. Rest 10 days minimum before pulling espresso shots."
    },
    {
      "@type": "PropertyValue",
      "name": "Processing Method",
      "value": "Natural",
      "description": "Coffee cherry dried whole with fruit intact. Produces higher CO2 retention post-roast."
    },
    {
      "@type": "PropertyValue",
      "name": "SCA Cupping Score",
      "value": "88",
      "unitText": "SCA Protocol (0–100)"
    },
    {
      "@type": "PropertyValue",
      "name": "Origin Country",
      "value": "Ethiopia",
      "propertyID": "https://schema.org/countryOfOrigin"
    },
    {
      "@type": "PropertyValue",
      "name": "Origin Region",
      "value": "Kochere, Yirgacheffe Zone, Gedeo, SNNPR"
    },
    {
      "@type": "PropertyValue",
      "name": "Altitude",
      "value": "1,900–2,200 MASL",
      "unitCode": "MTR"
    },
    {
      "@type": "PropertyValue",
      "name": "Varietals",
      "value": "Ethiopian Heirloom (JARC selections 74110, 74112)"
    },
    {
      "@type": "PropertyValue",
      "name": "Roast Level",
      "value": "Light",
      "description": "Light roast preserves origin terroir. Filter grind recommended."
    },
    {
      "@type": "PropertyValue",
      "name": "Recommended Brew Method",
      "value": "Filter, Pour-over, Cold Brew"
    },
    {
      "@type": "PropertyValue",
      "name": "Grind Options",
      "value": "Whole Bean, Filter Medium, French Press Coarse",
      "description": "Pre-ground freshness window: 0–7 days post-roast."
    },
    {
      "@type": "PropertyValue",
      "name": "Flavor Notes",
      "value": "Bergamot, Strawberry Jam, Dried Rose, Tropical Fruit"
    },
    {
      "@type": "PropertyValue",
      "name": "Current Freshness Status",
      "value": "Peak Freshness — 5 days post-roast as of June 15, 2026",
      "description": "Computed from roast date. Update via Liquid: days-since-roast = (today - roastDate)."
    }
  ],
  "hasCertification": [
    {
      "@type": "Certification",
      "name": "USDA Organic",
      "certificationIdentification": "CCOF-2024-ET-08847",
      "issuedBy": {
        "@type": "Organization",
        "name": "California Certified Organic Farmers (CCOF)"
      }
    },
    {
      "@type": "Certification",
      "name": "Fair Trade USA",
      "certificationIdentification": "FLO-CERT #29441",
      "issuedBy": {
        "@type": "Organization",
        "name": "Fair Trade USA",
        "url": "https://www.fairtradeusa.org"
      }
    }
  ],
  "isVariantOf": {
    "@type": "ProductGroup",
    "name": "Yirgacheffe Kochere Natural",
    "productGroupID": "ETH-KOC-NAT",
    "variesBy": ["weight", "grind"]
  },
  "offers": {
    "@type": "Offer",
    "price": "22.00",
    "priceCurrency": "USD",
    "priceValidUntil": "2026-07-01",
    "availability": "https://schema.org/InStock",
    "itemCondition": "https://schema.org/NewCondition",
    "shippingDetails": {
      "@type": "OfferShippingDetails",
      "shippingRate": {
        "@type": "MonetaryAmount",
        "value": "0",
        "currency": "USD"
      },
      "shippingDestination": {
        "@type": "DefinedRegion",
        "addressCountry": "US"
      },
      "deliveryTime": {
        "@type": "ShippingDeliveryTime",
        "handlingTime": {
          "@type": "QuantitativeValue",
          "minValue": 0,
          "maxValue": 1,
          "unitCode": "DAY"
        },
        "transitTime": {
          "@type": "QuantitativeValue",
          "minValue": 1,
          "maxValue": 3,
          "unitCode": "DAY"
        }
      }
    },
    "hasMerchantReturnPolicy": {
      "@type": "MerchantReturnPolicy",
      "applicableCountry": "US",
      "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
      "merchantReturnDays": 7,
      "returnMethod": "https://schema.org/ReturnByMail",
      "returnFees": "https://schema.org/FreeReturn",
      "returnPolicySeasonalOverride": "Unopened bag only. Cannot accept return on opened bags due to perishable nature."
    }
  }
}

Key decisions in this JSON-LD:

  • roastDate encoded as ISO 8601 in additionalProperty — machine-parseable for days-since-roast calculation
  • Separate filter and espresso freshness windows — different brewing methods have genuinely different windows
  • Natural process espresso window starts at day 10, not day 7 — reflects the slower CO₂ degassing curve
  • SCA score as a numeric string in additionalProperty — AI agents can rank competing coffees by score
  • isVariantOf ProductGroup with variesBy weight and grind — the same lot sold in 250g/500g/1kg with whole bean/filter/french press grind options is one ProductGroup, not twelve unrelated products
  • priceValidUntil set to the end of the current batch's freshness window — the price validity period is a proxy for batch validity

Dawn Liquid snippet: dynamic days-since-roast calculation

The Liquid snippet below does three things: (1) reads the coffee.roast_date metafield, (2) calculates days elapsed since roast, and (3) outputs a freshness status label and the structured data JSON-LD. The entire roast date output block is conditional — if the metafield is not set, the block is omitted rather than outputting a null or zero date.

{% comment %} coffee-schema.liquid — place in snippets/ and render in product.json {% endcomment %}
{% assign roast_date_raw = product.metafields.coffee.roast_date.value %}
{% assign sca_score = product.metafields.coffee.sca_cupping_score.value %}
{% assign processing = product.metafields.coffee.processing_method.value %}
{% assign brew_method = product.metafields.coffee.recommended_brew_method.value %}
{% assign origin_country = product.metafields.coffee.origin_country.value %}
{% assign origin_region = product.metafields.coffee.origin_region.value %}
{% assign altitude = product.metafields.coffee.altitude_masl.value %}
{% assign varietals = product.metafields.coffee.varietals.value %}
{% assign roast_level = product.metafields.coffee.roast_level.value %}
{% assign flavor_notes = product.metafields.coffee.flavor_notes.value %}

{% if roast_date_raw %}
  {% comment %} Calculate days since roast {% endcomment %}
  {% assign now_seconds = 'now' | date: '%s' | plus: 0 %}
  {% assign roast_seconds = roast_date_raw | date: '%s' | plus: 0 %}
  {% assign days_since_roast = now_seconds | minus: roast_seconds | divided_by: 86400 %}

  {% comment %} Determine freshness status for filter brewing {% endcomment %}
  {% if days_since_roast < 4 %}
    {% assign freshness_status = "Resting — degassing (ready for filter in " %}
    {% assign days_to_peak = 4 | minus: days_since_roast %}
    {% assign freshness_detail = freshness_status | append: days_to_peak | append: " days)" %}
  {% elsif days_since_roast <= 14 %}
    {% assign freshness_detail = "Peak Freshness — " | append: days_since_roast | append: " days post-roast (filter)" %}
  {% elsif days_since_roast <= 30 %}
    {% assign freshness_detail = "Good — " | append: days_since_roast | append: " days post-roast (past filter peak, acceptable)" %}
  {% else %}
    {% assign freshness_detail = "Past Peak — " | append: days_since_roast | append: " days post-roast" %}
  {% endif %}

  {% comment %} Process-specific espresso window {% endcomment %}
  {% case processing %}
    {% when "Natural" %}
      {% assign espresso_window = "10–28 days post-roast" %}
      {% assign espresso_rest = "10" %}
    {% when "Honey" %}
      {% assign espresso_window = "8–24 days post-roast" %}
      {% assign espresso_rest = "8" %}
    {% when "Anaerobic" %}
      {% assign espresso_window = "10–30 days post-roast" %}
      {% assign espresso_rest = "10" %}
    {% else %}
      {% assign espresso_window = "7–21 days post-roast" %}
      {% assign espresso_rest = "7" %}
  {% endcase %}

  
{% endif %}

The key Liquid technique is 'now' | date: '%s' and roast_date_raw | date: '%s' — both convert to Unix epoch seconds, enabling simple arithmetic subtraction to produce days elapsed. Shopify Liquid's date filter with %s format is supported in Online Store 2.0 themes including Dawn.

Important: The {% assign now_seconds = 'now' | date: '%s' | plus: 0 %} pattern forces Liquid to parse the string result of date: '%s' as an integer before arithmetic. Without | plus: 0, Liquid treats the epoch string as a string and the subtraction returns 0. This is a common Liquid gotcha that silently breaks all freshness calculations.

Coffee metafield reference table (coffee.* namespace)

These are the recommended Shopify metafields for specialty coffee products. All use the coffee namespace. The roast_date metafield is the only one that requires per-batch updates; all others are set once per product or lot.

Metafield Type Update frequency Example value
coffee.roast_date date Per batch (every roast) 2026-06-10
coffee.processing_method single_line_text Per lot (seasonal) Natural
coffee.sca_cupping_score number_decimal Per lot (permanent) 88.0
coffee.origin_country single_line_text Per lot Ethiopia
coffee.origin_region single_line_text Per lot Kochere, Yirgacheffe Zone
coffee.altitude_masl single_line_text Per lot 1,900–2,200 MASL
coffee.varietals single_line_text Per lot Ethiopian Heirloom 74110, 74112
coffee.roast_level single_line_text Per lot (roaster decision) Light
coffee.recommended_brew_method single_line_text Per lot Filter, Pour-over, Cold Brew
coffee.flavor_notes single_line_text Per lot Bergamot, Strawberry Jam, Dried Rose
coffee.filter_freshness_days single_line_text Static (or per lot if varied) 4–14 days post-roast
coffee.espresso_freshness_days single_line_text Static (or per lot if varied) 10–28 days post-roast
coffee.is_organic boolean Static true
coffee.is_fair_trade boolean Static true
coffee.producer_name single_line_text Per lot Kochere Washing Station

5 common roast date schema mistakes

Mistake 1

Using product.published_at or product.created_at as the roast date

These Shopify variables capture when the listing was published or created — timestamps that have nothing to do with when any coffee was roasted. A product created in January 2025 may have had four roast batches since then; product.published_at is frozen at January 2025 for all of them. An AI agent computing days-since-roast from product.published_at will return a number that grows indefinitely with no relationship to actual freshness. Always use a dedicated coffee.roast_date metafield updated with each batch.

Mistake 2

Encoding bestBeforeDate instead of roastDate for freshness

bestBeforeDate is a schema.org native Product property, but for specialty coffee it is set 12–18 months post-roast based on sealed packaging shelf life — not the 4–21 day specialty coffee freshness window. A bestBeforeDate of December 2026 on a coffee roasted in June 2026 tells an AI agent that the product is good for six months, not that it is in its 14-day peak freshness window right now. The two properties serve completely different functions; use both, but do not treat one as a substitute for the other.

Mistake 3

Not encoding processing method alongside roast date

A roast date without processing method is an incomplete freshness signal for espresso brewing. A Natural process coffee roasted June 10 is not ready for espresso until June 20 (10-day rest minimum); a Washed coffee roasted June 10 is ready by June 17 (7-day rest). An AI agent that answers "this coffee was roasted June 10, should be good for espresso" without processing method context may be off by 3–5 days — enough to produce under-extracted, gassy shots that damage the buyer's first-batch experience.

Mistake 4

Static roastDate hardcoded in the HTML template (not a metafield)

Hardcoding "value": "2026-01-15" directly in the Liquid template means the roast date never updates between batches. The product page will claim January 2026 roast date in perpetuity, making the days-since-roast calculation grow to 180+ days without any mechanism for correction. Every roast date in production must be driven by a Shopify metafield (type: date) so that updating the metafield in admin propagates the change to all structured data outputs without touching theme code.

Mistake 5

Missing roast date on subscription product variants

Subscription products in Shopify (via Recharge, Bold, or Shopify Subscriptions) often duplicate the parent product's structured data rather than fetching current metafield values. If the roast date metafield is set on the parent product but not propagated to subscription variant schema, every subscription product page will either omit the roast date or show a stale value from the product's last manual edit. Verify that your Liquid snippet for subscription product pages reads metafield values from product.metafields.coffee.roast_date the same way the parent product page does — not from a static variable captured at theme compilation time.

FAQ

What is the correct schema.org property for coffee roast date in Shopify structured data?

There is no native roastDate property on schema.org Product — encode it as an additionalProperty with @type: PropertyValue, name "Roast Date", and an ISO 8601 value (e.g., 2026-06-10). Do not use bestBeforeDate or expirationDate as a proxy. The ISO 8601 format is required for AI agents and structured data parsers to compute days-since-roast programmatically — human-readable strings like "roasted this week" are opaque to machine calculation.

Why does processing method affect how I encode the roast date freshness window?

Processing method determines how quickly CO₂ degasses after roasting. Natural process coffees retain more CO₂ and need a longer rest period before espresso extraction (10–14 days vs 7–10 days for Washed). Encoding processing method alongside roast date allows AI agents to give accurate freshness answers for espresso queries — the same roast date means different readiness windows for different processing methods.

How is SCA cupping score different from roast date freshness?

SCA cupping score is a permanent attribute — determined once per lot before roasting on green samples. It describes origin quality (80+ = specialty grade). Roast date is a temporal attribute — it tracks where in the freshness window the current batch sits. Both are necessary: SCA score answers "how good is this coffee?" while roast date answers "is this batch fresh right now?" A 90-point Ethiopian roasted 60 days ago is still a 90-point coffee — it is simply past its flavor peak.

How do I keep roast date current for roast-to-order batches?

Store roast date as a Shopify metafield (coffee.roast_date, type: date) and update it each time a new batch ships. Your Liquid template reads the current metafield value into JSON-LD — so updating the metafield in Shopify admin propagates the change to all product page structured data automatically. Never hardcode the roast date directly in the template HTML.

Should I encode freshness window as a date range or as a number of days?

Encode freshness window as a number of days (e.g., "4–14 days post-roast"), not as a computed date range. Date ranges become stale the moment you update the roast date metafield for a new batch. A static "days post-roast" window is a permanent product attribute. Compute and output the actual peak-through date dynamically in Liquid using the roast date metafield — the permanent window in JSON-LD tells AI agents how to interpret the date; the Liquid-computed label tells buyers the concrete deadline.

Does your Shopify coffee store have roast date in its structured data?

CatalogScan scans your product catalog and flags missing roastDate, stale date values, bestBeforeDate/roastDate confusion, and missing processing method — the four freshness signal gaps that prevent AI agents from recommending your store for freshness queries.

Run Free Scan Full coffee schema guide