- Install the extension (see install-metamask-chrome or install-extension).
- After install, pin the extension to Chrome’s toolbar so the popup is easy to open.
- Create a new wallet or import an account using your seed phrase. (Don’t use mainnet keys on local test networks.)
- If the extension won’t show, open chrome://extensions/ and ensure MetaMask is toggled on.
And if a site can’t see MetaMask, check that the popup hasn’t blocked the connection request and that "site access" is permitted.
Local dev networks & MetaMask: step-by-step
Run a local node so you can deploy fast and without real funds. Two repeatable steps I use:
- Start a local node:
## Hardhat local node
npx hardhat node
- Add the local RPC to MetaMask (Network > Add network) with the RPC URL (typically http://127.0.0.1:8545) and the chainId your node uses (check your node output). See also local-development-ganache-geth and add-networks-custom-rpc.
You can import one of the unlocked private keys from the local node into MetaMask (only for testing). But never import a seed phrase tied to real funds.
Step-by-step: how to deploy contract with MetaMask (browser + ethers.js)
This example shows a minimal browser deploy flow using ethers.js and the injected provider.
- Connect and request accounts (how to authenticate MetaMask wallet):
// connect.js
import { ethers } from 'ethers';
async function connect() {
if (!window.ethereum) throw new Error('MetaMask not detected');
const provider = new ethers.providers.Web3Provider(window.ethereum);
// how to authenticate metamask wallet
await provider.send('eth_requestAccounts', []);
const signer = provider.getSigner();
return { provider, signer };
}
- Deploy a contract with ABI and bytecode (example):
import contractJson from './MyContract.json'; // compiled ABI + bytecode
async function deploy(signer) {
const factory = new ethers.ContractFactory(contractJson.abi, contractJson.bytecode, signer);
const contract = await factory.deploy(/* constructor args */, {
// optional overrides
gasLimit: 6000000,
});
console.log('txHash', contract.deployTransaction.hash);
await contract.deployed();
console.log('deployed at', contract.address);
return contract;
}
Note: you can pass EIP-1559 fields (maxFeePerGas, maxPriorityFeePerGas) in the overrides if needed.
If you prefer a UI IDE, the browser IDE can use the injected provider option (select "Injected Web3") so MetaMask handles signing.
How to detect MetaMask provider in React & authenticate (how to detect metamask provider react)
A common pattern in React apps is using @metamask/detect-provider. Example:
import detectEthereumProvider from '@metamask/detect-provider';
import { useEffect, useState } from 'react';
function useMetaMask() {
const [provider, setProvider] = useState(null);
useEffect(() => {
(async () => {
const p = await detectEthereumProvider();
if (p) setProvider(p);
})();
}, []);
return provider;
}
You can also check window.ethereum and window.ethereum.isMetaMask directly if you want a lightweight approach.
For authentication, issue a short challenge from your backend, ask the user to sign that message with signer.signMessage(challenge), and verify the signature server-side. That proves control of the account without moving funds.
Gas, EIP-1559 settings and transaction overrides
MetaMask exposes EIP-1559 fields in its send flow. When you deploy from the browser you can set overrides on the transaction. Example:
await factory.deploy(args…, {
maxFeePerGas: ethers.utils.parseUnits('100', 'gwei'),
maxPriorityFeePerGas: ethers.utils.parseUnits('2', 'gwei'),
});
But remember: MetaMask will surface a confirmation popup and may change suggested fees based on the network. Test on your local node first to avoid unexpected cost or dropped transactions.
Common developer pitfalls and debugging tips (metamask developer guide)
- MetaMask not detected in React? Use the detect-provider package and check provider === window.ethereum.
- "User rejected the request": handle this gracefully and show a retry button.
- "INSUFFICIENT_FUNDS": check the connected account balance on the selected network (local tokens differ from mainnet tokens).
- Wrong chainId: confirm the node chainId and update MetaMask or call wallet_switchEthereumChain.
A frequent mistake I made early on was deploying with an incorrect constructor signature (so the deploy reverted). Read the contract ABI and verify constructor args before sending.
Security checklist for developers
- Never expose your seed phrase or production private keys to dev tools. Store keys securely.
- Use testnets or a local node for development.
- Revoke unnecessary token approvals after testing (token-approvals-and-revoke).
- Integrate transaction simulation in CI if you run automated deploys (simulate calls with eth_call or dedicated services).
But even with caution, mistakes happen. I once approved an unlimited allowance to a test contract and had to walk through revoking it — that taught me to use minimal allowances in tests.
FAQ — quick answers to common questions
Q: Is it safe to deploy from a hot wallet?
A: It's common for testing and rapid iteration. For high-value mainnet deployments use a hardware signer or a CI process with strict key management. See integrate-hardware-ledger-trezor.
Q: How do I revoke token approvals?
A: Use a revoke UI (or call an approval reset transaction) and check the allowance on-chain. See token-approvals-and-revoke.
Q: How do I detect MetaMask provider in React?
A: Use @metamask/detect-provider or check window.ethereum and isMetaMask. Example above shows the pattern.
Who this workflow is well-suited for / who should look elsewhere
Who this is well-suited for:
- Front-end devs building dApps and prototypes.
- Developers testing contract interactions on local nodes or testnets.
- Educators and students learning how signing and deployment flows work.
Who should look elsewhere:
- Teams doing production-grade mainnet deployments with high-value contracts should use air-gapped or hardware keys and automated CI/CD with audit controls.
- If you need batched, gasless or account-abstraction features in production, explore smart contract wallets and account abstraction resources (account-abstraction-and-smart-wallets).
Final thoughts & next steps (CTA)
If you want a repeatable starting point: run npx hardhat node, add the local RPC to MetaMask, and try the example deployment above from a simple React page. That exercise shows how the provider detects, how signing works, and how MetaMask surfaces confirmations.
For step-by-step installation and troubleshooting see install-metamask-chrome, local-development-ganache-geth, and add-networks-custom-rpc. And if you’re building richer integrations, check out snaps-dev and developer-integration for advanced developer tools.
Want a checklist or a minimal repo to copy? Try the sample flow above and adapt it into your own project—then iterate on gas settings, error handling, and signature authentication. Good luck, and test safely.