Skip to main content
Embedded checkout runs the entire Creem payment flow inside your own site instead of sending customers to a hosted page. Drop in a small script, open checkout as a modal or inline iframe, and get a callback when payment completes.

How it works

  1. Create a checkout session on your server with your secret API key (see Checkout API) and read its checkoutUrl.
  2. Load the Creem embed script on your page.
  3. Open the checkout as an overlay or inline, and handle onComplete.
You create the session server-side (secret key) and pass the resulting URL to the browser — the URL is safe to expose, and completion is always confirmed server-side via webhook.

1. Create a checkout session (server-side)

Every embed needs a checkout URL, created on your server with your secret API key so the price and product can’t be tampered with. Use the Checkout API or one of its SDKs and read checkoutUrl (the raw REST API returns it as checkout_url):
// Server-side only — keep CREEM_API_KEY secret
import { createCreem } from 'creem_io';

const creem = createCreem({ apiKey: process.env.CREEM_API_KEY! });

const checkout = await creem.checkouts.create({
  productId: 'prod_YOUR_PRODUCT_ID',
  successUrl: 'https://yoursite.com/success', // optional
});

// Send checkout.checkoutUrl to the browser, then embed it (below).
Then embed that URL with a framework SDK, the script loader, or a raw iframe — pick one.

2. Choose an embed path

Use exactly one of the three paths below — framework SDKs, the script loader, or a raw iframe.

Framework SDKs

First-class packages for React, Vue, and Svelte with typed props and lifecycle events. They share a framework-agnostic core, @creem_io/embed, which you can also use directly in vanilla JS.
npm install @creem_io/react
import { CreemCheckout, CreemCheckoutInline } from '@creem_io/react';

// Overlay — wrap any clickable element
<CreemCheckout checkoutUrl={checkoutUrl} onComplete={(d) => console.log('paid', d)}>
  <button>Subscribe</button>
</CreemCheckout>

// Inline — mount in place
<CreemCheckoutInline
  checkoutUrl={checkoutUrl}
  onComplete={onComplete}
  style={{ width: 460, height: 820 }}
/>
Also available: the useCreemCheckout() hook and the CreemEmbedCheckout.create() promise API. Full reference →
Every SDK takes the same options as the loader below (theme, locale) and emits the same ready + completed events. On completion, if the product has a Return URL, the page navigates there automatically (after a short confirmation screen) — handle onComplete for custom behavior.

Script loader

For non-framework apps, or when you want a global Creem object. No build step — drop in the loader script and open checkout from any framework or plain HTML.

Overlay

1

Add the script

<script src="https://www.creem.io/embed.js" defer></script>
2

Open checkout on click

<button id="buy">Subscribe</button>
<script>
  document.getElementById('buy').onclick = () => {
    Creem.openCheckout({
      checkoutUrl: 'CHECKOUT_URL', // from step 1
      onComplete: (detail) => {
        // detail = { checkoutId, orderId, orderNo }
        console.log('Payment complete', detail);
      },
    });
  };
</script>
The overlay shows the confirmation screen on success; call Creem.close() from onComplete if you want it to dismiss automatically.

Inline

Mount checkout inside a container on your page:
<div id="creem-checkout" style="height: 820px"></div>
<script>
  Creem.mount({
    checkoutUrl: 'CHECKOUT_URL',
    container: '#creem-checkout',
    onComplete: (detail) => unlockContent(detail.orderId),
  });
</script>

Declarative data attributes

Any element with data-creem-checkout opens the overlay on click — no JS wiring, but it still relies on the loader script above:
<a data-creem-checkout data-creem-url="CHECKOUT_URL">Buy now</a>
Optionally set the theme and language with data-creem-theme and data-creem-locale:
<a
  data-creem-checkout
  data-creem-url="CHECKOUT_URL"
  data-creem-theme="dark"
  data-creem-locale="fr"
>Buy now</a>

Raw iframe

The lowest-level option — no loader, no SDK. Use it when you only need inline display and will handle the lifecycle yourself, or don’t need callbacks:
<iframe
  src="CHECKOUT_URL"
  allow="payment *"
  style="border:0;width:460px;height:820px">
</iframe>
The allow="payment *" attribute is required — without it, digital wallets and 3-D Secure challenges can’t run inside the iframe.

Presentation — theme & language

Works with the framework SDKs and the script loader. openCheckout and mount accept two presentation options, appended to the checkout URL for you:
Creem.openCheckout({
  checkoutUrl: 'CHECKOUT_URL',
  theme: 'dark',   // 'light' | 'dark'
  locale: 'pt-BR', // BCP47 tag — forces the checkout language
});
By default the checkout follows the customer’s browser language. Pass locale to force a specific one (e.g. to match your own site’s language). Unsupported locales fall back to English. See the supported languages for the full list.

API reference

The framework SDKs (@creem_io/react, /vue, /svelte) accept these same options — as props/args, with onComplete/onClose surfaced as the complete/close events where idiomatic.

Creem.openCheckout(options)

Opens checkout in a modal overlay.
checkoutUrl
string
required
The checkout session URL from the Checkout API.
theme
'light' | 'dark'
Color theme for the checkout. Defaults to light.
locale
string
BCP47 language tag (e.g. 'fr', 'pt-BR') to force the checkout language. Defaults to the customer’s browser language; unsupported locales fall back to English.
onReady
() => void
Called once the checkout UI has rendered and is ready for input.
onComplete
(detail) => void
Called when payment completes. detail = { checkoutId, orderId?, orderNo?, redirect?, redirectUrl? }redirectUrl is the merchant success URL, if set.
onClose
() => void
Called when the overlay is dismissed by the customer.

Creem.mount(options)

Mounts checkout inline. Same options as openCheckout, plus:
container
string | HTMLElement
required
The element (or a CSS selector) to mount the checkout iframe into.

Creem.close()

Programmatically closes the overlay.

Events

Under the hood, the checkout posts messages to the parent window over its lifecycle. The loader handles these for you (onReady, onComplete); if you build a fully custom integration (e.g. a raw iframe), listen for them directly:
window.addEventListener('message', (event) => {
  // Only trust events from the checkout's own origin.
  if (event.origin !== 'https://www.creem.io') return;
  const data = event.data;
  if (data?.source !== 'creem-embed') return;
  if (data.type === 'ready') {
    console.log('checkout ready');
  } else if (data.type === 'completed') {
    // { checkoutId, orderId, orderNo }
    console.log('completed', data);
  }
});
source
string
Always "creem-embed".
version
number
Protocol version (currently 1).
type
string
"ready" when the UI has rendered, then "completed" on payment.
Digital wallets. Apple Pay / Google Pay can require domain registration with the card networks and may be unavailable inside a cross-origin iframe. Card and 3-D Secure payments always work in the embed; if wallet buttons are critical for you, the hosted checkout page remains the most reliable surface today.