Skip to content

Browser requirements ​

This SDK is browser only. createSwappedConnectClient and createWalletVerification throw BROWSER_REQUIRED on the server (Node.js, SSR, RSC). Create a Connect sessionId on your backend, then instantiate the checkout client in the browser. Wallet verification uses a public API key instead of a session - see Wallet verification.

If your site sends a Content-Security-Policy, you must allow Swapped origins. The SDK creates a hidden iframe and opens network connections from your page - the browser still applies your CSP to those cross-origin URLs. Sites with no CSP can ignore this page.

Hidden gateway iframe ​

createSwappedConnectClient mounts a hidden iframe at {widgetBaseUrl}/gateway (production default https://connect.swapped.com/gateway) when wallets or coinbase is enabled - the default, or an explicit modules list that includes either. Pass modules: ['exchangePay'] (and/or cashApp) to skip the iframe. createWalletVerification always mounts that iframe. The page talks to that host over postMessage. It is not the hosted widget - users never see it.

A frame-src (or child-src / default-src) that only allows 'self' blocks that frame even though your own script created it. Wallet and Coinbase connect then fail with WALLET_GATEWAY_NOT_READY.

Some wallets and Coinbase OAuth also open {gatewayUrl}?mode=popup. Allow popups for your origin; a blocked popup is WALLET_POPUP_BLOCKED or OAUTH_POPUP_BLOCKED, not a CSP miss.

Content Security Policy ​

Add the widget origin to frame-src and the API origin to connect-src (HTTPS plus wss: for live updates).

Production (defaults):

http
Content-Security-Policy:
  frame-src 'self' https://connect.swapped.com;
  connect-src 'self' https://connect-api.swapped.com wss://connect-api.swapped.com;

Staging (environment: 'staging'):

http
Content-Security-Policy:
  frame-src 'self' https://staging.swapped.app;
  connect-src 'self' https://staging-api.swapped.app wss://staging-api.swapped.app;
DirectiveAllowWhy
frame-srcwidgetBaseUrlHidden /gateway iframe
connect-srcapiBaseUrl (https: and wss:)REST ({apiBaseUrl}/api) and the WebSocket ({apiBaseUrl}/swapped-connect)

If you omit frame-src, the browser falls back to child-src, then default-src. A lone default-src 'self' blocks both the iframe and the API.

If you pass a custom apiBaseUrl or widgetBaseUrl, allow those origins instead. Localhost widget hosts are accepted in development - add that origin to frame-src when you use one.

Storage ​

React WalletsProvider keeps the active walletId in sessionStorage so the selection survives a refresh in that tab.

Wallet verification Coinbase mode: 'redirect' stores the pending verification id in sessionStorage (persistVerification, default true) so completeVerification() can recover after Coinbase sends the browser back.

Errors ​

CodeWhenWhat to do
BROWSER_REQUIREDClient created outside the browserInstantiate in a client component / browser-only module
MODULE_NOT_ENABLEDCalled a module that was omitted from modulesInclude it in modules, or omit modules to enable all
WALLET_GATEWAY_NOT_READYHidden /gateway iframe blocked, timed out, or missingAllow widgetBaseUrl in frame-src; retry connect()
WEBSOCKET_CONNECTION_FAILEDLive session / order socket failed (error event, context: 'websocket')Allow apiBaseUrl in connect-src including wss:

WEBSOCKET_CONNECTION_FAILED is emitted on client.on('error', …), not thrown from loadSession.