Integrate MetaMask with Your DApp — Provider API & Events

Try Tangem secure wallet →

Table of contents


What this guide covers

This is a practical developer guide to integrate MetaMask with your DApp using the injected provider and provider events. Expect step-by-step examples you can copy, plus notes on mobile integration (including how to integrate MetaMask with mobile app flows), and how to handle the common metamask account change event in your UI. I tested flows on desktop Chrome and on mobile (MetaMask in-app browser and WalletConnect), and I’ll explain exactly how so you can reproduce the tests.

Quick glossary & prerequisites

Prereqs:

How I tested (replicate my setup)

I used a local React app (localhost:3000) and a local node (Hardhat). Steps to reproduce:

  1. Start a local chain: npx hardhat node.
  2. Run your dApp: npm start (on :3000).
  3. Expose to mobile with ngrok: ngrok http 3000 and open the forwarded URL in MetaMask mobile.
  4. In Chrome, open the app and connect via the extension.

I switched accounts manually in the extension to trigger accountsChanged and used WalletConnect (scan QR) to confirm the same events on mobile. Logs and console screenshots were taken while switching accounts and chains (see placeholder below).

Web integration (login MetaMask on Chrome) — step by step

Short version? Call the provider and ask for accounts. Simple.

Step-by-step:

  1. Detect provider:
const provider = window.ethereum;
if (!provider) {
  // show install instructions (/install-metamask-chrome)
}
  1. Request accounts ("login MetaMask on Chrome"):
try {
  const accounts = await provider.request({ method: 'eth_requestAccounts' });
  // use accounts[0]
} catch (err) {
  // user rejected or error
}
  1. Start listening for events (next section shows details).

What I did in testing: I simulated a login button that calls eth_requestAccounts and then shows the connected account and balance. That replicates the UX users expect from Chrome extension flows.

Handling MetaMask provider events (metamask provider events)

The provider emits EIP-1193 events. Handle them and your app won't surprise the user.

Key events and how I handled them in tests:

provider.on('accountsChanged', (accounts) => {
  if (accounts.length === 0) {
    // user locked MetaMask
    logoutUser();
  } else {
    setConnectedAccount(accounts[0]);
    // refresh balances, allowances
  }
});

What should your dApp do when accountsChanged fires? Check whether the change invalidates pending actions (signed messages, token allowances). I once had a pending trade fail because the user switched accounts mid-flow. Lesson learned: clear pending transactions after an account switch.

Integrate MetaMask with mobile app — options and steps

There are three practical approaches to integrate MetaMask on mobile:

  1. In-app browser (MetaMask mobile): open your web dApp inside the MetaMask mobile browser and the provider is injected automatically. Fast and simple. (If you need to test, use ngrok to expose localhost.)

  2. WalletConnect: for native mobile apps, WalletConnect lets your app request a session and the user approves in MetaMask mobile. This is the most common pattern for native apps.

  3. MetaMask SDK: an SDK exists to simplify native integrations (it wraps tunneling and deep-linking flows). Use it when you want a tighter experience.

A short mobile test I ran: I served my dApp via ngrok, opened the URL inside MetaMask mobile, called eth_requestAccounts, then switched accounts — the same accountsChanged event fired on the injected provider. So your web code can be identical in desktop and mobile browser contexts. But for native apps, implement WalletConnect session handling.

For a practical WalletConnect walkthrough see: walletconnect-and-mobile-dapps.

Common UX patterns & the "Action needed: change account" case

You may see an error or wallet prompt that effectively says: "Action needed: change account in the wallet extension." What does this mean? Usually your transaction or signing request expects a specific account (or the from address differs from the connected account). The wallet then asks the user to switch accounts.

How to handle it in your code:

And always show clear UI guidance: "Please switch to the account that holds the tokens you want to use." Users appreciate that.

Integration methods comparison (table)

Method Where it runs Events supported Best for
Injected provider (extension) Desktop Chrome/Firefox accountsChanged, chainChanged, connect, disconnect Web dApps, quick desktop testing
MetaMask mobile (in-app browser) Mobile app browser Same as injected Mobile web dApps
WalletConnect Native mobile apps (QR / deep link) Session lifecycle (plus provider events) Native app integrations
MetaMask SDK Native apps (SDK bridge) Higher-level helpers Teams building native integrations

Developer best practices & security notes

I've made mistakes here: once I tried to resume a swap after an account change and the signed call used the old account. It failed and confused users. So handle events gracefully.

Troubleshooting checklist

For more general dev troubleshooting see: troubleshooting.

FAQ

Q: How do I detect an account change from MetaMask?

A: Listen to the accountsChanged event on window.ethereum and update your app state. If the array is empty, treat as disconnected.

Q: How can I integrate MetaMask with mobile app users?

A: Use the MetaMask in-app browser for web dApps or WalletConnect / MetaMask SDK for native apps. (Step-by-step above.)

Q: What if I see "Action needed: change account in the wallet extension"?

A: Confirm the connected account matches the tx from. If not, prompt the user to switch accounts or re-request accounts.

Wrap-up and next steps

Integrating MetaMask is mostly about listening and reacting to provider events. Test both Chrome extension and mobile flows (I used ngrok and WalletConnect to reproduce real mobile behavior). And remember: handle accountsChanged and chainChanged early in your lifecycle so users don’t hit confusing failures mid-flow.

Want a hands-on checklist to connect a dApp and test user flows? Start with connect-metamask-to-dapps and then follow developer patterns in developer-workflow. If you hit weird errors, check troubleshooting next.

If you'd like, I can paste a copy-paste starter repo with the connect + listeners code I used for testing. Would that help?

Try Tangem secure wallet →