Skip to main content

Connect to MetaMask using Wagmi

Get started with MetaMask Connect EVM in a React and Wagmi dapp. Download the quickstart template or manually set up MetaMask Connect EVM in an existing dapp.

Migrating from @metamask/sdk?

If you are upgrading an existing wagmi project that used @metamask/sdk, see the wagmi connector migration reference at the bottom of this page for a parameter mapping table.

Prerequisites

Set up using a template

  1. Download the MetaMask Connect Wagmi template:

    npx degit MetaMask/metamask-connect-examples/integrations/wagmi metamask-wagmi
  2. Navigate into the repository:

    cd metamask-wagmi
    Degit vs. Git clone

    degit is a tool that enables cloning only the directory structure from a GitHub repository, without retrieving the entire repository.

    Alternatively, use git clone to download the entire repository. Clone the MetaMask Connect examples repository and navigate into the quickstarts/wagmi directory:

    git clone https://github.com/MetaMask/metamask-connect-examples
    cd metamask-connect-examples/integrations/wagmi
  3. Install dependencies:

    pnpm install
  4. Run the project:

    pnpm dev

Set up manually

1. Install dependencies

Install MetaMask Connect EVM along with its peer dependencies to an existing React project:

npm install @metamask/connect-evm wagmi@latest @wagmi/connectors@latest viem@2.x @tanstack/react-query

2. Import required dependencies

In the root of your project, import the required dependencies:

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { http, WagmiProvider, createConfig } from 'wagmi'
import { mainnet, sepolia, lineaSepolia } from 'wagmi/chains'
import { metaMask } from 'wagmi/connectors'

3. Configure your project

Set up your configuration with the desired chains and connectors. In the following example, replace <NEXT_PUBLIC_INFURA_API_KEY> with your Infura API key:

const INFURA_KEY = process.env.NEXT_PUBLIC_INFURA_API_KEY!;

const config = createConfig({
ssr: true, // Enable this if your dapp uses server-side rendering.
chains: [mainnet, sepolia, lineaSepolia],
connectors: [
metaMask({
dapp: {
name: 'My Dapp',
url: window.location.origin,
},
}),
],
transports: {
[mainnet.id]: http(`https://mainnet.infura.io/v3/${INFURA_KEY}`),
[sepolia.id]: http(`https://sepolia.infura.io/v3/${INFURA_KEY}`),
[lineaSepolia.id]: http(`https://linea-sepolia.infura.io/v3/${INFURA_KEY}`),
},
});

4. Set up providers

Wrap your application with the necessary providers:

const client = new QueryClient()

const App = () => {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={client}>
<Component {...pageProps} />
</QueryClientProvider>
</WagmiProvider>
)
}

5. Add the connect button

Add the wallet connect and disconnect buttons to your application:

import { useAccount, useConnect, useDisconnect } from 'wagmi'

export const ConnectButton = () => {
const { address } = useAccount()
const { connectors, connect } = useConnect()
const { disconnect } = useDisconnect()

return (
<div>
{address ? (
<button onClick={() => disconnect()}>Disconnect</button>
) : (
connectors.map(connector => (
<button key={connector.uid} onClick={() => connect({ connector })}>
{connector.name}
</button>
))
)}
</div>
)
}

After adding the connect button, test your dapp by running pnpm run dev.

Common operations

Switch chains

Use useSwitchChain and useChainId to let users switch between your configured chains:

import { useSwitchChain, useChainId } from 'wagmi'

function ChainSwitcher() {
const chainId = useChainId()
const { chains, switchChain } = useSwitchChain()

return (
<div>
{chains.map(chain => (
<button
key={chain.id}
disabled={chainId === chain.id}
onClick={() => switchChain({ chainId: chain.id })}>
{chain.name}
</button>
))}
</div>
)
}

Sign a message

Use useSignMessage to request a personal_sign signature from the connected wallet:

import { useSignMessage } from 'wagmi'

function SignMessage() {
const { data: signature, signMessage, isPending } = useSignMessage()

return (
<div>
<button disabled={isPending} onClick={() => signMessage({ message: 'Hello from my dapp!' })}>
Sign Message
</button>
{signature && <p>Signature: {signature}</p>}
</div>
)
}

Send a transaction

Use useSendTransaction and useWaitForTransactionReceipt to send ETH and track confirmation:

import { useSendTransaction, useWaitForTransactionReceipt } from 'wagmi'
import { parseEther } from 'viem'

function SendTransaction() {
const { data: hash, sendTransaction, isPending } = useSendTransaction()
const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash })

return (
<div>
<button
disabled={isPending}
onClick={() =>
sendTransaction({
to: '0xRecipientAddress',
value: parseEther('0.01'),
})
}>
{isPending ? 'Sending...' : 'Send 0.01 ETH'}
</button>
{isConfirming && <p>Confirming...</p>}
{isSuccess && <p>Confirmed! Hash: {hash}</p>}
</div>
)
}

Connect and sign

Use the connectAndSign connector option to connect and prompt the user to sign a message in a single approval:

metaMask({
dapp: { name: 'My Dapp', url: window.location.origin },
connectAndSign: 'By signing, you agree to our Terms of Service.',
})

Connect and execute

Use the connectWith connector option to connect and execute any RPC method in a single approval:

metaMask({
dapp: { name: 'My Dapp', url: window.location.origin },
connectWith: {
method: 'eth_signTypedData_v4',
params: [address, JSON.stringify(typedData)],
},
})

Production readiness

tip

For production deployments, use reliable RPC providers instead of public nodes. We recommend using services like Infura to ensure better reliability and performance. See the production readiness checklist for more details.

Migrate from @metamask/sdk

If you previously used @metamask/sdk with wagmi, the MetaMask connector now uses @metamask/connect-evm under the hood. Update your dependencies and connector configuration:

  1. Replace @metamask/sdk with @metamask/connect-evm:

    npm uninstall @metamask/sdk
    npm install @metamask/connect-evm
  2. Update connector options:

    Old parameter (@metamask/sdk)New parameter (@metamask/connect-evm)Notes
    dappMetadata: { name, url }dapp: { name, url, iconUrl }dappMetadata still works but is deprecated
    logging: { sdk: true }debug: truelogging still works but is deprecated
    useDeeplink: booleanmobile: { useDeeplink: boolean }Moved into mobile namespace
    preferredOpenLinkmobile: { preferredOpenLink }Moved into mobile namespace
    forceDeleteProvider(removed)Not needed with new SDK
    forceInjectProvider(removed)Not needed with new SDK
    injectProvider(removed)Not needed with new SDK
    readonlyRPCMap(auto-configured)Built automatically from wagmi's chain config

For non-wagmi migration details, see the full migration guide.

Next steps

After completing the basic setup, follow these guides to add your own functionality: