Appearance
Browser requirements
This SDK is browser only. createSwappedConnectClient throws BROWSER_REQUIRED on the server (Node.js, SSR, RSC). Create a sessionId on your backend, then instantiate the client in the browser.
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. 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;| Directive | Allow | Why |
|---|---|---|
frame-src | widgetBaseUrl | Hidden /gateway iframe |
connect-src | apiBaseUrl (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.
Errors
| Code | When | What to do |
|---|---|---|
BROWSER_REQUIRED | Client created outside the browser | Instantiate in a client component / browser-only module |
MODULE_NOT_ENABLED | Called a module that was omitted from modules | Include it in modules, or omit modules to enable all |
WALLET_GATEWAY_NOT_READY | Hidden /gateway iframe blocked, timed out, or missing | Allow widgetBaseUrl in frame-src; retry connect() |
WEBSOCKET_CONNECTION_FAILED | Live 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.