All posts
Ray Iyer
Ray Iyer
Co-founder, Anglera

Getting enriched product data onto Salesforce Commerce Cloud product pages

How an enriched attribute moves from the Product system object through SFRA templates onto a rendered SFCC product page, plus how to validate it.

Getting enriched product data onto Salesforce Commerce Cloud product pages

Once a product attribute is enriched, it still has to travel from Business Manager's data model through a cartridge template before a shopper or an AI crawler ever sees it. On Salesforce B2C Commerce (SFCC), that path runs through the Product system object, the SFRA product model, and an ISML template — three layers that are easy to get half-right. Here's the concrete, current mechanism for getting one enriched field onto the page, plus how to check that it actually landed.

Where the data lives: the Product system object

Every product in B2C Commerce is backed by the Product system object. Standard fields (name, brand, UPC) live there by default; anything else — a fit guide, a care instruction, a compliance callout — has to be added as a custom attribute:

  1. In Business Manager, go to Administration, then Site Development, then System Object Types, open Product, and use the Attribute Definitions tab to add a new attribute (ID, type, and a display name for each locale you support).
  2. Add it to an Attribute Grouping so merchandisers can find and edit it in the Business Manager product editor.
  3. If the value is fed by an outside system (a PIM, an enrichment pipeline, or Anglera), select Externally Managed on the Attribute Definition Details page so Business Manager users see it's not meant to be hand-edited there. (A separate, similarly-named "externally defined" flag exists too, but it can only be set by a catalog import — it isn't a checkbox you toggle in the UI — so for a manually-created attribute, Externally Managed is the one that applies.)

This step only creates the field. It does nothing to the storefront yet — a custom attribute with no template reference is invisible to shoppers even after it's fully populated.

Getting a value into the attribute

Values reach the Product object one of three ways: manual entry in Business Manager, a product import (Business Manager Administration, then Site Development, then Import & Export, or scheduled catalog feeds using the custom-attribute element, keyed by an attribute-id, in the product XML), or programmatically through the B2C Commerce APIs. For system integrations, that means SCAPI's Product resource — Salesforce marked the older Data API (OCAPI) deprecated in 2026 and now directs all new integration work to SCAPI, though existing OCAPI implementations keep working during the multi-year sunset window. Either way, custom attributes always surface with a c_ prefix (for example c_careInstructions) to distinguish them from standard fields — a convention documented in Salesforce's Custom Properties guide.

Binding it to the storefront template

Storefront rendering in modern SFCC implementations runs on the Storefront Reference Architecture (SFRA). SFRA's cartridge path determines which template wins when multiple cartridges define a file of the same name — your custom cartridge, placed to the left of app_storefront_base on the path, overrides the base version, per Salesforce's Customize SFRA guide. A product page request is composed like this:

  • A controller (Product-Show) builds a product model — a plain JSON object assembled from a stack of decorator modules (app_storefront_base/cartridge/models/product/decorators/*, one of which is literally named attributes.js) that each add one slice of data (price, images, availability, attributes) to viewData.
  • The rendered productDetails.isml template reads that model via pdict.product and, through a chain of isincluded sub-templates under product/, renders each visible attribute group — the exact template file name varies slightly by SFRA version, so check your own cartridge's product/ folder rather than assuming a single canonical path.

There are two legitimate ways to get a new enriched attribute onto that page:

No-code path — Product Attribute Groups. If you just need the value to show inside the existing "Product Specifications" table, assign the attribute to a category-level attribute group under Merchandising, then Products, then Product Attributes, then Assign Product Attributes. SFRA's built-in attributes decorator already loops over each product's visible attribute groups and renders them, so nothing changes in code.

Code path — a custom decorator and template snippet. For anything that needs its own placement, label, or styling (a callout above the fold, a spec sheet block, a compatibility note), extend the product model:

// cartridges/custom_storefront/cartridge/models/product/decorators/careInstructions.js
'use strict';

module.exports = function (product, apiProduct) {
    Object.defineProperty(product, 'careInstructions', {
        enumerable: true,
        value: apiProduct.custom.careInstructions
            ? apiProduct.custom.careInstructions.toString()
            : null,
    });
};
// cartridges/custom_storefront/cartridge/models/product.js
'use strict';

var base = module.superModule;
var careInstructions = require('*/cartridge/models/product/decorators/careInstructions');

module.exports = function (product, apiProduct, options) {
    base.call(this, product, apiProduct, options);
    careInstructions(product, apiProduct);
    return product;
};
<!-- cartridges/custom_storefront/cartridge/templates/default/product/components/careInstructions.isml -->
<isif condition="${pdict.product.careInstructions}">
    <div class="care-instructions" data-testid="care-instructions">
        <h3>${Resource.msg('label.care.instructions', 'product', null)}</h3>
        <isprint value="${pdict.product.careInstructions}" encoding="html" />
    </div>
</isif>

The include tag below pulls that snippet into an overridden productDetails.isml:

<isinclude template="product/components/careInstructions" />

Because ISML renders server-side, the attribute lands as plain text in the HTML response — no client-side hydration required, which is exactly what matters for crawlers (AI agents included) that don't execute JavaScript.

Making it visible to search and AI crawlers, not just shoppers

Meta tags are handled separately from body content. Under Merchant Tools, then SEO, then Page Meta Tag Rules, a "Product Detail Page" scoped rule can reference any custom attribute directly inside a description or Open Graph rule, per Salesforce's Page Meta Tags documentation:

${Product.custom.careInstructions}

JSON-LD structured data, by contrast, isn't a built-in Business Manager feature on B2C Commerce SFRA storefronts the way meta tag rules are — teams typically add a small script block to htmlHead.isml (or a dedicated include) that serializes pdict.product fields, including custom ones, into a Product schema with an additionalProperty/PropertyValue entry for anything that doesn't map to a standard schema.org field:

<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "Product",
    "name": "${product.productName}",
    "additionalProperty": [{
        "@type": "PropertyValue",
        "name": "Care instructions",
        "value": "${product.careInstructions}"
    }]
}
</script>

How to validate

  • View-source vs. rendered DOM: for a plain ISML-rendered attribute like the example above, curl -s https://yoursite/on/demandware.store/Sites-.../.../Product-Show?pid=SKU123 | grep -A2 "care-instructions" should return the same text as the rendered DOM in browser DevTools. If it appears only in DevTools and not in curl output, the content is likely coming from a client-side remote include (an AJAX-loaded ISML fragment) or a Page Designer component that renders asynchronously — worth flagging, since crawlers that don't execute JavaScript will miss it.
  • Page cache: SFRA product pages are usually page-cached. If a newly published attribute doesn't appear, check the Caching tab on the page/controller or clear the cache before re-checking — you may be looking at a stale cached response, not a broken template.
  • Structured data: run the page through Google's Rich Results Test or the Schema Markup Validator to confirm the JSON-LD parses and the Product type is recognized.
  • Meta tag rules: preview the rule in Business Manager's Page Meta Tag Rules screen, then confirm the resolved value in the page head section via view-source on the live product URL — the rule editor preview and the actual storefront output can differ if the rule falls back to static text for an empty attribute.

Verified as of July 2026

Menu paths, decorator patterns, and API prefixes above reflect current SFRA and SCAPI documentation as of this writing; Salesforce ships quarterly platform releases, so confirm exact field names and menu locations against your instance's release version before implementing.

This whole exercise assumes the attribute already has a clean, correct value sitting on the Product object — which is the harder problem in practice. Anglera plugs into your existing PIM or commerce platform to keep those fields (specs, use-cases, identifiers) enriched and current, so the template and meta-tag work above has something worth rendering.

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