Storefront embedding
Status: Plan / RFC. The
sellub-embedpackage and proxy-fidelity integration are tracked atPLATFORM-STATUS.md.
This document describes the plan for embedding Sellub marketplace surfaces (product listings, checkout, seller dashboard) into 3rd-party host sites such as Proxy Fidelity loyalty pages.
Use case: Proxy Fidelity
Proxy Fidelity is a loyalty/identity platform whose merchants want to:
- Show their catalog as part of the loyalty page (browse + redeem).
- Let members check out with loyalty discounts applied — without leaving the loyalty experience.
- Offer the merchant a light dashboard view (orders, inventory) inside the Proxy Fidelity merchant console.
Three embedding modes
| Mode | What’s embedded | Trust model |
|---|---|---|
| A. Headless SDK | None — host queries Sellub API directly | Host owns UI; uses API key |
| B. iframe widgets | Sellub-rendered widgets via <iframe> | Sandboxed; postMessage bridge |
| C. Web component | <sellub-checkout> custom element | Loaded from CDN; styled by host |
Recommended path: B for checkout (PCI / payment isolation) and A for catalog browsing (best UX, host CSS).
Mode A — Headless via @duabalabs/sellub-client
Host site uses the existing SDK to query Sellub directly.
import { createShopClient } from "@duabalabs/sellub-client";
const sellub = createShopClient({
endpoint: "https://api.sellub.com/shop-api",
channelToken: PROXY_CHANNEL_TOKEN, // per-merchant Vendure channel
});
// Query products
const { products } = await sellub.query(`
query {
products(options: { take: 24 }) {
items { id name slug featuredAsset { preview } variants { priceWithTax } }
}
}
`);Required SDK additions
To make this fully usable for the Proxy Fidelity catalog, sellub-client needs:
sellub.delivery.estimates({ destinationCity })→ wraps thedeliveryEstimatesquery (now multi-source aware).sellub.delivery.sources({ sellerId? })→ optional helper for “carrier picker” widgets.- Better-typed
searchProducts,addToCart,transitionToStatehelpers (today onlyquery/mutateraw escape hatches plus a few cart ops).
These are tracked under the D7 storefront workstream.
Mode B — <iframe> checkout widget
The host site renders its own catalog (Mode A) but delegates payment to a
Sellub-hosted checkout iframe at https://checkout.sellub.com/embed.
<iframe
src="https://checkout.sellub.com/embed?cart=<cartId>&theme=light"
width="100%"
height="640"
allow="payment *"
></iframe>
<script>
window.addEventListener("message", (e) => {
if (e.origin !== "https://checkout.sellub.com") return;
if (e.data.type === "sellub:checkout:complete") {
window.location.href = "/loyalty/order-success";
}
});
</script>postMessage events emitted by the iframe:
| Event | Payload |
|---|---|
sellub:checkout:ready | — |
sellub:checkout:resize | { height } |
sellub:checkout:cart_updated | { totalWithTax, currency } |
sellub:checkout:complete | { orderCode } |
sellub:checkout:error | { message, code } |
Why iframe for checkout?
- PCI scope isolation — Paystack widget stays inside Sellub’s origin.
- Channel auth — iframe carries Sellub session cookie scoped to the channel without leaking it to host.
- Cart consistency — host can’t tamper with line totals.
Mode C — Web component (future)
<script src="https://cdn.sellub.com/embed/v1.js" async></script>
<sellub-product-grid channel="proxy_fidelity_acme" take="24"></sellub-product-grid>
<sellub-checkout cart-id="abc123"></sellub-checkout>This wraps Modes A/B with a CSS-isolated shadow DOM. Lower priority — only needed when host sites can’t run the iframe approach.
Auth & multi-tenancy
Each embedding host gets:
- A dedicated Vendure channel (
proxy_fidelity_<merchant>) - A channel token for read queries (safe to expose in client JS)
- An API key (server-side only) for write operations
Proxy Fidelity’s own auth (loyalty member login) is mapped to a Sellub
Customer record using the existing
@duabalabs/sellub-types external auth bridge
(planned).
Delivery in embedded checkout
The iframe checkout already supports the multi-source delivery system shipped in the latest sellub-server release:
- One option per (seller, carrier) combination.
- “via Ghana Post / DHL / your in-house courier” subtitle on each option.
- ETA per option.
Host sites do not need to know about delivery sources — they’re rendered automatically inside the iframe.
Roadmap
| Phase | Deliverable | Status |
|---|---|---|
| 1 | Mode A SDK delivery helpers | 🔴 STUB (packages/sellub-client/src/shop-client.ts) |
| 2 | Mode B iframe origin (checkout.sellub.com/embed) | 🔴 STUB (apps/sellub/sellub-storefront) |
| 3 | postMessage protocol | 🔴 RFC (this doc) |
| 4 | Proxy Fidelity adapter package | 🔴 not started |
| 5 | Web component wrapper | 🔴 not started |
Track: PLATFORM-STATUS.md
under “Embeddable surfaces”.