Skip to content
decodecodeveloper docs
Storefront → Templates → Commerce

Shared commerce

schema.org types, useOffer, formatPrice, analytics, useVariantPossibilities, Image / Picture / JsonLd.

@decocms/apps-commerce/* provides the platform-agnostic surface: types, SDK helpers, and components used by both VTEX and Shopify integrations. If you're building a custom commerce integration or a custom storefront component, this is the contract.

Types

@decocms/apps-commerce/types exports schema.org-aligned commerce shapes:

TypeUse
ProductSingle product (PDP, shelf cards)
ProductLeafA specific SKU/variant of a product
AggregateOfferWrapper around multiple offers (lowest price, count, etc.)
OfferSingle offer (price, availability, seller)
UnitPriceSpecificationPer-unit pricing (e.g. R$ 10.00 each)
ProductDetailsPagePDP page shape — product + breadcrumbs + SEO + similar products
ProductListingPagePLP page shape — products + filters + sort options + pagination
BreadcrumbListBreadcrumb path
MinicartCart shape used by useCart / SSR minicart
SiteNavigationElementHeader/footer navigation item
import type {
  Product,
  ProductDetailsPage,
  ProductListingPage,
  AggregateOffer,
  BreadcrumbList,
} from "@decocms/apps-commerce/types";

These mirror schema.org JSON-LD, so types double as both runtime data shapes and SEO payloads.

TODOs in the type file. commerce/types/commerce.ts has open TODOs about JSON Schema generator support for recursive types. Some navigation types are marked @deprecated. Pin to current types and watch the changelog when upgrading.

SDK helpers

useOffer

import { useOffer } from "@decocms/apps-commerce/sdk/useOffer";
 
const { price, listPrice, availability, seller, installments, installment } = useOffer(
  product.offers,
);

Pulls the canonical offer from an AggregateOffer. Returns:

  • price — lowest current price.
  • listPrice — original price (for strikethrough display).
  • availability — "InStock" / "OutOfStock".
  • seller — seller ID for VTEX multi-seller stores.
  • installments / installment — installment plans where applicable.

formatPrice

import { formatPrice, formatPriceRange } from "@decocms/apps-commerce/sdk/formatPrice";
 
formatPrice(99.9, "BRL", "pt-BR");        // "R$ 99,90"
formatPriceRange("100:200", "BRL");       // "R$ 100,00 — R$ 200,00"

formatPriceRange parses VTEX-style min:max facet bounds.

analytics

import { mapProductToAnalyticsItem } from "@decocms/apps-commerce/sdk/analytics";
 
const item = mapProductToAnalyticsItem({
  product,
  index: 0,
  itemListName: "Home — Best sellers",
});

Returns a GA4-compatible AnalyticsItem. Push to dataLayer directly:

window.dataLayer.push({ event: "view_item_list", items: [item] });

useVariantPossibilities

import { useVariantPossibilities } from "@decocms/apps-commerce/sdk/useVariantPossibilities";
 
const possibilities = useVariantPossibilities(product.isVariantOf?.hasVariant ?? [], product);
// → { Color: { Red: { url: "/p/red-version" }, Blue: ... }, Size: ... }

Builds a map of variant-property → option → URL for the variant picker UI. Handles cross-product variants (different products grouped by a shared isSimilarTo relationship).

url

import { relative } from "@decocms/apps-commerce/sdk/url";
 
const cleanLink = relative(href, { stripSearchParams: ["idsku"] });

Converts absolute URLs to relative + strips known noise params. Use for PDP <a href> so cross-variant navigation doesn't carry SKU IDs forward.

Components

Image

import { Image, registerImageCdnDomain } from "@decocms/blocks/hooks";

Optimized commerce image with width/height enforcement (CLS), responsive srcSet, and CDN URL transformation.

<Image
  src="https://cdn.example.com/product.jpg"
  width={400}
  height={400}
  fit="cover"
  preload
  alt="Product name"
/>

Required props: src, width. Recommended: height (improves CLS), alt. Optional: fit (cover / contain / fill), preload (adds preload link), media.

If your CDN isn't auto-detected, register it once at site setup:

import { registerImageCdnDomain } from "@decocms/blocks/hooks";
 
registerImageCdnDomain("cdn.example.com", {
  buildUrl: ({ src, width, height, fit }) => `${src}?w=${width}&h=${height}`,
});

Picture

import { Picture, Source } from "@decocms/blocks/hooks";
 
<Picture preload>
  <Source src={mobileSrc} media="(max-width: 767px)" width={400} />
  <Source src={desktopSrc} media="(min-width: 768px)" width={1200} />
  <Image src={desktopSrc} width={1200} alt="Banner" />
</Picture>

Use when you have art-directed responsive images (different crops or compositions for different viewports). For simple resizing, Image alone is enough.

JsonLd

import { ProductJsonLd, BreadcrumbJsonLd, PLPJsonLd } from "@decocms/blocks/hooks";
 
<ProductJsonLd product={product} url={pageUrl} />
<BreadcrumbJsonLd breadcrumbs={breadcrumbList} />
<PLPJsonLd page={productListingPage} />

Emits <script type="application/ld+json"> with schema.org markup. Search engines pick this up for rich results.

Utils

productToAnalyticsItem

import { mapProductToAnalyticsItem } from "@decocms/apps-commerce/utils/productToAnalyticsItem";

Slightly different shape from sdk/analytics's mapper — kept for compatibility with v1 sites. New code should prefer the SDK version.

canonical

import { canonicalFromBreadcrumblist } from "@decocms/apps-commerce/utils/canonical";
 
const canonical = canonicalFromBreadcrumblist(breadcrumbs, baseUrl);

Builds the canonical URL for a PLP from its breadcrumb path. Useful when the displayed URL has tracking params or filter state that shouldn't be canonical.

stateByZip (Brazil-specific)

import getStateFromZip from "@decocms/apps-commerce/utils/stateByZip";
 
const state = getStateFromZip("01310-100"); // → "SP"

Maps Brazilian CEPs to state UFs via Correios ranges. Handy for VTEX regional logic.

filters

import { facetsToFilters } from "@decocms/apps-commerce/utils/filters";

Helpers for transforming Intelligent Search facets into UI-friendly filter shapes.

constants

Shared constants — currency codes, sort key constants, etc.

App typing

@decocms/apps-commerce/app-types exports the contracts apps must satisfy:

import type { AppDefinition, AppMiddleware, ResolveSecretFn } from "@decocms/apps-commerce/app-types";

Used by anyone building a custom commerce app. End users don't touch this.

resolveApps

import { resolveApps } from "@decocms/apps-commerce/resolve";

Composes multiple AppDefinitions into one — merging manifests, chaining middleware. Used internally by autoconfigApps. End users rarely call.

See also