Paywall Blueprint
The first publicly available worked example of monetizing a Sitecore Marketplace App — a foundation tranche, a real Stripe Checkout integration, and two adapter seams ready to swap.
What it is
Sitecore's Cloud Portal Marketplace ships no built-in commerce primitives. Every team that wants to charge for a Marketplace App starts from zero on every decision — which provider, how to map Cloud Portal tenants to subscription objects, how to enforce seats inside an iframe sandbox, what to show editors when access is denied, how to handle reinstalls, how to wire webhooks back to entitlements. The result is an ecosystem that stays effectively free-only because the per-app cost of inventing a paywall in isolation is too high.
Paywall Blueprint is the first publicly available worked example of
monetizing a Sitecore Marketplace App. It is a public OSS reference
app on the SitecoreAI Full Screen extension point that demonstrates a
freemium pattern — free piece + gated premium piece on one page — plus
a complete denial-state UX library, all driven by a <PaywallGate>
React wrapper and an entitlement store.
The reference app itself has no real feature behind the paywall. The paywall flow IS the feature. Fork the repo, replace the placeholder concerns through two clean adapter seams, ship a monetized Marketplace App without reinventing the gating pattern.
(000 · 001 · 002 · 003)
(foundation + Stripe)
across both PRDs
green at PRD-000 ship
The roadmap, named up front
The product is deliberately architected as four PRDs so adopters can copy at any layer of completeness. Each PRD ends in a ship; each ship stands on its own.
The two adapter seams
The whole product hinges on two abstraction boundaries that adopters can swap on the day they fork the repo. Each one has a placeholder implementation in PRD-000 and a real one in PRD-001 (PaymentProvider) or PRD-002 (EntitlementStore polish).
The PRD-001 captures
Wiring Stripe Checkout into a Marketplace iframe end-to-end returned a specific stack of integration captures. None of them are in the Stripe docs in the form they ship as inside Cloud Portal. Each one became an ADR.
CSP frame-ancestors must allow-list the host.
The sitecore:setup-marketplace-full-stack scaffold ships a default frame-ancestors that omits app.sitecorecloud.io. Cloud Portal embeds from that host. Add it before first real-tenant smoke or the iframe never loads.
stripe listen needs https:// + --skip-verify against next dev --experimental-https.
The CLI defaults to http:// and silently fails when the dev server runs HTTPS. Pass https://localhost:3000/... explicitly and --skip-verify (mkcert is self-signed). Copy a fresh whsec_* from each listen session into .env.local and restart dev.
automatic_tax requires customer_update.address.
automatic_tax: { enabled: true } against an existing Customer without an address throws customer_tax_location_invalid. Fix: customer_update: { address: 'auto', name: 'auto' } on the Checkout Session params.
Idempotency keys cache params — version the key.
Stripe caches the params shape against the first idempotency-key submission for 24h. Same key + changed params = rejected. Build the key as ${id}:${PARAMS_VERSION} and bump the version constant when the params shape changes. Self-documenting changelog.
Subscription.current_period_end was removed from the SDK type — but still ships at runtime.
stripe@22.x migrated current_period_end to per-item but webhook payloads still ship it at the top level. Cast through unknown as Record<string, unknown> to read it without losing type discipline elsewhere.
Post-payment refresh needs a visibilitychange listener.
External-tab payment flows carry no payload back to the iframe; webhook + DB is the truth. Polling alone has a finite window. A visibilitychange listener catches returns after polling timeout — and returns from previous sessions — so the iframe always reconciles. Build pattern, not a workaround.
What the methodology shifted
PRD-000's Tranche 1 ran the same kind of two-day real-tenant probe that
Redirect Manager made
unavoidable. The Paywall Blueprint probe asked a different question —
not "is this possible" but "is this key the right key" — and got a
green verdict on marketplaceAppTenantId as the entitlement key, plus
the side-finding that host.user is a separate SDK query rather than a
property on tenant context.
That second finding was the move that pushed seat-aware evaluation cleanly into a future PRD (ADR-0011). Without the probe, PRD-000 would have shipped with a confused seat shape, or stretched its scope to include seats, or both. With it, Phase 0 ran as a deliberate minimum-viable foundation — a shippable reference that an adopter could install, read, and copy from on day one, while the differentiated SDK surfaces (Stripe billing, seat enforcement, customer portal) layered on top in subsequent PRDs against a verified key.
The methodology pattern from the Real-Tenant Probe applied:
- Two-day cap — probe ended in a day on this product.
- One assumption, named — tenant-only evaluation, with the marketplaceAppTenantId as the durable key.
- Three legitimate outcomes — green for tenant-only PRD-000; yellow on seat enforcement (workaround = queue it); red would have killed the product before PRD-000 ever opened.
- The capture is the artefact — the SDK identity table is now a reference memory that PRD-002 and PRD-003 will inherit.
Where this leaves the loop
Paywall Blueprint is the sixth Marketplace product shipped through the full agentic pipeline (after PageShot, QuickCopy, Component Atlas, Last-Edit Trail, and Redirect Manager). It is the first of them designed as a public reference rather than a focused product — "Blueprint" is in the name on purpose.
The four-PRD shape is the methodology contribution that scales beyond this product. Foundation → real provider → polish → portal is the same shape any monetized Marketplace App can copy. The provider and the entitlement store are seams, not assumptions. The probe before each PRD is the gate. The dogfood loop hardens the skills as each PRD ships. The pipeline runs the inside half; the operator runs the outside half against a real tenant.
If you're building a paid Sitecore Marketplace App, start by reading the public repository. Adopt the seams. Probe your own load-bearing assumption in two days. Ship the foundation tranche first; layer the provider second. The hard work is in the captures — and the captures are already done.
Related case studies