Developer Integration — web3.js, ethers, React, Node, Python

Try Tangem secure wallet →

Table of contents


Introduction

This page focuses on developer integration patterns for MetaMask: how browser-based dApps ask a software wallet for accounts, signatures, and transactions. I use MetaMask daily for testing and small trades (so I speak from hands-on experience). What I've found is that most problems come from lifecycle events — accounts or chain changes — and from assuming the wallet behaves like a backend RPC node.

Who this guide is for

Who should look elsewhere

If you haven't installed the extension or mobile app yet, see install-metamask-extension and install-metamask-mobile-app.

How MetaMask exposes a provider (quick primer)

MetaMask injects an EIP-1193-compatible provider into web pages as window.ethereum. You request access with a method call (eg. eth_requestAccounts) and then subscribe to provider events (accountsChanged, chainChanged). Simple. But there are details: the provider is a bridge to the user's private keys in the hot wallet. Requests must be user-initiated for UX and security reasons.

Events you must handle: accountsChanged, chainChanged, and disconnect. Do it on a testnet first.

web3.js — web3.js connect MetaMask (step by step)

If you want web3 js connect MetaMask, here's a minimal flow with web3.js v1.x.

import Web3 from 'web3';

async function connectWithWeb3() {
  if (!window.ethereum) throw new Error('No injected provider');
  const web3 = new Web3(window.ethereum);
  try {
    // ask user to connect
    await window.ethereum.request({ method: 'eth_requestAccounts' });
    const accounts = await web3.eth.getAccounts();
    return { web3, account: accounts[0] };
  } catch (err) {
    throw err; // user rejected or other error
  }
}

Listen for changes:

window.ethereum.on('accountsChanged', (accounts) => { /* update UI */ });
window.ethereum.on('chainChanged', (chainId) => { window.location.reload(); });

ethers.js — connect and sign

Many prefer ethers for its smaller API surface and utility helpers. For react connect MetaMask or plain JS this pattern is common.

import { ethers } from 'ethers';

async function connectWithEthers() {
  if (!window.ethereum) throw new Error('No provider');
  const provider = new ethers.providers.Web3Provider(window.ethereum, 'any');
  await provider.send('eth_requestAccounts', []);
  const signer = provider.getSigner();
  const address = await signer.getAddress();
  return { provider, signer, address };
}

Signing a message (useful for auth):

const signature = await signer.signMessage('Login request: 167244');

Server-side verification is a standard pattern (see below).

React integrations (react connect MetaMask)

A simple React button that asks MetaMask to connect is the most common UX. Below is the simplest pattern (no external hooks):

import React, { useState } from 'react';
import { ethers } from 'ethers';

export default function ConnectButton() {
  const [addr, setAddr] = useState(null);

  async function connect() {
    try {
      const { signer } = await connectWithEthers();
      setAddr(await signer.getAddress());
    } catch (e) {
      console.error(e);
    }
  }

  return <button onClick={connect}>{addr || 'Connect MetaMask'}</button>;
}

If you prefer structured tooling, compare connect-web3-react, web3modal connect MetaMask, or wagmi connect MetaMask for pre-built hooks and modal flows. React Native cannot directly access the browser extension — use WalletConnect or deep linking to the mobile app instead (see walletconnect-guide).

Server patterns: Node.js and Python (nodejs connect to MetaMask / python connect MetaMask)

Node.js cannot directly talk to a browser extension. So how do servers "connect to MetaMask"? The common pattern is:

  1. Frontend asks MetaMask to sign a challenge message.
  2. Frontend sends message + signature to backend.
  3. Backend verifies the signature and maps it to an address.

Node verification (ethers):

const { ethers } = require('ethers');
function verify(message, signature) {
  return ethers.utils.verifyMessage(message, signature); // returns address
}

Python verification (web3.py / eth-account):

from eth_account.messages import encode_defunct
from eth_account import Account

def verify(message, signature):
    msg = encode_defunct(text=message)
    return Account.recover_message(msg, signature=signature)

For on-chain reads/writes from a server you use an RPC node (Infura, Alchemy, or self-hosted). But that is separate from MetaMask — which remains a client signer.

Tooling & middlewares: web3modal, WalletConnect, wagmi

Tooling can simplify UX. web3modal connect MetaMask provides a modal picker for many wallets. WalletConnect links mobile wallets (useful for react native connect MetaMask flows). wagmi exposes React hooks for providers and signers.

Table: quick comparison

Integration Best for Notes
web3.js Classic dApps Familiar API, larger bundle
ethers.js Modern JS apps Utilities for signatures and ABI parsing
web3modal / WalletConnect Multi-wallet UX Adds mobile support (deep links)
wagmi / web3-react React apps Hook-based state management

For local development see connect-ganache-local and connect-remix.

Security checklist for dApp developers

For UI actions around approvals, link to token-approvals-revoke and security-best-practices.

Troubleshooting quick hits

For common UI problems see connect-button-troubleshoot and troubleshooting-dapp-connections.

Conclusion & next steps

Connecting to MetaMask is straightforward once you accept two realities: the provider lives in the browser, and signing belongs to the user. Which library you choose (web3.js, ethers, or a React toolkit) depends on your stack and team preferences.

Try these steps locally: wire up a simple connect button, request a signature, and verify it on a small Node or Python endpoint. And if you want to expand later, check the guides for connecting to networks (connect-to-networks, add-custom-network) and mobile flows (connect-walletconnect).

If you'd like, follow the hands-on examples here and then test against a local chain — it's the safest way to learn. Happy building.

Try Tangem secure wallet →