Appearance
Connect wallet
connect opens a wallet. It returns the WalletConnection, or null when the device only opens the wallet app (browse deeplink) and nothing connects on this page. Multi-chain wallets (for example Phantom EVM + Solana + Bitcoin) are one connection — namespaces live on connection.namespaces.
This page is the action. The instances that remain afterward are Connected wallets (getConnections, getConnectionState, disconnect). Which wallets can be opened on this device is Availability.
Bring your own QR component — qrcode.react in the examples is only an example.
| Situation | UI |
|---|---|
| Extension installed | Connect button |
| Desktop, no extension, WalletConnect supported | QR |
| Mobile in-app browser | Injected |
| Mobile Safari / Chrome | Open in wallet / deeplink |
| Deeplink wallet on desktop | QR or “open on phone” |
When transport is omitted, the SDK uses injected if the extension is installed, otherwise walletconnect if the wallet supports it.
connect
ts
const connection = await client.wallets.connect({
provider: IntegrationProvider.MetaMask,
});ConnectWalletRequest:
| Field | Meaning |
|---|---|
provider | Payment-method provider |
transport? | 'injected' or 'walletconnect'. Default: installed extension → injected, else WalletConnect |
namespaces? | Chain families to request. Default: what the session / host supports |
chainId? | EVM only: chain to request at connect time |
onUri? | WalletConnect pairing callback { uri, deeplinkUrl, provider } |
force? | WalletConnect only. Cancel any in-flight pairing before starting a new one |
forcePopup? | Always run this injected connect in a popup |
popupIfUnavailable? | If the host cannot see this extension, open a popup instead of failing |
Only one WalletConnect pairing can be in flight. A second connect({ transport: 'walletconnect' }) without force: true throws WALLET_PAIRING_IN_PROGRESS.
An injected connect for a provider that is already connected on that transport throws WALLET_ALREADY_CONNECTED. A new WalletConnect pairing is a new instance and does not throw that error.
Injected (browser extension)
ts
const connection = await client.wallets.connect({
provider: IntegrationProvider.MetaMask,
transport: 'injected',
popupIfUnavailable: true,
});forcePopup and popupIfUnavailable apply to injected connect. Some wallets have isPopupConnection: true on AvailableWallet and always complete injected connect in a popup.
Popup failures: WALLET_POPUP_BLOCKED, WALLET_POPUP_CLOSED, WALLET_POPUP_IN_PROGRESS, WALLET_POPUP_NO_OPENER.
WalletConnect
connect({ transport: 'walletconnect' }) emits a pairing URI. Read it from onUri, getConnectionState().pairingUri, or wallets:pairingUri.
| Value | Meaning |
|---|---|
pairingUri | WalletConnect URI (QR / copy) |
pairingDeeplinkUrl | Same pairing as a mobile deep link (open the wallet on this device) |
ts
const off = client.on('wallets:pairingUri', ({ uri, deeplinkUrl, provider }) => {
// `uri` — QR / clipboard
// `deeplinkUrl` — open the wallet app on this device
});
const connection = await client.wallets.connect({
provider: IntegrationProvider.Trust,
transport: 'walletconnect',
onUri: ({ uri, deeplinkUrl }) => {
// same payload as the event
},
});
off();cancelPairing() aborts the in-flight pairing and clears the URI. The pending connect() rejects with WALLET_PAIRING_CANCELLED.
ts
const cancelled = await client.wallets.cancelPairing();The demo renders pairingUri as a QR and uses pairingDeeplinkUrl for an “Open in wallet” button.
Open in wallet app (deeplink)
Some wallets on some devices do not use WalletConnect. requiresDeepLink(provider) is true (also on AvailableWallet.isDeepLinkConnection).
| Method | Returns |
|---|---|
getDeepLinkUrl(provider) | Checkout URL to open inside the wallet app, or null |
openDeepLink(provider) | Opens that URL; returns the URL or null |
ts
if (client.wallets.requiresDeepLink(IntegrationProvider.Phantom)) {
const url = client.wallets.getDeepLinkUrl(IntegrationProvider.Phantom);
client.wallets.openDeepLink(IntegrationProvider.Phantom);
}Calling connect({ transport: 'injected' }) for a deeplink wallet on a device that should open the app returns null after handing off to the wallet. Treat null as “opened the wallet app”, not a failed connect.
isMobileBrowser() is exported from @swapped/connect-sdk if you need to branch desktop vs mobile yourself.
Helpers
ts
client.wallets.supportsWalletConnect(provider);
client.wallets.requiresDeepLink(provider);AvailableWallet.qrScanTarget says how to label a desktop QR: 'camera' for a browse URL (Phantom, Coinbase), 'wallet-app' for a WalletConnect wc: URI, or null when the wallet is not in the SDK config.
Errors
connect rejects with ConnectSdkError. Common codes: WALLET_CONNECT_REJECTED, WALLET_NOT_INSTALLED, WALLET_NOT_SUPPORTED, WALLET_ALREADY_CONNECTED, WALLET_PAIRING_IN_PROGRESS, WALLET_PAIRING_CANCELLED, WALLET_POPUP_*. See Errors.