An embedded app (app_type: embedded) renders its UI inside the PlatformDTC dashboard at /apps/installed/<your-handle>. The dashboard loads your embedded_app_url in an iframe and talks to it through App Bridge, a small script served from the PlatformDTC CDN, over an origin-locked postMessage channel. If you have built a Shopify embedded app, the model is the same: short-lived session tokens authenticate your frontend to your backend, and token exchange gives your backend the install’s offline access token without any redirect after install.

How your app is loaded

The iframe is sandboxed without top-level navigation: to send the merchant elsewhere in the dashboard, use app.navigation.redirectToAdmin(). Your embedded_app_url must be https.

Set up App Bridge

App Bridge is an ES module on the PlatformDTC CDN. Nothing to install: load it by URL, the way Shopify apps load App Bridge from cdn.shopify.com. Map the module name in an import map on your embedded page, then import it from your own scripts:
Or import the URL directly: import { createApp } from 'https://cdn.platformdtc.com/app-bridge/v1/app-bridge.js';. If your page sends a Content-Security-Policy, allow https://cdn.platformdtc.com in script-src (and the import map’s hash, if it is inline). The dtc app init starter does both.
Paths are relative to your embedded_app_url’s origin. /embedded/settings shows in the admin as /apps/installed/<handle>/embedded/settings. Reloading that URL reopens your iframe on https://<your origin>/embedded/settings.

Admin navigation

Declare nav_links on an app version. They appear in the merchant’s sidebar under your app while it is open. Like scopes, they are part of the version and go through review.
A destination must start with /. You can declare up to 20 links, each label up to 64 characters.

Session tokens

App Bridge gets a session token from the dashboard for each idToken() call. It is an HS256 JWT signed with your client secret and expires 60 seconds after it is issued. Verify every request on your backend. Check the signature, aud, iss, exp and nbf, and allow about 10 seconds of clock skew. Reject a failure with 401. To have App Bridge retry once with a fresh token, also send the header X-PlatformDTC-Retry-Invalid-Session-Request: 1.

Token exchange

Your backend swaps a session token for the install’s offline sq_agt_* token (RFC 8693). No redirect is needed after install.
The dated route POST /api/v1/appstore/2026-08/oauth/token accepts the same grant.
Every exchange issues a new token and retires the previous one. Offline tokens are stored only as hashes, so the platform cannot return a token it issued earlier. The retired token keeps working for 15 minutes so in-flight requests finish, then stops. Exchange once, store the token against install_id, and exchange again only when you have no token or it returns 401.
Rules the token endpoint enforces:
  • Each session token can be exchanged once (its jti).
  • The session’s install must belong to your app and be installed. A pending_reauth install needs the merchant to reauthorize first.
  • Only embedded apps can use this grant. Online (per-user) tokens are not supported.
  • After you rotate your client secret, authenticate with either secret during the 72-hour grace window. Session tokens are signed with the new secret straight away.
Uninstalling revokes every token issued for the install, retired ones included.

Security model

  • App Bridge posts only to the admin origin decoded from host. It accepts messages only from that origin and from its parent window.
  • The dashboard accepts messages only from your embedded_app_url origin and your iframe, and replies only to that origin.
  • The offline token never passes through postMessage or the browser.
  • Text you send (toasts, modal content, labels, titles) is shown as plain text and truncated.