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
| Target | Page | Wired 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 |
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
| Field | Required | Description |
|---|---|---|
target | yes | One of the targets above. |
url | yes | Relative path (under extensions/) or absolute https URL. |
title | no | Label shown to the merchant in the apps admin. |
permissions | no | OAuth 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 resolvedurl:
- 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_CONTEXTwiring on the storefront side. - No page context is injected into the URL. The slot mounts with the
store’s
domainSlugand the customer’s bearer token only — the host does not appendorderId/customerIdquery parameters to your iframeurl. 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:Security
- The iframe is sandboxed with
allow-scripts allow-forms allow-popupsand noallow-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
401without 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.