Skip to content

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.

SituationUI
Extension installedConnect button
Desktop, no extension, WalletConnect supportedQR
Mobile in-app browserInjected
Mobile Safari / ChromeOpen in wallet / deeplink
Deeplink wallet on desktopQR 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:

FieldMeaning
providerPayment-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.

ValueMeaning
pairingUriWalletConnect URI (QR / copy)
pairingDeeplinkUrlSame 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.

Some wallets on some devices do not use WalletConnect. requiresDeepLink(provider) is true (also on AvailableWallet.isDeepLinkConnection).

MethodReturns
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.