@aforoai/storefront-widgets
v1.0.12
Published
Embeddable widgets for Aforo's storefront — pricing card, subscribe button, invoice list, and embedded checkout. Drop into any HTML page, React app, or Vue app to add Aforo billing surfaces with your own branding. Three integration tiers: script tag, npm,
Maintainers
Readme
@aforoai/storefront-widgets
Drop-in embeddable widgets for Aforo's storefront — pricing cards, subscribe buttons, invoice lists, and embedded checkout. Brand them yours, ship in minutes.
npm install @aforoai/storefront-widgetsFull developer docs: https://docs.aforo.ai/docs/embed-quickstart
What you get
Eight widgets covering the customer billing surface. v0.1.0 ships four real widget bodies — the other four render an accessible loading placeholder while their bodies are being built. Their public API is locked, so dropping in the new bundle later requires no code changes on your side.
| Widget | Status | What it does |
|-----------------------------|-----------------|---------------------------------------------------|
| AforoPricingCard | ✅ Shipped | Anonymous pricing display (horizontal / vertical / table) |
| AforoSubscribeButton | ✅ Shipped | Authenticated subscribe CTA with anti-double-subscribe check |
| AforoInvoiceList | ✅ Shipped | Paginated invoice list with status filter, search, PDF, Pay Now |
| AforoCheckoutFlow | ✅ Shipped | Multi-step embedded checkout (Stripe / Razorpay / PayPal) |
| AforoSubscriptionManager | 🔜 Coming soon | Customer-facing subscription summary + lifecycle actions |
| AforoUsageMeter | 🔜 Coming soon | Real-time per-metric usage gauges with quota visualization |
| AforoPaymentMethod | 🔜 Coming soon | Saved payment methods table + add/remove flow |
| AforoUpgradeCancel | 🔜 Coming soon | Plan upgrade / downgrade / cancel flow with deflection |
Three ways to embed
1. Script tag (no build needed)
For Webflow, WordPress, Squarespace, and plain HTML pages. The loader is ~2.5 KB gzipped and lazy-fetches per-widget bundles only when their placeholders are on the page.
<script
src="https://embed.aforo.ai/v1/loader.js"
integrity="sha384-…"
crossorigin="anonymous"
async
></script>
<div
data-aforo-widget="pricing-card"
data-tenant-slug="acme"
data-embed-key="embk_live_…"
data-layout="horizontal"
></div>The current SRI hash for loader.js is at
https://embed.aforo.ai/v1/sri.json. Copy it into the integrity=
attribute on the <script> tag so the browser refuses to execute a
tampered bundle.
2. React / Next.js
import { AforoPricingCard } from '@aforoai/storefront-widgets';
export function PricingSection() {
return (
<AforoPricingCard
tenantSlug="acme"
embedKey="embk_live_…"
layout="horizontal"
ctaUrlByOffering={{ off_pro: '/checkout/pro' }}
/>
);
}3. Vue 3
<script setup>
import { AforoPricingCard } from '@aforoai/storefront-widgets/vue';
</script>
<template>
<AforoPricingCard
tenant-slug="acme"
embed-key="embk_live_…"
layout="horizontal"
/>
</template>Vanilla JS consumers (Svelte, Solid, Lit, etc.) import from
@aforoai/storefront-widgets/vanilla — the same mount/unmount API the
loader script uses internally.
Authentication modes
The plugin tier supports three auth modes depending on what your portal already has:
Anonymous — pricing display only, no customer context. Use this for marketing pages where you want to show your live offerings without asking visitors to sign in.
Bridge token — your backend mints a short-lived signed token that identifies your customer to Aforo. The widget exchanges it for an in-memory session JWT — your signing key never reaches the browser. Use this when your portal already has its own authenticated session.
Magic link — for portals that don't have their own session yet. The customer types their email, gets an Aforo-branded email, clicks the link, and lands back on your page with a session JWT. Rate-limited and anti-enumeration-defended out of the box.
Full guide with sequence diagrams + code samples for Node.js / Python / Go bridge-token signing: https://docs.aforo.ai/docs/embed-authentication.
Theming
Three-layer cascade — each layer overrides the previous:
- Tenant brand kit (logo + colors) configured in Aforo's Storefront → Customize, fetched once when the widget mounts.
- CSS variables on your page (e.g.
--aforo-color-primary: #1A73E8;) override the brand kit for fine-grained theming. - Per-widget
themeOverridesprop for in-React/Vue customization at the component level.
Dark mode is opt-in via theme="dark". The widgets are RTL-safe (100%
logical CSS properties) and namespace every class
(aforo-w-pc-*, aforo-w-sb-*, etc.) to avoid colliding with your CSS.
Full theming docs: https://docs.aforo.ai/docs/embed-theming.
Events
Every widget emits typed postMessage events you can listen to from the
parent page. Origin is always the resolved parent origin — never *.
window.aforoEmbed?.on('aforo.subscribe.checkout_requested', (payload) => {
console.log('Customer clicked subscribe', payload);
// payload = { offeringId, planName, priceCents, currency, billingCycle, ratePlanId }
});Common events:
| Event | When |
|--------------------------------------|-----------------------------------------------|
| aforo.<widget>.ready | Widget mounted and first paint complete |
| aforo.subscribe.checkout_requested | Customer clicked Subscribe |
| aforo.subscription.created | Subscribe checkout completed (advisory only) |
| aforo.invoice-list.invoice.paid | Invoice marked paid via SSE push |
| aforo.checkout.confirmed | Embedded checkout completed |
| aforo.<widget>.error | Any error path (typed code, no PII) |
⚠ Webhook is authoritative. postMessage events fired into your page are advisory only. Always validate state changes via Aforo's signed webhooks before mutating your own database. We surface this prominently because it's the most common source of integration bugs.
Full event catalog: https://docs.aforo.ai/docs/embed-events.
Browser support
We test against the latest two stable versions of every major browser. The SDK runs anywhere modern JavaScript runs.
| Browser | Minimum version | Notes | |--------------------|-----------------|-------| | Chrome | N-2 (latest 2) | Desktop and Android | | Firefox | N-2 | Desktop | | Safari | 16+ | macOS | | Mobile Safari | iOS 16+ | iPhone + iPad | | Mobile Chrome | Android 12+ | Most devices | | Edge | Latest | Chromium-based |
The loader refuses to bootstrap on http:// pages — HTTPS is mandatory.
We do not support IE11 or pre-Chromium Edge.
Security
- SRI hashes published per release at
https://embed.aforo.ai/v1/sri.json. Pin them via
integrity=on the<script>tag. - Customer CSP guidance. Add
script-src https://embed.aforo.aiandconnect-src https://api.aforo.aito your Content-Security-Policy. Nounsafe-inlineorunsafe-evalrequired. - In-memory session JWTs. Never written to
localStorage,sessionStorage, or cookies. Cleared on tab close. - Anti-enumeration on magic-link. Identical 202 response regardless of whether the email is registered. Rate-limited per IP and per email.
- No dynamic code. No
eval(), noFunction(), no dynamicimport()of untrusted URLs.
Full security model + how to report vulnerabilities: see
SECURITY.md.
Versioning
We follow Semantic Versioning. Pre-1.0:
0.x.y— frequent additions, occasional breaking changes documented in CHANGELOG.md. Pin to a specific version in production.
Post-1.0:
1.x.y— strict semver. Additions and bug fixes only.2.x.y— breaking changes with a 90-day deprecation period announced via the changelog. The loader URL is pinned at/v1/and stays backward-compatible within v1.
Full versioning policy: https://docs.aforo.ai/docs/embed-versioning.
License
MIT — see LICENSE.
Support
- 📖 Docs: https://docs.aforo.ai/docs/embed-quickstart
- 🐛 Issues: https://github.com/aforoai/aforo-nextgen-UI/issues
- 🔒 Security:
[email protected] - 💬 Email:
[email protected]
