All posts
Ray Iyer
Ray Iyer
Co-founder, Anglera

From metafield to page: the product-data chain that ends at a rendered PDP

How enriched product data travels from PIM or metafield through the template layer to a rendered PDP and its JSON-LD, and where the chain breaks.

From metafield to page: the product-data chain that ends at a rendered PDP

Once a product attribute is enriched — a material, a use-case, a certification, a compatibility note — it still has to travel through three more systems before a shopper or an AI agent sees it: the data layer, the template layer, and the render layer, with a structured-data mirror alongside. Most PDP gaps aren't missing data anymore; they're a broken link in that chain. This guide walks the chain end to end using real mechanisms — Shopify metafields, Salesforce B2C Commerce custom attributes, Adobe Commerce EAV attributes, and PIM export mappings — so you can trace where an attribute lives, how it binds, and how to confirm it rendered.

The chain, in one pass

  1. Data layer — the attribute is stored on a PIM record, a platform custom attribute, or a metafield, scoped to a namespace/entity/channel.
  2. Template layer — a template file references that field by name and decides where and how it appears on the page.
  3. Render layer — the server (or client) turns the template plus data into actual HTML in the DOM.
  4. Structured-data mirror — the same value is repeated in JSON-LD so search engines and AI agents can parse it without layout guesswork.

If any one of those four links is missing, the attribute either doesn't show up, shows up empty, or shows up on the page but not in structured data (or vice versa) — which is its own problem, covered below.

Link 1: where the enriched data actually lives

The storage mechanism differs by platform, but the pattern is consistent: a scoped key attached to a product record.

  • Shopify: product data is stored as a metafield, identified by a namespace and a key (for example custom.material). Metafields are created via the Shopify admin, the Admin API, or an app — never from inside a Liquid template — and each one has a declared type (single-line text, rich text, list, reference, and so on) that determines how it can be rendered later (Shopify metafield object reference).
  • Salesforce B2C Commerce: attributes are either system attributes (built into the base product object) or custom attributes added through Business Manager's attribute definitions, then populated per product and made available to templates through the pipeline dictionary (pdict) (B2C Commerce templates guide).
  • Adobe Commerce (Magento): attributes live in the EAV (entity-attribute-value) model, assigned to attribute sets and exposed to the storefront only if flagged as visible on the catalog pages.
  • PIM-sourced data (Akeneo, Salsify, inRiver, etc.): the attribute exists in the PIM's attribute group and only reaches the storefront once it's mapped to a channel/locale and pushed through a connector or export job. This mapping step is the single most common place enriched data silently stops — the value is complete in the PIM but was never added to the channel's attribute list.

The common failure at this link isn't that the data doesn't exist. It's that the data exists but isn't scoped, mapped, or flagged for the channel the template reads from.

Link 2: binding the data to the template

Binding is the template referencing the field by its exact key. This is the step most teams get informally right and formally undocumented, which is why it breaks during a re-theme or a platform migration.

Shopify (Liquid), reading a product metafield inside a section file:

{% if product.metafields.custom.material.value != blank %}
  <p class="pdp-attribute">
    <span class="label">Material</span>
    <span class="value">{{ product.metafields.custom.material.value }}</span>
  </p>
{% endif %}

Both details matter: Shopify Liquid resolves a metafield reference to an object with .type and .value properties rather than a bare scalar, and skipping the blank guard means products missing that metafield render an empty element instead of omitting it — a small layout bug that compounds across a large catalog (Shopify metafield object reference).

Salesforce B2C Commerce (ISML), reading a custom attribute passed into the pipeline dictionary:

<isif condition="${pdict.Product.custom.material}">
  <p class="pdp-attribute">
    <span class="label">Material</span>
    <span class="value"><isprint value="${pdict.Product.custom.material}" /></span>
  </p>
</isif>

B2C Commerce favors the isprint tag over a raw expression for consistent encoding and formatting, as shown above (B2C Commerce ISML expressions guide).

