MetaMask Connect
June 26, 2026 · View on GitHub
A unified SDK for dApps to connect to MetaMask across all platforms and ecosystems. MetaMask Connect replaces the previous MetaMask SDK with a ground-up rewrite built on the CAIP-25 Multichain API.
A single integration handles:
- Desktop browser with MetaMask Extension installed — communicates directly with the extension
- Desktop browser without MetaMask Extension installed — connects to MetaMask Mobile via QR code + relay
- Mobile native browser (Safari, Chrome, etc.) — connects to MetaMask Mobile via deeplink + relay
- In-app browser (inside MetaMask Mobile) — direct bridge, no relay needed
- React Native apps — deeplink + relay to MetaMask Mobile
MetaMask Connect automatically determines the right transport and abstracts platform-specific details behind a unified interface.
Why not just EIP-6963?
EIP-6963 solves wallet discovery — it lets dApps find which wallets are available as injected providers. That's useful, but it only works when the MetaMask Extension is present in the same browser.
MetaMask Connect gives you:
- Remote connections when the MetaMask Extension isn't installed — mobile wallet connections via relay, replacing WalletConnect for MetaMask-specific flows with better stability and UX
- Multichain session management — request access to EVM + Solana (+ future ecosystems) in a single session, instead of connecting per-chain
- Automatic session persistence — sessions survive page reloads and new tabs without re-prompting the user
- Cross-platform consistency — same API whether connecting to MetaMask Extension or MetaMask Mobile
The Multichain API
MetaMask Connect is built on the CASA Multichain API (CAIP-25), a chain-agnostic standard for wallet–dApp communication. For the full rationale, see MIP-5.
Instead of the traditional EIP-1193 model (eth_requestAccounts on one chain at a time), the Multichain API lets dApps:
- Request permissions across ecosystems in one call — e.g., "I need Ethereum Mainnet, Polygon, and Solana Mainnet" as a single session request
- Invoke methods on any permitted scope — send a Solana transaction and an EVM transaction through the same session
- Use standardized session lifecycle —
wallet_createSession,wallet_invokeMethod,wallet_getSession,wallet_revokeSession
This means a dApp that supports both EVM and Solana doesn't need separate connection flows — one session covers both.
Looking for the wallet-side JSON-RPC contract (the
wallet_createSession/wallet_invokeMethodrequests and responses underneath this SDK)? See the Multichain API reference in@metamask/multichain-api-middleware, including how MetaMask currently diverges from the latest CAIP-25.
Integration Options
There are two ways to integrate, depending on how much you want to adopt:
Option A: Ecosystem-Specific Clients (drop-in)
Use @metamask/connect-evm and/or @metamask/connect-solana for a familiar developer experience with minimal changes to your existing code.
EVM
Provides an EIP-1193 compatible provider so your existing EVM code works with minimal changes.
import { createEVMClient } from '@metamask/connect-evm';
const client = await createEVMClient({
dapp: { name: 'My DApp', url: 'https://mydapp.com' },
});
const { accounts, chainId } = await client.connect({
chainIds: ['0x1', '0x89'], // Ethereum Mainnet + Polygon
});
// Get an EIP-1193 provider — works with ethers.js, viem, web3.js, etc.
const provider = client.getProvider();
const balance = await provider.request({
method: 'eth_getBalance',
params: [accounts[0], 'latest'],
});
Solana
Provides a Wallet Standard compatible wallet, so it integrates with the Solana wallet adapter ecosystem.
import { createSolanaClient } from '@metamask/connect-solana';
const client = await createSolanaClient({
dapp: { name: 'My DApp', url: 'https://mydapp.com' },
api: {
supportedNetworks: {
mainnet: 'https://api.mainnet-beta.solana.com',
devnet: 'https://api.devnet.solana.com',
},
},
});
// MetaMask auto-registers with Wallet Standard during initialization.
MetaMask appears as a Solana wallet in any dApp using @solana/wallet-adapter. Users connect the same way they would with Phantom or Solflare.
Using both together
If your dApp supports EVM and Solana, you can use both clients. They share the same underlying multichain session — the user only approves once.
Option B: Multichain Client (full API)
Use @metamask/connect-multichain directly for the full Multichain API experience. This is more powerful but requires adapting your dApp to work with scopes and wallet_invokeMethod rather than traditional per-chain RPC.
import { createMultichainClient } from '@metamask/connect-multichain';
const client = await createMultichainClient({
dapp: { name: 'My DApp', url: 'https://mydapp.com' },
});
// Connect with scopes across ecosystems
await client.connect(
['eip155:1', 'eip155:137', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'],
[],
);
// Invoke methods on any scope
const ethBalance = await client.invokeMethod({
scope: 'eip155:1',
request: { method: 'eth_getBalance', params: ['0x...', 'latest'] },
});
const solanaSignature = await client.invokeMethod({
scope: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
request: {
method: 'signMessage',
params: {
account: { address: 'YourSolanaAddress' },
message: 'SGVsbG8gZnJvbSBTb2xhbmE=', // "Hello from Solana" in base64
},
},
});
Full control over the multichain session. Request exactly the scopes you need, invoke methods on any chain, and handle events for cross-chain flows. This is the path that unlocks the best UX for multichain dApps — a single connection prompt for all ecosystems — but it does require your dApp to work with the Multichain API's scope model rather than per-chain RPC providers.
Which option should I choose?
| Ecosystem Clients (Option A) | Multichain Client (Option B) | |
|---|---|---|
| Integration effort | Low — drop-in replacement for existing provider code | Medium — requires adapting to scope-based API |
| EVM support | EIP-1193 provider, works with ethers/viem/web3.js | Via wallet_invokeMethod with eip155:* scopes |
| Solana support | Wallet Standard, works with Solana wallet adapter | Via wallet_invokeMethod with solana:* scopes |
| Cross-chain UX | Separate connect flows per ecosystem | Single connect prompt for all ecosystems |
| Session management | Handled automatically per-client | Full control over unified session |
| Best for | Existing dApps wanting MetaMask Connect benefits with minimal code changes | New or multichain-native dApps wanting the best possible cross-chain UX |
You can also start with Option A and migrate to Option B incrementally. The ecosystem clients are wrappers around the multichain client — they use the same transport, session, and relay infrastructure under the hood.
How Connections Work Under the Hood
- Platform detection — SDK checks if MetaMask Extension is present, what browser you're in, whether you're on mobile, etc.
- Transport selection — MetaMask Extension present? Direct messaging. Not present? Relay connection via QR code or deeplink.
- Session creation — CAIP-25 session established with the requested scopes (chains + methods).
- E2E encryption — Relay connections are end-to-end encrypted (ECIES). The relay server never sees message content.
- Session persistence — Session survives reloads. User doesn't need to re-approve on page refresh.
Architecture
MetaMask Connect is layered: @metamask/connect-multichain is the CAIP-25 client that
manages the session and negotiates transports, and the EVM and Solana adapters wrap it for
ecosystem-specific APIs. At connect time the client detects the platform and selects a
transport — direct messaging to the extension, or the Mobile Wallet Protocol relay for
QR/deeplink connections to MetaMask Mobile.
See docs/architecture.md for the package topology and transport
diagrams, plus a detailed walk-through of transport selection, session persistence, and
headless mode.
Getting Started
# For EVM dApps
npm install @metamask/connect-evm
# For Solana dApps
npm install @metamask/connect-solana
# For full multichain control
npm install @metamask/connect-multichain
Content Security Policy
Host pages integrating MetaMask Connect need to allow a few origins in their Content Security Policy.
Required
connect-src wss://mm-sdk-relay.api.cx.metamask.io;
img-src data:;
wss://mm-sdk-relay.api.cx.metamask.io— the WebSocket URL of the MetaMask relay used for remote connections (mobile, no-extension, etc.). Unavoidable — the relay cannot be proxied or deferred from within the library, and remote connections will fail without it.img-src data:— the install/QR-code modal in@metamask/multichain-uiembeds the MetaMask fox SVG as adata:URI inside the generated QR code. Without this, the QR code will fail to render entirely.
Also consider
https://mm-sdk-analytics.api.cx.metamask.io— telemetry endpoint used by@metamask/analyticswhen analytics are enabled. Analytics are enabled by default; setanalytics.enabled: falseto disable analytics events and omit this endpoint fromconnect-src.style-src 'unsafe-inline'—@metamask/multichain-uiis built with Stencil, which injects component styles at runtime inside Shadow DOM. Strict CSPs without'unsafe-inline'(or an equivalent nonce/hash strategy) may break modal styling.- RPC endpoints you pass to
api.infuraProjectId/api.readonlyRPCMap/supportedNetworks— e.g.https://*.infura.io, your own node provider, or a public RPC. These are supplied by your dApp, so add whateverconnect-srcentries match the endpoints you configure. https://metamask.app.linkandmetamask://— used for mobile deeplinks / universal links. These are top-level navigations and are not normally subject toconnect-src, but strict CSPs that usenavigate-toorform-actionmay need to allow them.
Minimal example
For a dApp using the default analytics endpoint, Infura, and the install modal:
connect-src 'self' wss://mm-sdk-relay.api.cx.metamask.io https://mm-sdk-analytics.api.cx.metamask.io https://*.infura.io;
img-src 'self' data:;
style-src 'self' 'unsafe-inline';
See playground/browser-playground/public/index.html for a working reference CSP.
Packages
The published libraries under packages/. This table is generated from the workspace
metadata — run yarn update-readme-content to regenerate it.
| Package | npm | Description |
|---|---|---|
@metamask/analytics | npm | MetaMask Connect telemetry — batched connection-lifecycle events |
@metamask/connect | npm | Unified entry point for MetaMask Connect — re-exports the multichain client (default) and the EVM adapter (/evm) |
@metamask/connect-evm | npm | MetaMask Connect EVM adapter — EIP-1193 provider over the multichain client |
@metamask/connect-multichain | npm | MetaMask Connect multichain client — CAIP multichain API, session management, and transport negotiation |
@metamask/connect-solana | npm | MetaMask Connect Solana adapter — Wallet Standard integration over the multichain client |
@metamask/multichain-ui | npm | MetaMask Connect UI — install modal, OTP modal, and QR codes |
Playgrounds
Local test apps (not published). Maintained by hand.
| Package | Description |
|---|---|
@metamask/browser-playground | Browser test dApp — React app for multichain, legacy EVM, and wagmi |
@metamask/node-playground | Node.js CLI playground — Inquirer-based with terminal QR codes |
@metamask/playground-ui | Shared playground logic — constants, helpers, and types |
@metamask/react-native-playground | React Native test dApp — Expo app for mobile testing |
Dependency graph
Generated from the published-package workspace dependencies (run
yarn update-readme-content to regenerate). For the full topology including the
playgrounds and transports, see docs/architecture.md.
%%{ init: { 'flowchart': { 'curve': 'bumpX' } } }%%
graph LR;
linkStyle default opacity:0.5
analytics(["@metamask/analytics"]);
connect(["@metamask/connect"]);
connect_evm(["@metamask/connect-evm"]);
connect_multichain(["@metamask/connect-multichain"]);
connect_solana(["@metamask/connect-solana"]);
multichain_ui(["@metamask/multichain-ui"]);
connect --> connect_evm;
connect --> connect_multichain;
connect_evm --> analytics;
connect_evm --> connect_multichain;
connect_multichain --> analytics;
connect_multichain --> multichain_ui;
connect_solana --> connect_multichain;
Security Audits
MetaMask Connect has been independently audited. Reports are stored in the audits/ directory.
| Auditor | Report | Date | Scope | Findings |
|---|---|---|---|---|
| Cyfrin | March 2026 | Cryptographic implementation (ECIES, key management), session management, transport layer security, input validation, third-party dependency review across connect-monorepo, mobile-wallet-protocol, metamask-mobile, metamask-extension, and relay server | 14 issues (0 critical, 1 high, 5 medium, 5 low, 3 informational) — 12 resolved, 2 acknowledged |
Contributing
See the Contributor Guide for help on:
- Setting up your development environment
- Working with the monorepo
- Testing changes a package in other projects
- Issuing new releases
- Creating a new package