Miniwall Docs
SDK

Embed a screen

Draw a screen inline inside your own layout, like a pricing section or an onboarding step.

Embedding draws a screen inside your own layout instead of over the page or app. Use it for a pricing section, an onboarding step, a settings page or anywhere the screen is part of the layout.

function mountPaywall(container: HTMLElement, options: PaywallOptions): Promise<PaywallHandle>;
import { configure, mountPaywall } from '@ui-kit/web';

configure({ apiKey: 'pk_...' });

const handle = await mountPaywall(document.querySelector('#pricing'), {
  paywall: { placement: 'pricing' },
  products: { annual: { price: 59.99, currency: 'USD', period: 'year' } },
  onPurchase: async ({ packageId }) => startCheckout(packageId),
});

handle.destroy(); // later, to remove it

The same thing exists as a tag (Web component) and as a component (React).

Options

Embedding takes the same options as Present a screen except the display ones (no mode, style, position, size, duration or closeOnBackdrop): the screen is part of your layout. A placement's display format and trigger are ignored.

OptionWhat it does
SourceRequired. Placement, paywall ID, JSON (web also URL).
products, variablesPerPackage, customVariables, locale, colorMode, screens, attributesAs in Present a screen. Web also takes maxContentWidth.
CallbacksonPurchase, onRestore, onAction, onAnswer, onOpenUrl, onError (web also onClose, onSkip). See Callbacks.
onFinishiOS and Android only: called once with the result when the screen ends (purchased, restored, closed, action or skipped).

The handle (web)

mountPaywall returns a handle once the screen is drawn.

MemberWhat it does
destroy()Removes the screen and frees its resources. Safe to call more than once.
answers()The answers given so far, across every screen of a flow. {} when there are no questions.
shownfalse when targeting chose to show nothing. Nothing was drawn.
skipReasonfrequency_cap, audience or holdout.

How it differs from present

  • It stays in your layout. A purchase, restore, button press or close does not remove the screen. Your callbacks run (web) or onFinish runs (mobile), and you decide what to do next: call handle.destroy() or change your own layout.
  • No result. On web the promise resolves once the screen is drawn; results come from the callbacks. On mobile results come from onFinish.
  • Skipped placements draw nothing. The container stays empty (shown: false and onSkip on web, onFinish with skipped on mobile). Make sure your layout still looks right.
  • Load failures. On web the promise rejects (wrong key, unknown placement, no network and no saved copy; see Errors). On mobile the view stays empty and onError is called.
  • Flows ("Go to another screen" buttons) replace each other inside the container.
  • No overlay behaviour. No focus trap, no scroll lock, no sheet or cover. The screen is as wide as the space you give it; give the container the width you want.

On web the SDK appends one div[data-ui-kit-paywall] to your container (display: block, as wide as the container) and draws inside a shadow root. maxContentWidth can narrow it.

On this page