| title | Wagmi Integration - MetaMask Connect EVM | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| description | Integrate MetaMask Connect EVM into a React dapp using Wagmi hooks like useConnect and useConnection, with the MetaMask connector and wallet connection UI. | |||||||||||||
| toc_max_heading_level | 3 | |||||||||||||
| sidebar_label | Wagmi | |||||||||||||
| keywords |
|
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.
:::tip 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.
:::
- Node.js version 19 or later installed.
- A package manager installed, such as npm, Yarn, pnpm, or bun.
- MetaMask installed in your browser or on mobile.
- An Infura API key from the Infura dashboard.
-
Download the MetaMask Connect Wagmi template:
npx degit MetaMask/metamask-connect-examples/integrations/wagmi metamask-wagmi
-
Navigate into the repository:
cd metamask-wagmiDegit vs. Git clone
degitis a tool that enables cloning only the directory structure from a GitHub repository, without retrieving the entire repository.Alternatively, use
git cloneto download the entire repository. Clone the MetaMask Connect examples repository and navigate into thequickstarts/wagmidirectory:git clone https://github.com/MetaMask/metamask-connect-examples cd metamask-connect-examples/integrations/wagmi -
Install dependencies:
pnpm install
-
Run the project:
pnpm dev
Install MetaMask Connect EVM along with its peer dependencies to an existing React project:
:::note Version requirements
This quickstart requires wagmi@^3.6.0 and wagmi/connectors@^8.0.0
:::
npm install @metamask/connect-evm wagmi@^3.6.0 wagmi/connectors@^8.0.0 viem@2.x @tanstack/react-queryIn 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'Set up your configuration with the desired chains and connectors.
In the following example, replace <VITE_INFURA_API_KEY> with your Infura API key:
const INFURA_KEY = import.meta.env.VITE_INFURA_API_KEY
const config = createConfig({
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}`),
},
})Wrap your application with the necessary providers:
const client = new QueryClient()
const App = () => {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={client}>
<Component {...pageProps} />
</QueryClientProvider>
</WagmiProvider>
)
}Add the wallet connect and disconnect buttons to your application:
import { useConnection, useConnect, useConnectors, useDisconnect } from 'wagmi'
export const ConnectButton = () => {
const { address, isConnected } = useConnection()
const connectors = useConnectors()
const connect = useConnect()
const disconnect = useDisconnect()
const handleConnect = async () => {
// highlight-start
const connector = connectors.find(c => c.id === 'metaMaskSDK') ?? connectors[0]
await connect.mutateAsync({ connector })
// highlight-end
}
return (
<div>
{isConnected ? (
<button onClick={() => disconnect.mutate()}>Disconnect</button>
) : (
<button onClick={handleConnect}>Connect MetaMask</button>
)}
{address && <p>Connected: {address}</p>}
</div>
)
}After adding the connect button, test your dapp by running pnpm run dev.
Use useConnection, useChains, and useSwitchChain to let users switch between your configured chains:
import { useConnection, useChains, useSwitchChain } from 'wagmi'
function ChainSwitcher() {
const { chainId } = useConnection()
const chains = useChains()
const switchChain = useSwitchChain()
return (
<div>
{chains.map(chain => (
<button
key={chain.id}
disabled={chainId === chain.id}
onClick={() => switchChain.mutate({ chainId: chain.id })}>
{chain.name}
</button>
))}
</div>
)
}Use useSignMessage to request a personal_sign signature from the connected wallet:
import { useSignMessage } from 'wagmi'
function SignMessage() {
const signMessage = useSignMessage()
const handleSign = async () => {
const signature = await signMessage.mutateAsync({ message: 'Hello from my dapp!' })
console.log('Signature:', signature)
}
return (
<div>
<button disabled={signMessage.isPending} onClick={handleSign}>
{signMessage.isPending ? 'Signing...' : 'Sign Message'}
</button>
{signMessage.data && <p>Signature: {signMessage.data}</p>}
</div>
)
}Use useSendTransaction to send ETH:
import { useSendTransaction } from 'wagmi'
import { parseEther } from 'viem'
function SendTransaction() {
const sendTx = useSendTransaction()
const handleSend = async () => {
const hash = await sendTx.mutateAsync({
to: '0xRecipientAddress',
value: parseEther('0.01'),
})
console.log('Transaction hash:', hash)
}
return (
<div>
<button disabled={sendTx.isPending} onClick={handleSend}>
{sendTx.isPending ? 'Sending...' : 'Send 0.01 ETH'}
</button>
{sendTx.data && <p>Transaction hash: {sendTx.data}</p>}
</div>
)
}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.',
})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)],
},
}):::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. :::
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:
-
Replace
@metamask/sdkwith@metamask/connect-evmand update Wagmi packages:npm uninstall @metamask/sdk npm install @metamask/connect-evm wagmi@^3.6.0 wagmi/connectors@^8.0.0
-
Update hook usage for wagmi v3:
Old (wagmi v2) New (wagmi v3) Notes useAccountuseConnectionReturns address,isConnected,chainIduseConnectreturnsconnectorsuseConnectorshookConnectors are a separate hook connect({ connector })connect.mutate({ connector })Hooks return mutation objects signMessage({ message })signMessage.mutateAsync({ message })Use .mutateAsyncfor async resultssendTransaction({...})sendTx.mutateAsync({...})Use .mutateAsyncfor async resultsswitchChain({ chainId })switchChain.mutate({ chainId })Mutation pattern -
Update connector options:
Old parameter ( @metamask/sdk)New parameter ( @metamask/connect-evm)Notes dappMetadata: { name, url }dapp: { name, url, iconUrl }dappMetadatastill works but is deprecatedlogging: { sdk: true }debug: trueloggingstill works but is deprecateduseDeeplink: booleanmobile: { useDeeplink: boolean }Moved into mobilenamespacepreferredOpenLinkmobile: { preferredOpenLink }Moved into mobilenamespaceforceDeleteProvider(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.
After completing the basic setup, follow these guides to add your own functionality: