Miniwall Docs
Web SDK

Quickstart

Show a screen from a placement on your site, pass it prices, and run your own checkout when someone buys.

This page takes you from a published screen to a working screen on your site. It uses a placement, so you can change the screen later without a deploy.

What you need

  • A published screen and a placement that points at it. See Placements.
  • A public key from Install SDK or API keys.
  • The IDs of the packages on the screen. Each package card has an ID set in the editor (see Packages and pricing). The Install SDK page lists them for the screen you pick.

Show the screen

Add the script and set your key. Use the URL that the Install SDK page shows.

<script src="https://sdk.miniwall.app/ui-kit.iife.js"></script>
<script>
  UIKit.configure({ apiKey: 'pk_...' });
</script>

Open the screen from a button. Pass a price for every package ID on the screen, and run your checkout in onPurchase.

<button id="upgrade">Upgrade</button>
<script>
  document.querySelector('#upgrade').addEventListener('click', async () => {
    const result = await UIKit.presentPaywall({
      paywall: { placement: 'upgrade_button' },
      products: {
        monthly: { price: 9.99, currency: 'USD', period: 'month' },
        annual: { price: 59.99, currency: 'USD', period: 'year' },
      },
      onPurchase: async ({ packageId }) => {
        // Your checkout (Stripe, Paddle, your backend...).
        // Return true when paid, false when the visitor cancelled. Throw on failure.
        return startCheckout(packageId);
      },
    });
    console.log(result);
  });
</script>

Handle the result. presentPaywall always resolves with an object whose outcome tells you what happened:

if (result.outcome === 'purchased') unlockPro(result.packageId);
if (result.outcome === 'skipped') console.log('Not shown:', result.reason);

That is a complete integration. The paywall opens as a popup (or in the format you chose on the placement), shows your prices, calls onPurchase when the visitor taps buy, and closes.

Results you can get

outcomeWhenExtra fields
purchasedonPurchase finished without returning false.packageId, answers if any
restoredonRestore finished without returning false.answers if any
closedThe visitor closed the screen (close button, Esc, backdrop click, or a toast timing out).answers if any
actionA "Run your code" button was pressed and onAction did not return false.actionId, answers if any
skippedThe placement's targeting chose to show nothing. Nothing opened.reason: frequency_cap, audience or holdout

Make it show by itself

If you set a trigger on the placement (for example "After 10 seconds"), call startAutoPlacements() once instead of calling presentPaywall yourself.

<script>
  UIKit.startAutoPlacements({
    products: { monthly: { price: 9.99, currency: 'USD', period: 'month' } },
    onPurchase: async ({ packageId }) => startCheckout(packageId),
  });
</script>

See Auto placements.

Show a screen inline

Put a screen inside your pricing section with mountPaywall, or with the <uikit-paywall> tag.

<uikit-paywall placement="pricing" api-key="pk_..."></uikit-paywall>
<script>
  const el = document.querySelector('uikit-paywall');
  el.products = { annual: { price: 59.99, currency: 'USD', period: 'year' } };
  el.onPurchase = async ({ packageId }) => startCheckout(packageId);
  el.addEventListener('uikit-purchased', (event) => unlockPro(event.detail.packageId));
</script>

See Mount a paywall and Web component.

React

import { configure } from '@ui-kit/web';
import { usePaywall } from '@ui-kit/react';

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

export function UpgradeButton() {
  const present = usePaywall({ products });
  return (
    <button
      onClick={async () => {
        const result = await present({ paywall: { placement: 'upgrade_button' }, onPurchase: ({ packageId }) => checkout(packageId) });
        if (result.outcome === 'purchased') unlockPro();
      }}
    >
      Upgrade
    </button>
  );
}

See React.

If something does not show

  • Open the browser console. The SDK logs a warning if a package ID has no price: [UIKit] No price for package(s) ....
  • A rejected promise with UIKit: Placement not found means the key does not match a placement. Published paywall not found means the screen was never published.
  • A 403 origin_not_allowed means your site is not in Allowed websites.
  • See Errors for every message.

On this page