> For the complete documentation index, see [llms.txt](/llms.txt).

# 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[​](#prerequisites "Direct link to Prerequisites")

- [Node.js](https://nodejs.org/) version 20 or later installed.
- A package manager installed, such as [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), [Yarn](https://yarnpkg.com/), or [pnpm](https://pnpm.io/installation).
- The [MetaMask mobile app](https://metamask.io/download/) installed on your phone.
- An [Infura API key](/developer-tools/dashboard/get-started/create-api/) from the Infura dashboard.

## Steps[​](#steps "Direct link to Steps")

### 1\. Install MetaMask Connect EVM[​](#1-install-metamask-connect-evm "Direct link to 1. Install MetaMask Connect EVM")

Install the EVM client in an existing Node.js project:

- npm
- Yarn
- pnpm
- Bun

```
npm install @metamask/connect-evm

```

```
yarn add @metamask/connect-evm

```

```
pnpm add @metamask/connect-evm

```

```
bun add @metamask/connect-evm

```

### 2\. Initialize MetaMask Connect EVM[​](#2-initialize-metamask-connect-evm "Direct link to 2. Initialize MetaMask Connect EVM")

Create a file (`index.mjs`) and initialize the client using [createEVMClient](/metamask-connect/evm/reference/methods/#createevmclient). In Node.js, there is no `window.location`, so you must set `dapp.url` explicitly:

index.mjs

```
import { createEVMClient, getInfuraRpcUrls } from '@metamask/connect-evm'

const evmClient = await createEVMClient({
  dapp: {
    name: 'My Node.js App',
    url: 'https://myapp.com',
  },
  api: {
    supportedNetworks: getInfuraRpcUrls({
      infuraApiKey: 'YOUR_INFURA_API_KEY',
    }),
  },
})

```

Async client

`createEVMClient` returns a promise. Always `await` it before using the client.

### 3\. Connect to MetaMask[​](#3-connect-to-metamask "Direct link to 3. Connect to MetaMask")

Call [connect](/metamask-connect/evm/reference/methods/#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[​](#4-use-the-provider "Direct link to 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[​](#5-sign-a-message "Direct link to 5. Sign a message")

Use [personal_sign](/metamask-connect/evm/reference/json-rpc-api/personal%5Fsign/) 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[​](#6-disconnect "Direct link to 6. Disconnect")

```
await evmClient.disconnect()
console.log('Disconnected')

```

## Listen for events[​](#listen-for-events "Direct link to 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[​](#full-example "Direct link to Full example")

index.mjs

```
import { createEVMClient, getInfuraRpcUrls } from '@metamask/connect-evm'

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[​](#next-steps "Direct link to Next steps")

- [Manage user accounts](/metamask-connect/evm/guides/manage-user-accounts/)
- [Send transactions](/metamask-connect/evm/guides/send-transactions/)
- [Sign data](/metamask-connect/evm/guides/sign-data/)
