Skip to main content
Use the JavaScript SDK to support EVM and Solana accounts through one of these routes:
  • An installed MetaMask browser extension, on desktop or inside the MetaMask in-app browser.
  • A MetaMask SDK pairing URI rendered as a QR code on desktop.
  • An SDK-managed handoff to MetaMask on mobile web or React Native.
MetaMask SDK pairing is not a generic WalletConnect connection. The MetaMask functions open MetaMask on mobile. Use their returned URI only when rendering a desktop QR code.

Prerequisites

Add the extensions

The MetaMask extensions in @dynamic-labs-sdk/evm/metamask and @dynamic-labs-sdk/solana/metamask cover only the desktop QR code and the mobile handoff. The installed MetaMask browser extension is discovered by the standard chain extensions through EIP-6963 (EVM) and Solana Wallet Standard, so add both:

Connect an installed extension

This route applies when MetaMask runs as a browser extension: a desktop browser with MetaMask installed, or your dapp opened inside the MetaMask in-app browser. On mobile web and React Native without the extension, use the URI routes below instead. Use the chain-specific key helper to detect a MetaMask provider announced through EIP-6963 or Solana Wallet Standard. If the helper returns a key, pass it to the normal wallet provider connection flow.
For Solana, use getMetaMaskSolanaExtensionWalletProviderKey from @dynamic-labs-sdk/solana/metamask.

Connect with a MetaMask SDK URI

The URI functions return { uri, approval }:
  • On desktop, render uri as a QR code for the user to scan with MetaMask.
  • On mobile web and React Native, the SDK opens MetaMask. You do not need to use uri.
  • Call approval() after starting the connection. It resolves with { walletAccounts } after the user finishes the wallet interactions.
Choose the function based on whether the account must be verified during the flow: The connect-only functions add an unverified wallet account by default. Pass { addToDynamicWalletAccounts: false } if you only need the returned account. The connect-and-verify functions verify the account before approval() resolves. Users may see separate pairing and verification requests in MetaMask. Each function returns one wallet account for its selected chain.

Desktop QR code

Render the URI with your QR code library. The user must scan the QR code from MetaMask.

Mobile web

Call the MetaMask function from the user’s click or tap handler. The SDK opens MetaMask:
Use the corresponding Solana URI function when the user selects a Solana account.

React Native

React Native uses the same URI pairing functions. Call the function from the user’s press handler so the SDK can open MetaMask.
Configure metadata.nativeLink and metadata.universalLink on your Dynamic client so MetaMask can return the user to your app. See React Native setup.

Route MetaMask from a wallet picker

Call getWalletOptionsCatalogue({ includeMobileOptions: true }) to include MetaMask’s mobile and QR routes. A MetaMask entry can contain:
  • withWalletProvider for the installed MetaMask browser extension.
  • metamaskSdkUri for MetaMask SDK desktop QR and mobile pairing.
  • inAppBrowser for opening your dapp inside MetaMask.
Use the chain the user selected. A withWalletProvider option is the installed MetaMask browser extension, so connect it through the normal wallet provider flow. See Build a Wallet Picker for inAppBrowser, installation, and fallback handling.
Do not route a metamaskSdkUri option through connectWithWalletProvider or connectAndVerifyWithWalletProvider. It cannot connect through the generic provider path and throws MetaMaskDirectConnectNotSupportedError. Route it through the chain-specific MetaMask URI functions.

Common pitfalls

A fresh pairing replaces stale connection state

Each MetaMask URI function clears stale MetaMask pairing state before requesting a new URI. If pairing fails or expires, call the URI function again. Render its new URI only for a desktop QR code. Do not cache and reuse a previous URI.

User rejection and timeouts

The initial URI function or approval() can reject if the user cancels a wallet interaction. The URI function also rejects with MetaMaskDisplayUriMissingError if MetaMask does not provide a pairing URI, or NoAddressFoundError if the approved session has no account. Keep the connection UI available so the user can retry, but allow only one attempt at a time. Disable retry while the URI request or approval() is pending. MetaMask transport timeouts are not automatically retried. A timed-out signing or transaction request may still be pending in MetaMask. Avoid immediately sending the same fund-moving request again.
Last modified on September 16, 2026