Adobe Commerce templates typically pull the value through the product block, e.g. $block->getProduct()->getAttributeText('material') inside a .phtml file, gated by the same "Visible on Catalog Pages on Storefront" flag mentioned above (Adobe Commerce product attributes guide).

In every case, the binding does the same job: matching a template variable name to a data-layer key. If a PIM export renames or restructures an attribute (a "material" attribute becoming "primary_material" during a taxonomy cleanup, for instance), the template reference breaks silently — the page still builds, it just quietly drops that field.

Link 3: what actually renders as HTML

This is the link most teams never check directly, and it matters most for AI agents. A template reference resolving correctly on the server doesn't guarantee the value reaches the DOM in a form a non-JS client can read.

  • Server-side rendered PDPs (Liquid, ISML, most .phtml storefronts) put the attribute value in the initial HTML response — view-source and the rendered DOM match.
  • Client-hydrated PDPs (a React/Hydrogen or headless storefront fetching product data after page load) may omit the attribute from the initial HTML, adding it only after JavaScript executes. Many crawlers and AI agents fetch raw HTML without running a full browser, so a value accurate in the PIM and correctly bound in the component can still be invisible to them.

The fix isn't avoiding client rendering — it's confirming the specific attributes buyers and agents rely on (spec tables, compatibility notes, identifiers) are present in the server-rendered or pre-rendered payload, not injected client-side only.

Link 4: mirroring the value in structured data

The same attribute should also appear in the page's JSON-LD, because that's the version an AI agent or search engine parses directly instead of inferring from layout. Google's guidance for Product structured data requires name plus at least one of offers, review, or aggregateRating, and is explicit that marked-up values must match what's visible on the page (Google Product snippet structured data):

{
  "@context": "https://schema.org/",
  "@type": "Product",
  "name": "Example Product Name",
  "additionalProperty": [
    {
      "@type": "PropertyValue",
      "name": "Material",
      "value": "316 stainless steel"
    }
  ],
  "offers": {
    "@type": "Offer",
    "price": 119.99,
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock"
  }
}

Attributes beyond the core schema.org Product fields (material, compatibility, certifications, use-case notes) typically go in additionalProperty as name/value pairs, keeping the JSON-LD in sync with the visible spec table. The failure mode here is subtle: JSON-LD is often built from a separate template or a cached snapshot, so the visible HTML can update while the JSON-LD still reflects the old value — violating Google's matching guidance and giving an AI agent a different answer than a human reader sees.

How to validate

View-source vs. rendered DOM: pull the raw server response and check whether the attribute's text is actually present, not just a loading skeleton. Then compare against the browser's rendered DOM (right-click, Inspect) to catch client-only rendering gaps.

curl -s https://example.com/products/product-handle | grep -i "material"

JSON-LD extraction: pull the script block directly and diff it against the visible spec table on the same page.

curl -s https://example.com/products/product-handle | grep -A 30 "application/ld+json"
  • Google's Rich Results Test: run the live URL to confirm the Product markup validates and to see exactly which properties Google parsed.
  • Schema.org validator: useful for catching structural JSON-LD errors (wrong nesting, missing type declarations) that Rich Results Test doesn't always flag clearly.

Verified as of July 2026 against Shopify's metafield docs, Salesforce B2C Commerce's ISML guide, and Google Search Central's Product structured data guidelines; confirm field names and required properties against your platform's current version and plan, since these do shift between releases.

Anglera sits at the front of this chain, not inside it: it enriches the attributes, specs, use-cases, and identifiers that live in your PIM or metafields, continuously and at catalog scale, without requiring a rip-and-replace of the platform you already run. Once that data is rich and correctly scoped, the binding-to-render-to-JSON-LD work above is what turns it into a page buyers and AI agents can actually read.

Ray Iyer

About the author

Ray IyerCo-founder, Anglera

Ray is a co-founder of Anglera, building the product-data infrastructure for agentic commerce — turning messy catalogs into structured, AI-readable data that buyers and answer engines can find. Previously product at Uber; Stanford CS.

See it on your own SKUs.

A 30-minute walkthrough on your categories and your supplier data.

Book a demo