Skip to main content

Customer Account Extensions

Customer-account extensions are iframes injected into the customer’s account pages (/account, /orders/[orderId], /account/profile). Use them for order tracking widgets, loyalty balances, support chat panels, and similar customer-facing surfaces. These are distinct from admin extensions (which target the merchant admin UI) and from checkout extensions (which target the unauthenticated checkout flow). They run for a logged-in customer with the customer’s session.

Targets

TargetPageWired today
customer-account.order-status.block.render/orders/[orderId]✓ live
customer-account.dashboard.block.render/account✓ live
customer-account.order-list.block.render/account✓ live
customer-account.profile.block.render/account/profile✓ live
All four targets have a slot mounted in the storefront account pages. dashboard.block.render renders above the page header on /account; order-list.block.render renders between the header and the order history list on the same page; profile.block.render renders above the “Profile” heading on /account/profile; order-status.block.render renders on the per-order page. The <CustomerAccountExtensionSlot target="..." /> component renders one iframe per registered extension at the given target. It requires the customer’s session token as bearerToken; without it the slot API returns 401 and the slot renders empty (correct secure default — extension enumeration is gated behind authentication).

Manifest

FieldRequiredDescription
targetyesOne of the targets above.
urlyesRelative path (under extensions/) or absolute https URL.
titlenoLabel shown to the merchant in the apps admin.
permissionsnoOAuth scopes the iframe needs — same vocabulary as admin extensions.

How the iframe is rendered

Each registered extension is rendered as a plain iframe pointed at its resolved url:
A few things to design around:
  • No App Bridge host on this surface. Unlike admin extensions, the customer-account slot does not run an App Bridge postMessage host, and it does not push any context object into the iframe. There is no useApi() / EXTENSION_CONTEXT wiring on the storefront side.
  • No page context is injected into the URL. The slot mounts with the store’s domainSlug and the customer’s bearer token only — the host does not append orderId / customerId query parameters to your iframe url. If your extension needs to know which order or customer it’s rendering for, fetch that from your own backend using the customer session token (see Security), or derive it from the page your block targets.
  • Fixed height. The iframe renders at a fixed 120px height. Keep your block compact, or scroll within it.

Discovery

The storefront exposes:
which returns the registered extensions plus their absolutized URLs. The slot component fetches this on mount and renders one iframe per extension.

Security

  • The iframe is sandboxed with allow-scripts allow-forms allow-popups and no allow-same-origin, so it runs in an opaque origin and cannot read the parent page’s cookies or storage.
  • Enumerating a store’s installed extensions is gated behind authentication: the discovery endpoint requires the customer’s bearer token and returns 401 without it (the slot then renders nothing).
  • The bearer token the slot is mounted with is the customer’s session credential. If your iframe needs to call an API on behalf of the customer, your own backend must independently verify that credential — never trust ids passed to you in the clear.