@billdog.io/web
v1.0.0-beta.1
Published
BillDog SDK for Web - Platform-specific implementation with web features
Maintainers
Readme
@billdog.io/web
Web implementation of the BillDog SDK. Extends @billdog.io/core with browser-native paywall mounting (via the unified @billdog.io/paywall-renderer), Stripe Checkout redirect for purchases, localStorage persistence, and event-bus parity with the iOS / Android / React Native / Flutter SDKs.
Installation
npm install @billdog.io/web @billdog.io/paywall-renderer react react-domreact and react-dom are peer deps because the paywall renderer is a React component. If your app is already React-based, you already have them.
Quick start
import BillDog from '@billdog.io/web';
BillDog.configure({
apiKey: 'bd_prod_xxxxxxxx',
projectUrl: 'https://<project>.supabase.co',
enableLogging: true,
});
// Identify the user before fetching a paywall.
BillDog.setCustomerId('user_123');
// Subscribe to the canonical purchase-completed event. This fires when
// the browser returns from Stripe Checkout with a successful session.
BillDog.eventBus.subscribe('purchase_completed', (event) => {
console.log('Purchase completed:', event);
// Refresh entitlements / unlock features here.
});
// Present a paywall by placement id.
await BillDog.presentPaywall('premium_offer', {
mode: 'modal', // 'modal' (default) or 'inline'
onPurchase: (productId) => console.log('Purchase initiated for', productId),
onDismiss: () => console.log('Paywall closed without purchase'),
onError: (err) => console.error('Paywall failed:', err),
});What happens under the hood
configurecachesapiKey+projectUrl, initializes@billdog.io/core, and inspectswindow.location.searchforbd_purchase=success/bd_purchase=cancel(set when Stripe Checkout redirects back). On success → firespurchase_completedon the inheritedeventBusand strips the query param.presentPaywall(placementId)calls the inheritedgetWall(placementId, customerId)(which hits the/decide-contentedge function), then mountsSDKPaywallAppfrom@billdog.io/paywall-rendererinto a modal overlay ondocument.body. The renderer's React props (onPurchase/onDismiss/onRestore/onTrackEvent) are wired to the consumer-supplied callbacks AND to the inheritedpurchaseManager.- Purchase flow — when the user clicks a buy button inside the paywall, the renderer fires
onPurchase(productId). The Web SDK callspurchaseManager.purchaseProduct(...), which delegates toWebPurchaseDelegate.purchaseProduct, which POSTs tocreate-web-checkout, receives a Stripe Checkout URL, and navigates the browser to it. Stripe-hosted Checkout handles the rest; on success, the browser returns to the original page withbd_purchase=successand theconfigure-time return-flow handler firespurchase_completed.
Inline mode
For embedded paywalls inside a host page (rather than overlaying):
await BillDog.presentPaywall('premium_offer', {
mode: 'inline',
mountTo: '#paywall-slot', // CSS selector or HTMLElement
});Surveys
await BillDog.presentSurvey('survey_id', {
customerId: 'user_123',
onComplete: (surveyId, result) => console.log('Submitted', result),
});Storage
const storage = BillDog.getStorageAdapter();
await storage.setItem('preference', 'dark_mode'); // namespaced as 'billdog_preference'
const value = await storage.getItem('preference');Event bus
Cross-platform event names emitted on the inherited eventBus:
| Event | When |
|---|---|
| purchase_completed | Stripe Checkout returned to bd_purchase=success |
| purchase_cancelled | Stripe Checkout returned to bd_purchase=cancel |
| entitlements_changed | CustomerManager detected entitlement change |
Same-window DOM events
The presenter also dispatches DOM-level CustomEvents for vanilla-JS consumers who don't want to use the event bus:
billdog:paywall_dismissed—{ placementId }billdog:paywall_purchase_started—{ placementId, productId }billdog:paywall_restore_started—{ placementId }billdog:survey_completed—{ surveyId, result }billdog:survey_dismissed—{ surveyId }
Public API
| Method | Description |
|---|---|
| configure(config) | Initialize the SDK, register modules, wire return-flow handler |
| setCustomerId(id) | Identify the current user |
| presentPaywall(placementId, options?) | Mount paywall to DOM and route events |
| dismissPaywall() | Programmatically close the active paywall |
| presentSurvey(surveyId, options?) | Mount survey overlay |
| getStorageAdapter() | Return the LocalStorageAdapter |
| destroy() | Tear down listeners + unmount overlays |
| eventBus.subscribe(name, fn) | Subscribe to platform events |
All methods inherited from @billdog.io/core (trackEvent, getWall, getCustomerInfo, etc.) remain available.
Deferred to a follow-up release
- Stripe.js modal-mode purchase — Pass 2. Today the SDK redirects to Stripe-hosted Checkout; modal mode (Stripe Elements inline) is a separate work item that adds ~50 KB to the bundle.
restorePurchases()— currently a no-op returningfalse. Web restore is fundamentally different from native (no App Store / Play Store receipts); the planned shape callscheck-entitlement/get-customer-infoand rebuilds the localcustomerInfocache.- Inline error / cached-fallback UI — currently errors bubble through
onError. Pass 2 adds a default error renderer + offline-mode fallback that reads the last good paywall config fromlocalStorage. - Framework wrappers — React hook (
useBillDog), Vue composable, Svelte store — thin layers over the singleton. None are required to use the SDK today.
Browser support
Chrome 90+, Firefox 88+, Safari 14+, Edge 90+.
License
MIT
