Connect to MetaMask using Node.js
Get started with MetaMask Connect EVM in a Node.js application. The SDK displays a QR code in the terminal that you scan with MetaMask Mobile to establish a connection.
Node.js has native support for Buffer, crypto, stream, and other modules that require
polyfilling in browser or React Native environments.
Prerequisites
- Node.js version 20 or later installed.
- A package manager installed, such as npm, Yarn, or pnpm.
- MetaMask Mobile installed on your phone.
- An Infura API key from the MetaMask Developer dashboard.
Steps
1. Install dependencies
- npm
- Yarn
- pnpm
- Bun
npm install @metamask/connect-evm @metamask/connect-multichain
yarn add @metamask/connect-evm @metamask/connect-multichain
pnpm add @metamask/connect-evm @metamask/connect-multichain
bun add @metamask/connect-evm @metamask/connect-multichain
@metamask/connect-multichain provides the getInfuraRpcUrls helper for generating RPC URLs.
2. Initialize the EVM client
Create a file (for example, index.mjs) and initialize the client.
In Node.js, there is no window.location, so you must set dapp.url explicitly:
import { createEVMClient } from '@metamask/connect-evm'
import { getInfuraRpcUrls } from '@metamask/connect-multichain'
const evmClient = await createEVMClient({
dapp: {
name: 'My Node.js App',
url: 'https://myapp.com',
},
api: {
supportedNetworks: getInfuraRpcUrls({
infuraApiKey: 'YOUR_INFURA_API_KEY',
}),
},
})
createEVMClient is asynccreateEVMClient returns a promise. Always await it before using the client.
The client is a singleton -- calling createEVMClient again returns the same instance.
3. Connect to MetaMask
Call connect() to start the connection flow.
A QR code appears in the terminal -- scan it with MetaMask Mobile:
try {
const { accounts, chainId } = await evmClient.connect({
chainIds: ['0x1'],
})
console.log('Connected account:', accounts[0])
console.log('Active chain:', chainId)
} catch (error) {
if (error.code === 4001) {
console.log('User rejected the connection request')
} else if (error.code === -32002) {
console.log('Connection request already pending')
} else {
console.error('Connection failed:', error)
}
}
4. Use the provider
Get the EIP-1193 provider and make JSON-RPC requests:
const provider = evmClient.getProvider()
const balance = await provider.request({
method: 'eth_getBalance',
params: [accounts[0], 'latest'],
})
console.log('Balance (wei):', balance)
5. Sign a message
Use personal_sign to request a signature from the connected wallet:
const message = '0x' + Buffer.from('Hello from Node.js!', 'utf8').toString('hex')
const signature = await provider.request({
method: 'personal_sign',
params: [message, accounts[0]],
})
console.log('Signature:', signature)
6. Disconnect
await evmClient.disconnect()
console.log('Disconnected')
Listen for events
Use eventHandlers in the client configuration to react to connection state changes:
const evmClient = await createEVMClient({
dapp: {
name: 'My Node.js App',
url: 'https://myapp.com',
},
api: {
supportedNetworks: getInfuraRpcUrls({
infuraApiKey: 'YOUR_INFURA_API_KEY',
}),
},
eventHandlers: {
connect: ({ accounts, chainId }) => {
console.log('Connected:', accounts, 'on chain', chainId)
},
disconnect: () => {
console.log('Disconnected')
},
accountsChanged: (accounts) => {
console.log('Accounts changed:', accounts)
},
chainChanged: (chainId) => {
console.log('Chain changed:', chainId)
},
},
})
Full example
import { createEVMClient } from '@metamask/connect-evm'
import { getInfuraRpcUrls } from '@metamask/connect-multichain'
const evmClient = await createEVMClient({
dapp: {
name: 'My Node.js App',
url: 'https://myapp.com',
},
api: {
supportedNetworks: getInfuraRpcUrls({
infuraApiKey: 'YOUR_INFURA_API_KEY',
}),
},
})
// Connect -- scan the QR code with MetaMask Mobile
const { accounts, chainId } = await evmClient.connect({ chainIds: ['0x1'] })
console.log('Connected:', accounts[0], 'on', chainId)
// Get balance
const provider = evmClient.getProvider()
const balance = await provider.request({
method: 'eth_getBalance',
params: [accounts[0], 'latest'],
})
console.log('Balance:', balance)
// Sign a message
const message = '0x' + Buffer.from('Hello from Node.js!', 'utf8').toString('hex')
const signature = await provider.request({
method: 'personal_sign',
params: [message, accounts[0]],
})
console.log('Signature:', signature)
// Disconnect
await evmClient.disconnect()
console.log('Disconnected')
Run it with:
node index.mjs
Next steps
- Manage user accounts
- Send transactions
- Sign data
- Use the Multichain SDK to connect to both EVM and Solana from a single session