Admin Block Extensions
An admin block is a sandboxed iframe the host renders inline on a merchant admin page (product, order, customer, etc.). Use blocks for UI that is always present on the page — review summaries, fulfilment status, warehouse KPIs, or anything you want the merchant to see without clicking a button. If you want a button that opens a modal on demand, use an Admin Action instead.How the Host Renders It
<AdminExtensionSlot target="..." resourceId resourceType domainSlug />
mounts a sandboxed iframe per registered extension:
GET /api/apps/admin-extensions?target=<target>&domainSlug=<slug> to
discover registered extensions, then renders one iframe per result.
Available Targets
Targets are filtered by exact string match against the wired slots in the LaunchMyStore admin. Every slot uses theadmin.<resource>.render naming
convention — your manifest’s target must match exactly. 26 admin-block
slots are currently wired (plus separate slots for admin actions
and print actions):
Resource Detail Pages
| Target | Where it renders |
|---|---|
admin.product-details.block.render | Product detail page |
admin.order-details.block.render | Order detail page |
admin.customer-details.block.render | Customer detail page |
admin.collection-details.block.render | Collection detail page |
admin.discount-details.block.render | Discount detail page |
admin.abandoned-order-details.render | Abandoned checkout detail |
List Pages
| Target | Where it renders |
|---|---|
admin.product-list.render | Products list |
admin.order-list.render | Orders list |
admin.customer-list.render | Customers list |
admin.collection-list.render | Collections list |
admin.abandoned-order-list.render | Abandoned checkouts list |
admin.gift-card-list.render | Gift cards list |
admin.blog-list.render | Blogs list |
admin.contact-list.render | Contact submissions |
admin.newsletter-list.render | Newsletter subscribers |
Settings Pages
| Target | Where it renders |
|---|---|
admin.settings.render | Main settings page |
admin.shipping-settings.render | Shipping settings |
admin.payment-settings.render | Payment settings |
admin.pos-settings.render | POS settings |
admin.account-settings.render | Account settings |
Analytics
| Target | Where it renders |
|---|---|
admin.analytics.render | Main analytics dashboard |
admin.sales-analytics.render | Sales analytics page |
admin.product-analytics.render | Product analytics page |
admin.inventory.render | Inventory page |
Other
| Target | Where it renders |
|---|---|
admin.order-create.render | Order creation page |
admin.app.configuration | App configuration screen (no .render suffix) |
The slot string is matched exactly —
product.details.block won’t
render at admin.product-details.block.render. Always copy the target
value verbatim from the table above.Targets not in the tables above won’t render even if the API accepts the
upload — only the wired slots resolve. If you need a new target,
open a support ticket with the page and resource type you want.
Manifest
Declare admin blocks underextensions.adminExtensions[] in your app’s
app.json:
| Field | Required | Description |
|---|---|---|
handle | yes | URL-safe identifier unique within the app. |
target | yes | One of the wired slots above. |
url | yes | HTTPS URL loaded into the iframe. appUrl is an accepted alias. |
title | no | Display label (defaults to handle). |
iconUrl | no | URL of an SVG/PNG icon. |
permissions | no | Array of permission strings — purely informational at this time. |
Relative URLs (e.g.
/extensions/.../iframe.html) are absolutised by the
host before being returned to the admin. You always get back an absolute,
HTTPS-only URL — no domain-resolution surprises inside the iframe.Iframe URL Parameters
The host appends the following query params when building the iframesrc:
| Parameter | Always set | Value |
|---|---|---|
target | yes | The extension’s manifest target. |
domainSlug | yes | The merchant’s domain slug. |
extensionId | yes | The host-assigned extension id. You must echo this on APP_BRIDGE_RESIZE messages so the host filters them correctly. |
host | yes | btoa(window.location.origin) — base64-encoded admin origin, used to initialise the App Bridge SDK. |
resourceId | optional | Present when the slot was rendered with a resourceId prop (e.g. on admin.product-details.block.render). |
resourceType | optional | Present together with resourceId — e.g. "product", "order". |
Bootstrap
Initialise the App Bridge SDK with theapiKey you registered the app
under, and the base64 host from the URL:
app.dispatch(action, payload) and app.dispatchAndWait(action, payload)
take an action string and a payload object — not a {type, payload}
envelope.
Resizing the Iframe
The iframe starts at 200px. To grow it, post the resize message directly — this one is not routed throughapp.dispatch:
extensionId matches. Omit extensionId and the resize is ignored —
your iframe stays empty-looking at 200px.
A typical auto-resize hook using ResizeObserver:
App Bridge Actions (Admin host)
Admin blocks can use the full admin App Bridge action set. See App Bridge Overview for the complete reference. Common calls:Show a toast
Open a modal
Navigate
Resource picker
Session token (for backend calls)
The SDK does expose
LOADING_START / LOADING_STOP actions (dispatched
by the React useLoading hook) that draw a thin progress bar on the
admin host’s title bar. They’re for host-level affordance — inside
your block iframe, render loading skeletons in your own UI rather than
relying on the global bar.Example: Reviews Panel
Discovery API
GET /api/apps/admin-extensions?target=<target>&domainSlug=<slug> returns
all installed extensions for that target. Pass &type=admin_block to
exclude action and print-action entries that also live in
/api/apps/admin-extensions.
url and appUrl fields are server-absolutised so the admin always
receives an iframe-able HTTPS URL.
Security
Iframe sandbox
Iframe sandbox
Admin blocks render with
allow-scripts allow-same-origin allow-forms allow-popups. The bridge postMessage protocol is the only cross-frame
channel.Verify session tokens server-side
Verify session tokens server-side
Anything the iframe sends to your backend should be authorised with a
fresh session token (
app.getSessionToken()) and verified against your
app’s clientSecret server-side.HTTPS only
HTTPS only
url / appUrl must be HTTPS. HTTP URLs are rejected by the install
validator.Validate URL parameters
Validate URL parameters
resourceId and domainSlug come from the merchant’s browser. Always
re-fetch the resource server-side with the session token before
trusting it.Installing
Admin blocks are declared inapp.json; the install pipeline doesn’t write
per-handle schema files for them (unlike admin actions and print actions).
Instead, each adminExtensions[] entry is fanned out into a registry row
scoped to (appId, storeId, handle, target) so the discovery API can
return it.
Registry fan-out runs automatically on both install paths:
- OAuth install — when the merchant completes
POST /apps/oauth/tokenwithgrant_type=authorization_code, the install pipeline creates the installation, then synchronously registers everyadminExtensions[]entry from your app’s published manifest. - Direct/developer install —
POST /apps/store/install/:appIdruns the same fan-out.
(appId, storeId, handle, target) are
upserted, not duplicated. Uninstall destroys all registry rows for that
(appId, storeId) pair.
The target column accepts any string verbatim — there is no enum cap on
what you can register — but as noted above the host only renders entries
whose target matches one of the wired slot tables.
See Also
- Admin Actions — modal-iframe action buttons.
- Admin Print Actions — printable templates triggered from admin resource pages.
- App Bridge Overview — full action reference.
- Sessions & Authentication — verifying iframe calls server-side.