{"id":3592,"date":"2026-09-29T15:50:14","date_gmt":"2026-09-29T15:50:14","guid":{"rendered":"https:\/\/nownodes.io\/blog\/?p=3592"},"modified":"2026-09-29T15:50:16","modified_gmt":"2026-09-29T15:50:16","slug":"how-to-connect-a-dapp-to-metamask-with-ethers-js-v6","status":"publish","type":"post","link":"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/","title":{"rendered":"How to Connect a Dapp to MetaMask With Ethers.js v6"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">To connect a dapp to MetaMask with Ethers.js, wrap the wallet&#8217;s injected provider in a <code>BrowserProvider<\/code>, ask the user for account access with <code>eth_requestAccounts<\/code>, and call <code>getSigner()<\/code>. That gives your code an address to read from and a signer that can request transaction approvals. The whole flow fits in about 20 lines of JavaScript.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MetaMask reported more than <a href=\"https:\/\/bitcoinmagazine.com\/business\/metamask-launches-native-bitcoin-integration-for-30-million-active-users\" rel=\"nofollow noopener noreferrer\">30 million monthly active users<\/a> in late 2025, so for most Ethereum dapps it is the first wallet users try. This guide covers the current way to do it: Ethers.js v6, EIP-6963 wallet discovery, and the error cases that break a first integration.<\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"what-does-it-mean-to-connect-a-dapp-to-metamask\">What does it mean to connect a dapp to MetaMask?<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Connecting means your web page gets permission to see one or more of the user&#8217;s addresses and to ask the wallet to sign things on their behalf. The private keys never leave MetaMask. Your dapp only receives an address and, later, signed results.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MetaMask exposes this through a JavaScript object that follows <a href=\"https:\/\/eips.ethereum.org\/EIPS\/eip-1193\">EIP-1193<\/a>, the standard provider interface. It has a <code>request<\/code> method for JSON-RPC calls and emits events such as <code>accountsChanged<\/code> and <code>chainChanged<\/code>. Permissions are granted per origin, so a user who approves <code>app-one.com<\/code> has approved nothing for <code>app-two.com<\/code>.<\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"why-use-ethersjs-for-the-connection\">Why use Ethers.js for the connection?<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Ethers.js turns the raw provider into typed, readable objects. Without it, you send hand-built JSON-RPC requests and parse hex strings yourself. With it, you call <code>provider.getBalance(address)<\/code> and get a <code>bigint<\/code> back.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Richard Moore, the library&#8217;s author, described the goal in the <a href=\"https:\/\/docs.ethers.org\/v6\/getting-started\/\" rel=\"nofollow noopener noreferrer\">Ethers documentation<\/a> as &#8220;a complete and compact library for interacting with the Ethereum Blockchain and its ecosystem.&#8221; The compact part matters for frontends, because bundle size affects load time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ethers v6 splits responsibilities into three objects:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Object<\/th><th>Role<\/th><th>Example call<\/th><\/tr><\/thead><tbody><tr><td>Provider<\/td><td>Reads chain data<\/td><td><code>provider.getBalance(addr)<\/code><\/td><\/tr><tr><td>Signer<\/td><td>Holds an account and requests signatures<\/td><td><code>signer.sendTransaction(tx)<\/code><\/td><\/tr><tr><td>Contract<\/td><td>Talks to a deployed smart contract<\/td><td><code>contract.balanceOf(addr)<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h2 class=\"wp-block-heading\" id=\"what-do-you-need-before-you-start\">What do you need before you start?<\/h2>\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"512\" src=\"https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/image-72-1024x512.png\" alt=\"\" class=\"wp-image-3594\" srcset=\"https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/image-72-1024x512.png 1024w, https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/image-72-300x150.png 300w, https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/image-72-768x384.png 768w, https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/image-72-1536x768.png 1536w, https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/image-72.png 1774w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">You need Node.js, a frontend project, the MetaMask browser extension, and a small amount of testnet ETH. Install the library with <code>npm install ethers<\/code>. The current major version is 6, and the <a href=\"https:\/\/github.com\/ethers-io\/ethers.js\/releases\" rel=\"nofollow noopener noreferrer\">v6 release line<\/a> is what the code below targets.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use a testnet while you build. <a href=\"https:\/\/ethereum.org\/developers\/docs\/networks\/\" rel=\"nofollow noopener noreferrer\">ethereum.org lists Sepolia<\/a> as the recommended testnet for app developers, with Hoodi aimed at validators and Holesky deprecated. Note that ethereum.org also flags Sepolia&#8217;s expected end of life for late September 2026, with a replacement running in parallel, so check that page before you pin a chain ID in your config. Our guide to <a href=\"https:\/\/nownodes.io\/blog\/what-is-sepolia-a-complete-guide-to-ethereum-testnet\" rel=\"nofollow noopener noreferrer\">the Sepolia testnet<\/a> explains how to fund a test wallet.<\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"how-do-you-detect-metamask-in-the-browser\">How do you detect MetaMask in the browser?<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Listen for EIP-6963 announcements and pick the provider whose <code>rdns<\/code> is <code>io.metamask<\/code>. Older tutorials read <code>window.ethereum<\/code> directly, but that global breaks when several wallet extensions are installed, because they overwrite each other.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/eips.ethereum.org\/EIPS\/eip-6963\" rel=\"nofollow noopener noreferrer\">EIP-6963<\/a> fixes this with browser events. Each wallet announces itself with an <code>info<\/code> object (<code>uuid<\/code>, <code>name<\/code>, <code>icon<\/code>, <code>rdns<\/code>) and a provider. Your dapp collects the announcements and lets the user, or your code, choose.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">js<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { BrowserProvider, formatEther, parseEther } from \"ethers\";\n\nfunction findMetaMask() {\n  return new Promise((resolve) =&gt; {\n    let found = null;\n    window.addEventListener(\"eip6963:announceProvider\", (event) =&gt; {\n      if (event.detail.info.rdns === \"io.metamask\") found = event.detail.provider;\n    });\n    window.dispatchEvent(new Event(\"eip6963:requestProvider\"));\n    setTimeout(() =&gt; resolve(found ?? window.ethereum ?? null), 300);\n  });\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Two cautions. The <code>rdns<\/code> value is self-reported, so a malicious extension could claim it. And <code>window.ethereum<\/code> stays in the code only as a fallback for older setups.<\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"how-do-you-request-accounts-and-create-a-signer\">How do you request accounts and create a signer?<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Wrap the injected provider in <code>BrowserProvider<\/code>, then call <code>eth_requestAccounts<\/code>. This call opens the MetaMask popup. The user approves or rejects, and your code continues only after they decide.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">js<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export async function connect() {\n  const injected = await findMetaMask();\n  if (!injected) throw new Error(\"MetaMask not found\");\n\n  const provider = new BrowserProvider(injected);\n  await provider.send(\"eth_requestAccounts\", &#91;]);\n\n  const signer = await provider.getSigner();\n  const address = await signer.getAddress();\n  const { chainId } = await provider.getNetwork();\n  const wei = await provider.getBalance(address);\n\n  return { injected, provider, signer, address, chainId, balance: formatEther(wei) };\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s the detail that trips people up: <code>getSigner()<\/code> is asynchronous in v6, and <code>BrowserProvider<\/code> replaced the v5 <code>Web3Provider<\/code>. If you copy v5 code, you will hit <code>ethers.providers is undefined<\/code>, because that namespace no longer exists. The <a href=\"https:\/\/docs.ethers.org\/v6\/migrating\/\" rel=\"nofollow noopener noreferrer\">migration guide<\/a> lists every rename.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tie the call to a button click. Browsers and MetaMask both treat unprompted popups as hostile, and a request on page load is a common reason for a user to leave.<\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"how-do-you-read-the-balance-and-network\">How do you read the balance and network?<\/h2>\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/image-73-1024x683.png\" alt=\"\" class=\"wp-image-3595\" srcset=\"https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/image-73-1024x683.png 1024w, https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/image-73-300x200.png 300w, https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/image-73-768x512.png 768w, https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/image-73.png 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><code>provider.getBalance(address)<\/code> returns the balance in wei as a <code>bigint<\/code>, and <code>formatEther<\/code> converts it to a readable string. <code>provider.getNetwork()<\/code> returns the chain ID, also as a <code>bigint<\/code> in v6.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Compare chain IDs as bigints or convert them first. <code>chainId === 11155111<\/code> fails when the value is <code>11155111n<\/code>. Sepolia is <code>11155111<\/code> in decimal and <code>0xaa36a7<\/code> in hex, which is the form MetaMask uses in <code>wallet_switchEthereumChain<\/code>.<\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"how-do-you-send-a-transaction\">How do you send a transaction?<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Call <code>signer.sendTransaction()<\/code> with a recipient and a value in wei, then wait for the receipt. MetaMask shows the user the amount and the gas estimate, and the promise resolves once they confirm.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">js<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export async function sendEth(signer, to, amount) {\n  const tx = await signer.sendTransaction({ to, value: parseEther(amount) });\n  const receipt = await tx.wait();\n  return receipt.status === 1;\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>tx.wait()<\/code> resolves when the transaction is mined, so show a pending state in the UI between the click and the receipt. A <code>status<\/code> of <code>1<\/code> means success and <code>0<\/code> means the transaction reverted. If you want to preview costs before sending, a <a href=\"https:\/\/nownodes.io\/gwei-calculator\">Gwei calculator<\/a> converts gas prices into ETH and dollars.<\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"how-do-you-handle-account-and-network-changes\">How do you handle account and network changes?<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Subscribe to <code>accountsChanged<\/code> and <code>chainChanged<\/code> on the injected provider and refresh your state in both handlers. Users switch accounts and networks inside MetaMask without telling your page. If you ignore the events, your UI keeps showing the old address.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">js<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function watch(injected, refresh) {\n  injected.on(\"accountsChanged\", (accounts) =&gt; {\n    accounts.length === 0 ? showDisconnected() : refresh();\n  });\n  injected.on(\"chainChanged\", () =&gt; refresh());\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">An empty <code>accounts<\/code> array means the user disconnected the site, so clear your session state. To move a user to the right network, call <code>wallet_switchEthereumChain<\/code>. If the wallet doesn&#8217;t know the chain, it fails with code <code>4902<\/code>, and you then call <code>wallet_addEthereumChain<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">js<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>async function switchChain(injected, chainIdHex) {\n  try {\n    await injected.request({\n      method: \"wallet_switchEthereumChain\",\n      params: &#91;{ chainId: chainIdHex }],\n    });\n  } catch (err) {\n    if (err.code !== 4902) throw err;\n    \/\/ Unknown chain: call wallet_addEthereumChain with its parameters\n  }\n}<\/code><\/pre>\n\n\n<h2 class=\"wp-block-heading\" id=\"what-errors-will-you-run-into\">What errors will you run into?<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Most failures come from six causes, and each has a recognizable code. Handle them explicitly, because MetaMask&#8217;s default messages are not written for end users. The <a href=\"https:\/\/docs.metamask.io\/wallet\/reference\/provider-api\/\" rel=\"nofollow noopener noreferrer\">MetaMask provider API reference<\/a> documents the RPC error codes.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Error<\/th><th>Meaning<\/th><th>What to do<\/th><\/tr><\/thead><tbody><tr><td><code>ACTION_REJECTED<\/code> \/ <code>4001<\/code><\/td><td>User declined the popup<\/td><td>Show a neutral message and let them retry<\/td><\/tr><tr><td><code>-32002<\/code><\/td><td>A request is already pending<\/td><td>Ask the user to open MetaMask and answer it<\/td><\/tr><tr><td><code>4902<\/code><\/td><td>Chain not added to the wallet<\/td><td>Call <code>wallet_addEthereumChain<\/code><\/td><\/tr><tr><td><code>INSUFFICIENT_FUNDS<\/code><\/td><td>Balance below value plus gas<\/td><td>Show the shortfall and a faucet link on testnets<\/td><\/tr><tr><td><code>CALL_EXCEPTION<\/code><\/td><td>Contract call reverted<\/td><td>Log the revert reason for debugging<\/td><\/tr><tr><td>No provider<\/td><td>Extension not installed<\/td><td>Link to the MetaMask install page<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">In Ethers v6 you can test for a rejection with <code>isError(err, \"ACTION_REJECTED\")<\/code> instead of comparing numeric codes.<\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"which-connection-method-fits-your-project\">Which connection method fits your project?<\/h2>\n\n\n<p class=\"wp-block-paragraph\">For a plain Ethers.js dapp, EIP-6963 with a <code>BrowserProvider<\/code> is the right default. Other options exist for mobile support or multi-wallet UIs, and they trade control for convenience.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Method<\/th><th>Best for<\/th><th>Trade-off<\/th><\/tr><\/thead><tbody><tr><td><code>window.ethereum<\/code><\/td><td>Quick prototypes<\/td><td>Conflicts when multiple wallets are installed<\/td><\/tr><tr><td>EIP-6963 discovery<\/td><td>Production desktop dapps<\/td><td>You write the wallet picker<\/td><\/tr><tr><td><a href=\"https:\/\/docs.metamask.io\/\" rel=\"nofollow noopener noreferrer\">MetaMask Connect EVM<\/a><\/td><td>Desktop plus mobile MetaMask<\/td><td>Adds a dependency, MetaMask-specific<\/td><\/tr><tr><td>wagmi \/ viem<\/td><td>React apps with many wallets<\/td><td>Different library from Ethers.js<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">MetaMask Connect EVM (<code>@metamask\/connect-evm<\/code>) replaces the older <code>@metamask\/sdk<\/code>. You pass its provider to <code>BrowserProvider<\/code> the same way you would pass an injected one, so your Ethers code stays the same.<\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"does-your-dapp-need-a-separate-readonly-provider\">Does your dapp need a separate read-only provider?<\/h2>\n\n\n<p class=\"wp-block-paragraph\">Often yes. <code>BrowserProvider<\/code> only works while the user has the wallet connected, and it sends reads through the user&#8217;s selected network. Pages that show public data before login, such as a token price or a contract&#8217;s state, need their own endpoint.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ethers.js has <code>JsonRpcProvider<\/code> for this. You point it at a node provider&#8217;s HTTPS URL and use it for reads, while the <code>BrowserProvider<\/code> signer handles writes. Our page on <a href=\"https:\/\/nownodes.io\/nodes\/ethereum-eth\">Ethereum node access<\/a> shows the endpoint format, and the <a href=\"https:\/\/nownodes.io\/public-endpoints\">public endpoints list<\/a> covers free options for testing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">js<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { JsonRpcProvider } from \"ethers\";\n\nconst readOnly = new JsonRpcProvider(\"https:\/\/eth.nownodes.io\/YOUR_API_KEY\");\nconst blockNumber = await readOnly.getBlockNumber();<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Don&#8217;t ship a private API key in frontend code. Anyone can read it from the browser&#8217;s network tab. Route reads through a small backend proxy, or use a key restricted to your domain if your provider supports it. For a larger walkthrough that includes contracts, see <a href=\"https:\/\/nownodes.io\/blog\/how-to-build-a-dapp-on-ethereum\">how to build a dapp on Ethereum<\/a>.<\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"conclusion\">Conclusion<\/h2>\n\n\n<p class=\"wp-block-paragraph\">The working pattern is short. Discover MetaMask with EIP-6963, wrap it in <code>BrowserProvider<\/code>, request accounts on a user click, and listen for <code>accountsChanged<\/code> and <code>chainChanged<\/code>. Add explicit handling for the rejection, pending-request, and unknown-chain errors, and keep a separate read-only provider for public data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Test on a current testnet, and confirm the chain ID against ethereum.org before you deploy, since the testnet lineup is changing.<\/p>\n\n\n<h3 class=\"wp-block-heading\" id=\"faq\">FAQ<\/h3>\n\n<h3 class=\"wp-block-heading\" id=\"does-connecting-a-wallet-cost-gas\">Does connecting a wallet cost gas?<\/h3>\n\n\n<p class=\"wp-block-paragraph\">No. <code>eth_requestAccounts<\/code> is a permission request, not a transaction, so it costs nothing and writes nothing to the chain. Gas applies only when the user confirms a state-changing transaction.<\/p>\n\n\n<h3 class=\"wp-block-heading\" id=\"how-do-i-migrate-my-v5-code-to-v6\">How do I migrate my v5 code to v6?<\/h3>\n\n\n<p class=\"wp-block-paragraph\">Rename <code>Web3Provider<\/code> to <code>BrowserProvider<\/code>, drop the <code>ethers.providers<\/code> and <code>ethers.utils<\/code> prefixes, and replace <code>BigNumber<\/code> with native <code>bigint<\/code>. <code>getSigner()<\/code> is now async. The <a href=\"https:\/\/docs.ethers.org\/v6\/migrating\/\" rel=\"nofollow noopener noreferrer\">official migration guide<\/a> has a full table.<\/p>\n\n\n<h3 class=\"wp-block-heading\" id=\"how-can-a-user-disconnect-from-my-dapp\">How can a user disconnect from my dapp?<\/h3>\n\n\n<p class=\"wp-block-paragraph\">Your dapp cannot force a disconnect, because permissions live in the wallet. The user revokes access in MetaMask&#8217;s connected-sites settings, and your <code>accountsChanged<\/code> handler receives an empty array. MetaMask also offers <code>wallet_revokePermissions<\/code> for dapps that want to trigger revocation.<\/p>\n\n\n<h3 class=\"wp-block-heading\" id=\"how-do-i-sign-a-message-instead-of-sending-a-transaction\">How do I sign a message instead of sending a transaction?<\/h3>\n\n\n<p class=\"wp-block-paragraph\">Call <code>signer.signMessage(\"text\")<\/code>. The user sees the text in a popup and approves, and you get a signature you can verify with <code>verifyMessage<\/code>. This is the basis of sign-in-with-Ethereum flows and costs no gas.<\/p>\n\n\n<h3 class=\"wp-block-heading\" id=\"does-this-work-in-mobile-browsers\">Does this work in mobile browsers?<\/h3>\n\n\n<p class=\"wp-block-paragraph\">Mobile browsers don&#8217;t run the MetaMask extension. Users either open your dapp inside MetaMask&#8217;s in-app browser, where the same provider is injected, or you use MetaMask Connect EVM to link the mobile app to your page.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>To connect a dapp to MetaMask with Ethers.js, wrap the wallet&#8217;s injected provider in a BrowserProvider, ask the user for account access with eth_requestAccounts, and call getSigner(). That gives your code an address to read from and a signer that can request transaction approvals. The whole flow fits in about 20 lines of JavaScript. MetaMask [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":3593,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_eb_attr":"","_lmt_disableupdate":"","_lmt_disable":"","_monsterinsights_skip_tracking":false,"footnotes":""},"categories":[102],"tags":[],"class_list":["post-3592","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dev-report"],"blocksy_meta":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.0 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Connect a Dapp to MetaMask With Ethers.js: 2026 Guide<\/title>\n<meta name=\"description\" content=\"Connect your dapp to MetaMask with Ethers.js v6. Detect the wallet via EIP-6963, request accounts, read balances, send transactions and handle errors.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Connect a Dapp to MetaMask With Ethers.js: 2026 Guide\" \/>\n<meta property=\"og:description\" content=\"Connect your dapp to MetaMask with Ethers.js v6. Detect the wallet via EIP-6963, request accounts, read balances, send transactions and handle errors.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/\" \/>\n<meta property=\"og:site_name\" content=\"NOWNodes Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-29T15:50:14+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-29T15:50:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/text_3-11.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1800\" \/>\n\t<meta property=\"og:image:height\" content=\"900\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"\u0410nastasia\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@nownodes\" \/>\n<meta name=\"twitter:site\" content=\"@nownodes\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"\u0410nastasia\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/\"},\"author\":{\"name\":\"\u0410nastasia\",\"@id\":\"https:\/\/nownodes.io\/blog\/#\/schema\/person\/0890ec68e813adecb93c18ee00e1e7a8\"},\"headline\":\"How to Connect a Dapp to MetaMask With Ethers.js v6\",\"datePublished\":\"2026-09-29T15:50:14+00:00\",\"dateModified\":\"2026-09-29T15:50:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/\"},\"wordCount\":1499,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/nownodes.io\/blog\/#organization\"},\"articleSection\":[\"Dev Report\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/\",\"url\":\"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/\",\"name\":\"Connect a Dapp to MetaMask With Ethers.js: 2026 Guide\",\"isPartOf\":{\"@id\":\"https:\/\/nownodes.io\/blog\/#website\"},\"datePublished\":\"2026-09-29T15:50:14+00:00\",\"dateModified\":\"2026-09-29T15:50:16+00:00\",\"description\":\"Connect your dapp to MetaMask with Ethers.js v6. Detect the wallet via EIP-6963, request accounts, read balances, send transactions and handle errors.\",\"breadcrumb\":{\"@id\":\"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Blog\",\"item\":\"https:\/\/nownodes.io\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Dev Report\",\"item\":\"https:\/\/nownodes.io\/blog\/category\/dev-report\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"How to Connect a Dapp to MetaMask With Ethers.js v6\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/nownodes.io\/blog\/#website\",\"url\":\"https:\/\/nownodes.io\/blog\/\",\"name\":\"NOWNodes Blog\",\"description\":\"Your first-to-go source of development guides, web3 analytics and most recent news about NOWNodes\",\"publisher\":{\"@id\":\"https:\/\/nownodes.io\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/nownodes.io\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/nownodes.io\/blog\/#organization\",\"name\":\"NOWNodes Blog\",\"url\":\"https:\/\/nownodes.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/nownodes.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2024\/02\/cropped-New-Logo-NN.png\",\"contentUrl\":\"https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2024\/02\/cropped-New-Logo-NN.png\",\"width\":1164,\"height\":1164,\"caption\":\"NOWNodes Blog\"},\"image\":{\"@id\":\"https:\/\/nownodes.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/twitter.com\/nownodes\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/nownodes.io\/blog\/#\/schema\/person\/0890ec68e813adecb93c18ee00e1e7a8\",\"name\":\"\u0410nastasia\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/nownodes.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/1de24ab8dcdd7ec30f6adaf78b56bc1eda421f87575b7e103c8fc3fc4420e833?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/1de24ab8dcdd7ec30f6adaf78b56bc1eda421f87575b7e103c8fc3fc4420e833?s=96&d=mm&r=g\",\"caption\":\"\u0410nastasia\"},\"url\":\"https:\/\/nownodes.io\/blog\/author\/nasty-nownodes\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Connect a Dapp to MetaMask With Ethers.js: 2026 Guide","description":"Connect your dapp to MetaMask with Ethers.js v6. Detect the wallet via EIP-6963, request accounts, read balances, send transactions and handle errors.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/","og_locale":"en_US","og_type":"article","og_title":"Connect a Dapp to MetaMask With Ethers.js: 2026 Guide","og_description":"Connect your dapp to MetaMask with Ethers.js v6. Detect the wallet via EIP-6963, request accounts, read balances, send transactions and handle errors.","og_url":"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/","og_site_name":"NOWNodes Blog","article_published_time":"2026-09-29T15:50:14+00:00","article_modified_time":"2026-09-29T15:50:16+00:00","og_image":[{"width":1800,"height":900,"url":"https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2026\/09\/text_3-11.jpg","type":"image\/jpeg"}],"author":"\u0410nastasia","twitter_card":"summary_large_image","twitter_creator":"@nownodes","twitter_site":"@nownodes","twitter_misc":{"Written by":"\u0410nastasia","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/#article","isPartOf":{"@id":"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/"},"author":{"name":"\u0410nastasia","@id":"https:\/\/nownodes.io\/blog\/#\/schema\/person\/0890ec68e813adecb93c18ee00e1e7a8"},"headline":"How to Connect a Dapp to MetaMask With Ethers.js v6","datePublished":"2026-09-29T15:50:14+00:00","dateModified":"2026-09-29T15:50:16+00:00","mainEntityOfPage":{"@id":"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/"},"wordCount":1499,"commentCount":0,"publisher":{"@id":"https:\/\/nownodes.io\/blog\/#organization"},"articleSection":["Dev Report"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/","url":"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/","name":"Connect a Dapp to MetaMask With Ethers.js: 2026 Guide","isPartOf":{"@id":"https:\/\/nownodes.io\/blog\/#website"},"datePublished":"2026-09-29T15:50:14+00:00","dateModified":"2026-09-29T15:50:16+00:00","description":"Connect your dapp to MetaMask with Ethers.js v6. Detect the wallet via EIP-6963, request accounts, read balances, send transactions and handle errors.","breadcrumb":{"@id":"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/nownodes.io\/blog\/how-to-connect-a-dapp-to-metamask-with-ethers-js-v6\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Blog","item":"https:\/\/nownodes.io\/blog"},{"@type":"ListItem","position":2,"name":"Dev Report","item":"https:\/\/nownodes.io\/blog\/category\/dev-report"},{"@type":"ListItem","position":3,"name":"How to Connect a Dapp to MetaMask With Ethers.js v6"}]},{"@type":"WebSite","@id":"https:\/\/nownodes.io\/blog\/#website","url":"https:\/\/nownodes.io\/blog\/","name":"NOWNodes Blog","description":"Your first-to-go source of development guides, web3 analytics and most recent news about NOWNodes","publisher":{"@id":"https:\/\/nownodes.io\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/nownodes.io\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/nownodes.io\/blog\/#organization","name":"NOWNodes Blog","url":"https:\/\/nownodes.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/nownodes.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2024\/02\/cropped-New-Logo-NN.png","contentUrl":"https:\/\/nownodes.io\/blog\/wp-content\/uploads\/2024\/02\/cropped-New-Logo-NN.png","width":1164,"height":1164,"caption":"NOWNodes Blog"},"image":{"@id":"https:\/\/nownodes.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/twitter.com\/nownodes"]},{"@type":"Person","@id":"https:\/\/nownodes.io\/blog\/#\/schema\/person\/0890ec68e813adecb93c18ee00e1e7a8","name":"\u0410nastasia","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/nownodes.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/1de24ab8dcdd7ec30f6adaf78b56bc1eda421f87575b7e103c8fc3fc4420e833?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1de24ab8dcdd7ec30f6adaf78b56bc1eda421f87575b7e103c8fc3fc4420e833?s=96&d=mm&r=g","caption":"\u0410nastasia"},"url":"https:\/\/nownodes.io\/blog\/author\/nasty-nownodes"}]}},"modified_by":"\u0410nastasia","_links":{"self":[{"href":"https:\/\/nownodes.io\/blog\/wp-json\/wp\/v2\/posts\/3592","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nownodes.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nownodes.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nownodes.io\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/nownodes.io\/blog\/wp-json\/wp\/v2\/comments?post=3592"}],"version-history":[{"count":1,"href":"https:\/\/nownodes.io\/blog\/wp-json\/wp\/v2\/posts\/3592\/revisions"}],"predecessor-version":[{"id":3596,"href":"https:\/\/nownodes.io\/blog\/wp-json\/wp\/v2\/posts\/3592\/revisions\/3596"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nownodes.io\/blog\/wp-json\/wp\/v2\/media\/3593"}],"wp:attachment":[{"href":"https:\/\/nownodes.io\/blog\/wp-json\/wp\/v2\/media?parent=3592"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nownodes.io\/blog\/wp-json\/wp\/v2\/categories?post=3592"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nownodes.io\/blog\/wp-json\/wp\/v2\/tags?post=3592"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}