Skip to main content

Connect to EVM - Node.js quickstart

Get started with MetaMask Connect EVM in a Node.js application. The SDK displays a QR code in the terminal that you scan with the MetaMask mobile app to establish a connection.

No polyfills required

Node.js has native support for Buffer, crypto, stream, and other modules that require polyfilling in browser or React Native environments.

Prerequisites

Steps

1. Install dependencies

npm install @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:

index.mjs
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 async

createEVMClient 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 the MetaMask mobile app:

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

index.mjs
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 the MetaMask mobile app
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