Widget Integration
Embed hosted checkout with the browser widget runtime.
Use the widget runtime when your frontend needs to launch a Stafiel checkout
session. Create the checkout session first on your server, then pass the
complete checkoutSessionUrl from the response data to the browser. Do not
parse, rebuild, or modify this URL.
Important: Do not put API keys in browser code.
Widget Base URL
https://widget.stafiel.com
Choose a Runtime
Checkout Snippet
Script path:
/widget/v1/checkout.js
This script exposes window.StafielCheckout. Use it for button binding and
declarative HTML.
Widget Runtime
Script path:
/widget/v1/widget.js
This script exposes window.StafielWidget. Use it to control widget instances,
events, mounting, theme updates, and cleanup.
Your application loads the browser script. Once the checkout frame starts, Stafiel renders and manages the checkout interface.
A merchant-rendered payment page uses a separate integration model. See Custom Payment Page.
Content Security Policy
If the page loading checkout.js or widget.js uses Content Security
Policy (CSP), allow these sources in its policy:
script-src:https://widget.stafiel.com. Include the same source inscript-src-elemif that directive is present.frame-src:https://widget.stafiel.comformodal,inline,lite, andmicro.connect-src:https://api.stafiel.comfor requests made by the runtime from your page.
Note: Add these sources to your existing directives rather than replacing your site's policy. These are integration requirements, not a complete CSP. The inline scripts in this page's examples must also comply with your script policy; their initialization code can be moved to an allowed external JavaScript file.
Widget Modes
| Mode | Widget runtime call | Fixed scale 1 reference |
Description |
|---|---|---|---|
redirect |
open() |
— | Opens hosted checkout in a new tab by default, or in the current tab when openInNewTab is false. |
modal |
open() |
828 x 648 px |
Opens checkout in the built-in modal. |
inline |
mount() |
272 x 384 px |
Mounts a full checkout frame in your page. |
lite |
mount() |
368 x 144 px |
Mounts a compact checkout frame. |
micro |
mount() |
256 x 128 px |
Mounts the smallest checkout frame. |
In redirect mode, an allowed metadata.returnToUrl supplies the hosted
checkout Back destination. In modal, inline, lite, and micro modes,
the merchant frontend controls surrounding-page navigation.
Sizing
Modal, inline, lite, and micro use the structured sizing option.
Modal defaults to sizing: { strategy: 'auto', fit: 'height' }.
Inline, lite, and micro default to:
sizing: { strategy: 'auto', fit: 'width' }
Auto sizing supports:
width: fit the available width.height: fit the available height.contain: fit within both dimensions.
Fixed sizing uses a numeric multiplier:
sizing: { strategy: 'fixed', scale: 1 }
1 uses the reference dimensions in Widget Modes, 0.8
renders both dimensions at 80%, and 2.5 at 250%. The runtime clamps values to
this range. Every sizing strategy preserves the checkout's aspect ratio and
internal layout.
Set the width, height, and overflow of containers used by inline, lite, and
micro modes. Provide a positive width for width, a positive height for
height, and both dimensions for contain.
Auto sizing follows container size changes. During an active checkout, change the sizing strategy with:
widget.setSizing({ strategy: 'auto', fit: 'contain' });
checkoutBinding.update({
sizing: { strategy: 'fixed', scale: 1.2 }
});
Automatic Fallback
With autoFallback: true, a recoverable error can move checkout to the next
mode in this sequence:
micro → lite → inline → modal → redirect
Fallback starts from the selected mode. Non-recoverable errors remain errors.
The default is false.
Checkout Snippet
Checkout Snippet Quick Start
<button id="pay-now">Pay now</button>
<script src="https://widget.stafiel.com/widget/v1/checkout.js"></script>
<script>
window.StafielCheckout.bind('#pay-now', {
checkoutSessionUrl: 'https://pay.stafiel.com/pay/ps_your_session_token',
mode: 'modal'
});
</script>
For inline, lite, and micro, use open() with a container.
This example opens an inline checkout immediately:
<div id="stafiel-payment"></div>
<style>
#stafiel-payment {
width: 100%;
max-width: 400px;
}
</style>
<script src="https://widget.stafiel.com/widget/v1/checkout.js"></script>
<script type="module">
const checkoutBinding = await window.StafielCheckout.open({
checkoutSessionUrl: 'https://pay.stafiel.com/pay/ps_your_session_token',
mode: 'inline',
container: document.getElementById('stafiel-payment')
});
</script>
Checkout Snippet API
| Method | Returns | Description |
|---|---|---|
open(options) |
Promise<CheckoutSnippetBinding> |
Opens checkout immediately. For inline, lite, and micro, provide container. |
bind(target, options) |
CheckoutSnippetBinding |
Binds checkout to a CSS selector or HTMLElement. |
bindAll(root?, defaults?) |
CheckoutSnippetBinding[] |
Binds every [data-stafiel-checkout] node under root. |
setTheme(target, theme) |
void |
Updates the theme for an existing binding. |
setLanguage(target, language) |
void |
Updates the language for an existing binding. |
unbind(target) |
void |
Removes the click trigger listener for one binding. |
destroy(target?) |
void |
Removes one binding, or all bindings when no target is provided. |
Binding Methods
| Method | Returns | Description |
|---|---|---|
open() |
Promise<void> |
Opens the bound checkout. |
close() |
void |
Closes the current checkout surface when supported. |
destroy() |
void |
Removes the binding and its runtime state. |
setTheme(theme) |
void |
Switches the binding between light and dark. |
setLanguage(language) |
void |
Switches the binding language between en, zh-CN, and zh-TW. |
update(options) |
void |
Updates supported options, including sizing and language, for the current binding. |
Checkout Snippet Options
| Option | Required | Default | Description |
|---|---|---|---|
checkoutSessionUrl |
Yes | None | Hosted checkout URL returned by Stafiel's Checkout Sessions API. |
mode |
Yes | None | One of the values listed in Widget Modes. |
container |
For mounted modes | Bound target for bind() |
Container selector or element for inline, lite, and micro. |
openInNewTab |
No | true for redirect |
Controls redirect mode tab behavior. |
sizing |
No | Mode-specific auto sizing | Auto or fixed sizing for modal and mounted modes. See Sizing. |
borderRadius |
No | 24 for modal, 16 otherwise |
Frame border radius in pixels, clamped between 0 and 24. |
backdrop |
No | true |
Modal only. Set to false to hide the dimming; the page remains non-interactive. |
theme |
No | light |
One of light or dark. |
language |
No | en |
One of en, zh-CN, or zh-TW. en-US is accepted as English. |
autoFallback |
No | false |
Enables mode fallback for recoverable errors. See Automatic Fallback. |
onOpen |
No | None | Called when the checkout surface opens; payment data may still be loading. |
onClose |
No | None | Called when checkout closes. |
onError |
No | None | Called when checkout fails to initialize or open. |
onFallback |
No | None | Called when the runtime falls back to another mode. |
Checkout Snippet modal uses the current document viewport. Custom modal boundaries are available through the Widget runtime.
Declarative Binding
Declare bindings directly in HTML:
<button
data-stafiel-checkout
data-checkout-session-url="https://pay.stafiel.com/pay/ps_your_session_token"
data-mode="modal"
data-theme="light"
data-language="en"
data-sizing-strategy="auto"
data-sizing-fit="height"
data-border-radius="24"
data-backdrop="true"
>
Pay now
</button>
<script src="https://widget.stafiel.com/widget/v1/checkout.js"></script>
<script>
window.StafielCheckout.bindAll();
</script>
| Attribute | Required | Description |
|---|---|---|
data-stafiel-checkout |
Yes | Marks the element for bindAll(). |
data-checkout-session-url |
Yes, or supply it in bindAll defaults |
Hosted checkout URL returned by Stafiel's Checkout Sessions API. |
data-mode |
Yes | One of the values listed in Widget Modes. |
data-container |
No | Selector for a separate mounted container. |
data-sizing-strategy |
No | auto or fixed. Required when sizing attributes are used. |
data-sizing-fit |
No | width, height, or contain for auto sizing. |
data-sizing-scale |
No | Positive decimal required for fixed sizing. |
data-border-radius |
No | Frame border radius in pixels. |
data-backdrop |
No | Modal only. Set to false to hide the dimming; the page remains non-interactive. |
data-theme |
No | light or dark. |
data-language |
No | en, zh-CN, or zh-TW. Inherits bindAll defaults when omitted. |
data-auto-fallback |
No | Boolean value: true, false, 1, or 0. |
data-open-in-new-tab |
No | Boolean value used by redirect mode. |
Widget Runtime
Widget Runtime Quick Start
<div id="stafiel-payment"></div>
<script src="https://widget.stafiel.com/widget/v1/widget.js"></script>
<script>
const widget = window.StafielWidget.create({
checkoutSessionUrl: 'https://pay.stafiel.com/pay/ps_your_session_token',
mode: 'inline',
container: document.getElementById('stafiel-payment')
});
widget.mount();
</script>
Widget Options
| Option | Required | Default | Description |
|---|---|---|---|
checkoutSessionUrl |
Yes | None | Hosted checkout URL returned by Stafiel's Checkout Sessions API. |
mode |
Yes | None | One of the values listed in Widget Modes. |
container |
For mounted modes | None | Connected HTMLElement used by inline, lite, and micro. |
openInNewTab |
No | true for redirect |
Controls whether redirect mode opens a new browser tab. |
sizing |
No | Mode-specific auto sizing | Auto or fixed sizing for modal and mounted modes. See Sizing. |
appearance.borderRadius |
No | 24 for modal, 16 otherwise |
Frame border radius in pixels, clamped between 0 and 24. |
modal.backdrop |
No | true |
Modal only. Set to false to hide the dimming; the page remains non-interactive. |
modal.boundary |
No | Full page | Connected, positioned HTMLElement that bounds the complete modal area. |
autoFallback |
No | false |
Enables mode fallback for recoverable errors. See Automatic Fallback. |
theme |
No | light |
One of light or dark. |
language |
No | en |
One of en, zh-CN, or zh-TW. en-US is accepted as English. |
Use borderRadius with Checkout Snippet and appearance.borderRadius with the
Widget runtime.
Widget Methods
| Method | Returns | Description |
|---|---|---|
StafielWidget.create(options) |
WidgetInstance |
Creates a widget instance from a hosted checkout session URL and widget options. |
widget.open() |
Promise<void> |
Opens redirect or modal mode. |
widget.mount(container?) |
Promise<void> |
Mounts inline, lite, or micro mode. |
widget.close() |
void |
Closes the current checkout and built-in modal. |
widget.destroy() |
void |
Removes listeners, frames, and runtime state for the instance. |
widget.setTheme(theme) |
void |
Switches the instance between light and dark. |
widget.setLanguage(language) |
void |
Switches the instance language between en, zh-CN, and zh-TW. |
widget.setSizing(sizing) |
void |
Changes sizing for the current modal or mounted widget. |
widget.on(event, handler) |
() => void |
Subscribes to a widget event and returns an unsubscribe function. |
Custom Modal Boundary
The default modal uses the full page. Set modal.boundary to a connected,
positioned HTMLElement with a visible size to contain the backdrop, payment
panel, and close control. Auto sizing follows changes to this boundary.
<div id="stafiel-modal-boundary"></div>
<style>
#stafiel-modal-boundary {
position: relative;
width: 100%;
height: 720px;
overflow: hidden;
}
</style>
<script>
(async function () {
const boundary = document.getElementById('stafiel-modal-boundary');
const widget = window.StafielWidget.create({
checkoutSessionUrl: 'https://pay.stafiel.com/pay/ps_your_session_token',
mode: 'modal',
modal: {
boundary
}
});
await widget.open();
})();
</script>
Events
Subscribe to Widget runtime UI and status signals with
widget.on(event, handler). Order events are available while an embedded
checkout frame is active in modal, inline, lite, or micro mode. Checkout
Snippet provides onOpen, onClose, onError, and onFallback callbacks in
Checkout Snippet Options. Use webhooks or the order
query APIs as the authoritative source for server-side state changes.
| Event | Description |
|---|---|
widget.ready |
The widget instance is ready. Emitted once per instance. |
widget.opened |
Checkout was opened or mounted; payment data may still be loading. |
widget.closed |
Checkout was closed. |
widget.error |
The widget failed to initialize, mount, open, or load. |
widget.fallback |
The runtime switched to another mode. |
order.created |
The checkout surface observed the order in the awaiting-payment state. |
order.payment.detected |
The checkout surface received a real-time payment-detected signal. This event is not guaranteed for every payment path. |
order.payment.received_fullpaid |
The currently recorded payment amount matched the required amount. |
order.payment.received_underpaid |
The currently recorded payment amount was below the required amount. |
order.payment.received_overpaid |
The currently recorded payment amount exceeded the required amount. |
Event payload fields vary by event type.
| Field | Description |
|---|---|
event |
Event name. Present on every widget event. |
version |
Widget event payload version. Present on every widget event. |
timestamp |
Event timestamp. Present on every widget event. |
orderId |
Order ID when available. |
paymentToken |
Payment token when available. |
mode |
Active widget mode. Present on lifecycle, error, and order events. |
reason |
Error or fallback reason. Present on widget.error and widget.fallback. |
recoverable |
Whether the error can fall back to another mode. Present on widget.error. |
fromMode |
Original widget mode. Present on widget.fallback. |
toMode |
Fallback widget mode. Present on widget.fallback. |
status |
Order status. Present on order events. |
payload |
Event-specific payload. Present on order events and some error events. |

