Embed Widgets: Integration Patterns
End-to-end worked example, common pitfalls, production checklist, migration paths, and concurrent-widget shared auth state.
End-to-end: "Acme Corp" example#
Acme Corp sells a developer API. They want to:
- Show pricing on their public marketing page
- Let signed-in customers self-serve subscribe
- Let signed-in customers view and pay invoices
Step 1 — Operator setup (one-time)
- Sign up at
app.aforo.ai - Configure brand kit (logo, primary color) under Storefront → Customize
- Publish at least one offering with a rate plan
- Open Embed Studio → Keys → Mint a new embed key. Add allowed domains:
https://acme.com(marketing)https://app.acme.com(portal)https://staging.acme.com(staging)
- Open Embed Studio → Auth Bridge → Mint a NEXT signing key. Promote it to ACTIVE. Store the secret in your secret manager.
Step 2 — Pricing page (anonymous)
Drop a PricingCard on acme.com/pricing. No bridge token needed.
Step 3 — Subscribe button on the portal
After the customer signs in on app.acme.com, the portal mints a bridge token server-side and renders the button:
Step 4 — Invoice list on the account page
Step 5 — Webhook handler for the source of truth
Set up a webhook receiver on app.acme.com/api/aforo/webhook. When subscription.created fires, Acme writes to their database, provisions API keys, and sends a welcome email — all driven by the signed webhook, not the widget's postMessage event.
Common pitfalls#
Production readiness checklist#
Before flipping a widget to production, check off:
Migration paths#
From headless API (T6)
If you're already consuming Aforo's headless API and rendering your own UI, the plugin tier lets you swap individual surfaces incrementally. Start with the lowest-touch one (PricingCard on a marketing page), then migrate the customer portal flows. The headless API stays available — you can mix tiers freely.
From managed storefront (T1)
If you're using Aforo's managed storefront and want more control over branding and routing, the plugin tier is the bridge. Keep the managed storefront for the flows you don't want to own, and embed plugin widgets for the surfaces you do.
Concurrent widgets — shared auth state#
Pages often mount multiple widgets at once — for example, a customer portal might show an InvoiceList plus a UsageMeter plus a SubscribeButton (upsell) on the same page.
The SDK shares one bridge exchange + one SSE connection per tenant across all mounted widgets. If three widgets all need the session JWT, the SDK fires one bridge-exchange HTTP request and shares the result. This is enforced by an internal promise-coalescing map keyed on tenant slug.
tenantSlug and embedKey to every widget on the page. Different slugs spawn different sessions.See the for the session lifecycle (init → getSessionJwt → refresh → destroy).