Decentralized applications (DApps) on Ethereum rely on wallets like MetaMask to let users interact with the blockchain—signing transactions, sending ETH, or calling smart contracts. For developers, integrating MetaMask into a DApp is a crucial step to create a seamless user experience. This beginner-friendly guide will walk you through connecting your DApp to MetaMask using JavaScript libraries like Web3.js or Ethers.js. Let’s dive in!

What Is MetaMask?
MetaMask is a browser extension and mobile app that acts as a crypto wallet and gateway to Ethereum. It lets users manage ETH, interact with DApps, and sign blockchain transactions securely. For DApp developers, MetaMask provides a JavaScript API (window.ethereum
) to connect your app to the user’s wallet.
By integrating MetaMask, your DApp can:
- Request user account access.
- Send transactions (e.g., transfer ETH).
- Interact with smart contracts (e.g., call functions).
Why Connect DApps to MetaMask?
MetaMask is the most popular Ethereum wallet, used by millions. Connecting your DApp to MetaMask makes it accessible to a wide audience and enhances user trust. It also simplifies blockchain interactions, as MetaMask handles complex tasks like transaction signing, leaving you to focus on building a great app.
Tools You’ll Need
To connect your DApp to MetaMask, gather these tools:
- Node.js: For setting up a front-end app. Download from nodejs.org.
- MetaMask: Install the browser extension from metamask.io.
- Web3.js or Ethers.js: JavaScript libraries to interact with Ethereum. Install via npm.
- React: For building a front-end (optional but used in this guide). Create with
npx create-react-app
. - Testnet: Use the Sepolia testnet and get test ETH from sepoliafaucet.com.
- Smart Contract: A deployed contract to interact with (we’ll use a simple example).
With these, you’re ready to integrate MetaMask into your DApp.

Step-by-Step: Connecting Your DApp to MetaMask
We’ll build a simple DApp front-end that connects to MetaMask, displays the user’s account, and interacts with a smart contract to store and retrieve a number. We’ll use React and Ethers.js for simplicity, but Web3.js works similarly. Follow along!
Step 1: Deploy a Sample Smart Contract
For this guide, we’ll use a simple Solidity contract called Storage
. Deploy it on the Sepolia testnet using Remix IDE (remix.ethereum.org). Here’s the contract code:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Storage { uint256 public number; function setNumber(uint256 _number) public { number = _number; } function getNumber() public view returns (uint256) { return number; } }
Compile and deploy it to Sepolia via Remix, using MetaMask to sign the transaction. Note the contract’s address and ABI (from Remix’s “Compilation Details”).
Step 2: Set Up the React Front-End
Create a new React app in your terminal:
npx create-react-app metamask-dapp cd metamask-dapp npm install ethers
Replace src/App.js
with this code to connect to MetaMask and interact with the contract:
import { useState, useEffect } from 'react'; import { ethers } from 'ethers'; import './App.css'; const contractAddress = 'YOUR_CONTRACT_ADDRESS'; // From Remix const contractABI = [/* YOUR_CONTRACT_ABI */]; // From Remix function App() { const [account, setAccount] = useState(null); const [contract, setContract] = useState(null); const [number, setNumber] = useState(''); const [storedNumber, setStoredNumber] = useState(null); useEffect(() => { const connectWallet = async () => { if (window.ethereum) { try { const provider = new ethers.BrowserProvider(window.ethereum); const accounts = await provider.send('eth_requestAccounts', []); setAccount(accounts[0]); const signer = await provider.getSigner(); const contract = new ethers.Contract(contractAddress, contractABI, signer); setContract(contract); const currentNumber = await contract.getNumber(); setStoredNumber(currentNumber.toString()); } catch (error) { console.error('Connection failed:', error); } } else { alert('Please install MetaMask!'); } }; connectWallet(); }, []); const setContractNumber = async () => { if (!contract || !number) return; try { const tx = await contract.setNumber(number); await tx.wait(); const updatedNumber = await contract.getNumber(); setStoredNumber(updatedNumber.toString()); setNumber(''); } catch (error) { console.error('Transaction failed:', error); } }; return ( MetaMask DApp {account ? ( Connected Account: {account} ) : ( Connecting to MetaMask... )} setNumber(e.target.value)} /> Set Number {storedNumber !== null && ( Stored Number: {storedNumber} )} ); } export default App;
Update contractAddress
and contractABI
with your contract’s details. This code:
- Connects to MetaMask and retrieves the user’s account.
- Loads the
Storage
contract using Ethers.js. - Lets users set a new number and displays the stored number.
Step 3: Style the Front-End
Add basic styling in src/App.css
:
.App { text-align: center; padding: 50px; font-family: Arial, sans-serif; } input { padding: 10px; margin: 10px; width: 200px; } button { padding: 10px 20px; margin: 5px; cursor: pointer; background-color: #f39c12; color: white; border: none; border-radius: 5px; } button:hover { background-color: #e67e22; } p { margin: 10px 0; }
This creates a clean, user-friendly interface.

Step 4: Test Your DApp
Run your React app with npm start
. Open it in a browser with MetaMask installed and connected to the Sepolia testnet. Click to connect your wallet, enter a number, and click “Set Number.” MetaMask will prompt you to sign the transaction. After it’s confirmed, the stored number will update. Your DApp is now fully integrated with MetaMask!
Step 5: Handle MetaMask Events (Optional)
To improve user experience, listen for MetaMask events like account changes. Add this to the useEffect
in App.js
:
window.ethereum.on('accountsChanged', (accounts) => { setAccount(accounts[0] || null); });
This updates the displayed account if the user switches wallets in MetaMask.
Web3.js vs. Ethers.js: Which to Use?
Both libraries connect DApps to MetaMask, but they differ slightly:
- Web3.js: Older, more established, with a larger community. Better for legacy projects.
- Ethers.js: Lightweight, modern, and easier to use. Ideal for new DApps.
We used Ethers.js for its simplicity, but you can adapt the code for Web3.js by replacing the provider and contract logic. Check web3js.readthedocs.io for Web3.js docs.
Tips for a Better MetaMask Integration
To make your DApp’s MetaMask connection smooth and secure, follow these tips:
- Handle Errors: Show user-friendly messages for common issues, like MetaMask not installed or transaction rejections.
- Support Multiple Networks: Prompt users to switch to the correct network (e.g., Sepolia) using
wallet_switchEthereumChain
. - Optimize UX: Add loading states during transactions to keep users informed.
- Test Thoroughly: Use tools like Hardhat to simulate MetaMask interactions locally.
These practices enhance your DApp’s reliability and user experience.
Next Steps for DApp Developers
You’ve connected your DApp to MetaMask—great work! Here’s how to keep building:
- Enhance the DApp: Add features like toggling the number or displaying transaction history.
- Explore Frameworks: Use Truffle or Hardhat for easier contract management. Learn more at trufflesuite.com.
- Improve Security: Audit your contract for vulnerabilities using SWC Registry.
- Join Communities: Connect with developers on Ethereum Stack Exchange or MetaMask’s forums.
Keep experimenting to create innovative DApps.
Conclusion
Connecting your DApp to MetaMask is a key step in Ethereum development. With Ethers.js and a simple front-end, you’ve built an app that interacts with a smart contract via MetaMask, letting users sign transactions seamlessly. This guide is just the start—MetaMask integration opens the door to countless decentralized possibilities.
Try enhancing your DApp, testing on mainnet, or sharing your project with the community. Have questions or ideas? Leave a comment below!