Skip to main content
React bindings over the browser SDK: one component that mounts an embedded checkout session and manages the iframe’s lifecycle across re-renders. It depends on @ionicfi/js and bundles no payment logic of its own.

Usage

Create a checkout session on your server with ui_mode: "embedded", hand the response to the component, and render it where the payment form should appear:
session is the create-session API response ({ id, client_secret, embed_url }). The component loads the Ionic SDK from Ionic’s CDN on first mount (an existing window.Ionic, for example from a hand-placed script tag, is reused), so the card-handling runtime is never bundled into your app. Fulfill orders from webhooks, not from onComplete. The checkout.session.completed webhook is the reliable signal that payment succeeded; onComplete is a browser event that never fires if the buyer closes the tab first, and a hostile page could try to emit it. Grant the goods only when your server receives and verifies the webhook. Pass onError if you want to own the failure UI. Without it, the two failures that leave nothing on the page (the SDK script not loading, and mount rejecting its options) render a plain built-in message and log the technical detail to the console. Everything the checkout itself reports (expired session, terminal payment failure) is already displayed inside the iframe, so the component does not add a second message for those. Digital wallets are on by default (wallets defaults to "auto"): if the buyer’s device and your account support one, it appears above the card form with no integration work. If a wallet is configured but can’t be offered, the console explains exactly why and what to change. Don’t render the component inside another iframe: the checkout document controls who may frame it, and payment methods that redirect can’t complete inside a nested frame. In a Next.js App Router project, import it from a client component. The published bundle carries the "use client" directive, so importing it from a server component tree works without extra annotation, but the surrounding page logic (state, callbacks) must itself be client-side.

Props

Error codes

onError receives { code, message, terminal }. Branch on terminal, not on code. terminal: false means the iframe is still live and may yet succeed, so replacing it with an error screen would take a working checkout away from the buyer. New codes are added over time, so a switch on code needs a default branch; terminal never needs updating.
Retryable declines (an issuer saying no) never reach onError; the checkout handles them in the iframe and the buyer can try another card. New codes may be added over time; always handle unknown codes in a default branch rather than treating the list as closed.

Retrying after a load failure

After sdk_load_failed, remount the component to retry: the loader clears the failed load before retrying, so a fresh mount injects a fresh script:

Re-render behavior

The iframe holds the buyer’s in-progress card entry, so the component tears it down and remounts only when the values that define the mount change: the session’s fields (id, client_secret, embed_url) or the set of wallets offered. New callback identities (inline arrow functions), new session object identities with unchanged values, timeoutMs, and iframeTitle never remount. Callbacks always fire with their latest render’s identity, and never after the component unmounts.

Content Security Policy

If your page sends a Content-Security-Policy, it needs script-src https://js.ionicfi.com (the SDK is loaded at runtime, never bundled) and frame-src set to the origin of the session’s embed_url. A blocked script renders no payment form. Wallets need additional origins; see Embedded checkout: Content Security Policy.

Module format

This package is ESM-only, like @ionicfi/js. Jest projects still running CommonJS transforms need the package excluded from transformIgnorePatterns:

Security notes

The component passes session.client_secret to the SDK and never logs or stores it. It does live in React props, so tooling that captures props (React DevTools, error reporters configured to serialize component trees) can see it. The secret authorizes completing this one checkout session only.