Skip to main content
Before you begin: your server must generate a patToken for each session and make it available to your page. See Set up your server.

1. Load the widget script

Add this loader to your page. It injects the widget script and resolves once FluzEmbedded is ready, so the rest of your code never runs before the widget exists.

2. Initialize the widget

Once the script has loaded, call init() with the transaction details and the patToken from your server.
init() takes transaction_type in snake case. The claim inside the signed patToken is transactionType. Both must describe the same transaction.
Do not pass apiKey to init(). Your API key is your application’s credential, and anything in your page is visible to the user. The script identifies your application from the signed patToken, which carries your appId. Versions before 1.3.0 required apiKey; 1.3.0 ignores it if it is still passed.

3. Open the widget

Choose how the user launches the widget. Both options run after init().
Bind open() to a button that already exists on your page.

Init options

init() checks only what the script itself needs: patToken, transaction_type, and a resolvable container. Everything else is validated against your signed token, so a bad transaction_type or a missing amount reaches you through onError, not a console message your code can’t see.

Methods

Handle the outcome

onOpen and onClose only tell you the widget appeared and went away, not whether the user finished. To know how the flow ended, pass onSuccess and onError. Both are optional; if you pass neither, the widget still works, you just won’t receive outcomes.
Do not settle from onSuccess. It runs in the visitor’s browser, carries no verifiable record of the transaction, and anyone can call it from the console. Use it for what the user sees: a confirmation, a redirect, clearing a spinner. Credit accounts, release fulfillment, or write to your ledger only from your server, driven by a webhook or a transaction you fetched and verified yourself.

How the callbacks behave

  • onSuccess is final. It fires at most once, and no outcome is delivered after it, so a completed flow never also reports an error.
  • onError reports an attempt, not a verdict. A user whose identity check fails or whose payment is declined is still in the widget and can try again. onError can fire more than once in a session, and a later onSuccess can still arrive.
  • Neither callback closes the widget. The user stays on screen until they dismiss it, which fires onClose.
Treat the session as over only when onSuccess fires or the user closes the widget.

What the callbacks receive

Both callbacks include, when known, the ids that tie the session to your records and the contact details on the Fluz account that ran it. Fluz fills these in server-side from your signed token and the user’s session, so they’re the values Fluz recorded, not anything the page assembled. Read each field on its own; don’t assume the set is complete.
  • externalReferenceId comes from your token, so it survives failures that happen before a user signs in.
  • The other four come from the Fluz account and only appear once the session got that far.
  • A failure before your token validates (an expired token, a missing app permission) carries nothing. onError receives only code and message.
email and phoneNumber describe the Fluz account the user signed into, which may differ from the values you passed in the patToken. These fields identify the session; they aren’t a record of what happened. Use externalReferenceId to find the right row in your system, then confirm the outcome with a webhook or API call before acting on it.
email and phoneNumber require a registered Origin. Fluz addresses outcome messages to the Origin on your app’s OAuth tab and includes contact details only when that origin is set and usable. With no origin on file, you still receive the three ids.Keep the Origin pointed at the page that embeds the widget. If it names a host you no longer embed from, the browser refuses to deliver the messages, so onSuccess and onError stop firing. onOpen, onClose, and the close control are unaffected. The only trace is a postMessage target-origin mismatch in the browser console. See Configure App Widget.

Error codes

onError receives a stable code to branch on and a human-readable message to log. US-0005 and G-0004 are failed attempts the user can retry; every other code means the session can’t continue. Treat any unrecognized code like G-0001. New codes ship over time without a breaking change.

Render the widget inline (staging only)

The container option is available on staging only. Production integrations must use the default fullscreen modal until it ships there.
By default, the widget mounts a fixed, full-viewport overlay on your page. Pass a container and it renders inside an element you position and size yourself, with no overlay, scroll lock, or page takeover.

Sizing

The widget fills your container at 100% width and height and never resizes it. Content taller than the container scrolls inside the widget, not your page.
  • Set an explicit width and height on the container in your CSS. Without a height, the widget falls back to the browser’s default iframe height of 150px, the most common mistake in this integration. The script logs a console warning if the container is too small when the widget opens.
  • Minimum supported size is 320 × 480 px. Every screen, including document capture, 2FA, and PIN entry, is supported at that size. Smaller layouts aren’t supported.
  • There’s no maximum. Wide containers get the desktop layout, including the transaction summary pane; narrow ones get the mobile layout.

Differences from the modal

Plan for that last row: when the user closes an inline widget, onClose fires and your container is emptied, so render its replacement from onClose.

Container errors

If the container can’t be used, nothing renders, onOpen doesn’t fire, and the script logs an error:
  • At init(): container is neither an element nor a non-empty string. The widget stays unconfigured, and a later open() refuses.
  • At open(): the selector matches nothing, isn’t valid CSS, or the element isn’t attached to the document.
An unresolvable container never falls back to the fullscreen modal.
A container selector is resolved when open() is called, not at init(), so it’s fine to call init() before the element exists.