Skip to main content
A Connect widget is an iframe. You mint a short-lived access token on your backend, put it in the URL, and style the widget with query parameters. Try the parameters interactively on the playground, which generates the snippet for you.

Embedding

Swap payout for payin to embed the pay-in widget, and give it more room while you are there. Pay-in is the taller of the two: the Connect settings screen generates height="600" for it against 500 for payout, and a flat 500 clips it. The allow attribute matters. Identity verification uses the camera, and card flows may need payment permissions. Without it, those steps fail inside the frame rather than falling back.
Mint the token on your backend, never in the browser. Tokens default to a one-hour lifetime and cannot exceed 24 hours, so treat them as short-lived credentials rather than configuration.

Height

The examples use a fixed height="500", which is the simplest thing that works. The widget also posts its height to the parent whenever its content changes, so you can size the frame to fit:
One caveat: the widget’s own container defaults to min-height: 100vh so that short content still covers the frame, which means it never reports a height smaller than the frame you gave it. If you want the frame to shrink to its content, set minHeight explicitly, for example ?minHeight=0.

Overlays

Identity verification and withdrawal confirmation open as modals. Inside a short iframe they are cramped, so the widget announces them and lets you expand the frame:
Without a listener the modal still works, it just fills whatever space the iframe has.

Customization

Every option below is a query parameter on the widget URL.

Theme and colour

theme=auto is accepted but not implemented. It resolves to the light palette rather than following the system or page theme. To follow the reader’s theme, detect it yourself and set theme=light or theme=dark on the iframe URL.
Reassigning src reloads the frame, so change the theme before the reader starts a withdrawal rather than during one.

Individual colours

For finer control, override any of these directly. Each takes a hex value: background, cardBackground, inputBackground, textPrimary, textSecondary, textMuted, textInverted, border, borderFocus, borderSelected, primary, primaryHover, primaryLight, success, successBackground, error, errorBackground, warning, warningBackground, iconColor, iconMuted, divider, skeleton. primary wins over primaryColor when both are present.

Typography, spacing, buttons and cards

buttonTextTransform accepts none, uppercase or capitalize. cardBorderStyle accepts solid, dashed or none. The rest take CSS values and are passed through.

Sections

Send false to hide a section.

Labels

Payout: payoutTitle, balanceLabel, withdrawButton, historyTitle, historyDescription, settingsTitle, settingsDescription, kycButton, kycTitle, kycVerifiedTitle, kycVerifiedDescription. Pay-in: payinTitle, paymentMethodsTitle, addMethodButton, depositButton, amountLabel, feeLabel, totalLabel, walletLabel, successTitle, successMessage. In depositButton, $X is replaced with the formatted amount.
Label values are decoded twice, so a label that already round-tripped through an encoder comes back intact. A literal % in a hand-written URL is passed through as typed rather than decoded again. If you want a label to contain %20 as visible text rather than a space, encode it as %2520.

Three behaviours worth knowing

These surprise people, and each one is easy to mistake for a bug in your own code. Only the literal string false hides a section. showBalance=0 and showBalance=no both read as true. An out-of-range borderRadius is discarded, not clamped. borderRadius=99 falls back to the 12px default rather than rendering at 50. The config parameter replaces everything else. You can pass a whole theme as URL-encoded JSON in config. If it parses, every individual parameter on the URL is ignored, so pick one approach rather than mixing them. If it fails to parse, the widget falls back to the individual parameters rather than erroring.

Events

The widget posts these to the parent window. Every message has source: 'sideshift-connect', a type, and sometimes data. widget:loaded, widget:error, widget:resize, widget:overlay_open, widget:overlay_close, session:expired, payout:withdraw_initiated, payout:kyc_completed, payin:deposit_initiated, payin:deposit_completed, payin:deposit_failed, payin:method_added, payin:amount_changed.
Three more names exist in the event type but are never sent by the widget: payout:withdraw_completed, payout:balance_updated and payout:kyc_started. Do not build on them. payout:withdraw_completed is the trap, because it is the natural place to mark a payout finished and a handler for it will simply never run. Confirm completed withdrawals from the withdrawal.completed webhook instead, which is server-to-server and survives the reader closing the tab.
session:expired is the one to handle. Tokens are short-lived, so mint a fresh one and reload the frame when it arrives.