// Safe check for an injected provider
if (typeof window.ethereum !== 'undefined' && window.ethereum.isMetaMask) {
try {
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
console.log('Connected', accounts[0]);
} catch (err) {
// user rejected or other error
console.error('Connection failed', err);
}
} else {
// fallback: suggest WalletConnect or instruct install
}
For a simple UI: wire that code to a "Connect" button. What should the connect button do beyond calling eth_requestAccounts? Ask for the account and then subscribe to events so your UI stays in sync.
But remember: a user can disconnect or change accounts at any time. Handle the accountsChanged and chainChanged events (example further below).
Image: ![placeholder: connect button screenshot]
Common methods and events (quick reference)
Below is a short table mapping commonly used methods/events to their purpose and typical usage.
| Method / Event |
Purpose |
Example / Notes |
| eth_requestAccounts |
Ask user to connect accounts |
Returns array of addresses; triggers accountsChanged on change |
| eth_accounts |
Read currently available accounts (no prompt) |
Useful on load to detect prior connection |
| eth_chainId |
Read current chain ID |
Hex string like 0x1 for Mainnet |
| wallet_switchEthereumChain |
Ask wallet to switch network |
Use chainId param (hex) |
| wallet_addEthereumChain |
Prompt to add a custom chain |
Provide chainName, rpcUrls, nativeCurrency |
| wallet_watchAsset |
Prompt to add ERC20 token to UI |
Good for token onboarding (not automatic) |
| eth_sendTransaction |
Create transaction and request user approval |
User confirms in wallet UI; returns txHash |
| personal_sign / eth_signTypedData_v4 |
Request signature |
For login flows or EIP-712 typed data |
| accountsChanged (event) |
User changed accounts |
Update UI; do not assume same address |
| chainChanged (event) |
Network switched |
Many dApps reload (or re-init providers) |
For more developer-focused guides, see developers-connect and connect-web3-react.
Network management: switch and add chains
When your dApp requires a specific chain (say a Layer 2 or a testnet), use wallet_switchEthereumChain. If the chain is missing in the user's wallet, follow with wallet_addEthereumChain. Example:
await ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: '0x89' }] // Polygon mainnet as hex
});
// If that throws an error indicating the chain is unknown:
await ethereum.request({
method: 'wallet_addEthereumChain',
params: [{
chainId: '0x89',
chainName: 'Polygon',
nativeCurrency: { name: 'MATIC', symbol: 'MATIC', decimals: 18 },
rpcUrls: ['https://rpc-mainnet.matic.network']
}]}
);
Don't hardcode RPC endpoints for production apps; prefer well-maintained public endpoints or let users choose (see add-custom-network and the network-specific guides like add-polygon).
Token & asset handling: add tokens and NFTs
To prompt the wallet UI to display a token you can call wallet_watchAsset. This only asks the user to add a token to their UI—no transfer occurs.
await ethereum.request({
method: 'wallet_watchAsset',
params: {
type: 'ERC20',
options: { address, symbol, decimals, image }
}
});
NFT viewing is mostly a UI concern (the wallet decides how to present token metadata). For token management best practices, see token-management and how to revoke approvals at token-approvals-revoke.
Signing and transactions: send, sign, simulate
Transactions via eth_sendTransaction require a from address and usually hex-encoded values. If you want EIP-1559 fields, include maxFeePerGas and maxPriorityFeePerGas.
For signatures, personal_sign or eth_signTypedData_v4 are common. Use typed signatures (EIP-712) for structured data when possible; they are easier for users to audit.
And always display a preview of the transaction or message in your UI before calling the provider. Users will rely on that to detect phishing attempts.
Developer best practices: UX, security, mobile
- Subscribe to provider events (accountsChanged, chainChanged, disconnect). Update UI state gracefully; avoid silent reloads unless you must.
- Provide clear error handling for user rejection.
- Offer a fallback path (WalletConnect or deep linking) for mobile users who don't have an injected provider (see connect-walletconnect and install-metamask-mobile-app).
- Protect users from accidental unlimited token approvals; show clear warnings (I once approved an unlimited allowance by accident and had to revoke it—useful learning).
But don't implement signing flows that assume the user understands every low-level parameter. Make gas and recipient fields explicit in your UI.
Testing and troubleshooting
Test on local environments like Ganache or with Remix to inspect transactions before they hit public testnets. (See connect-ganache-local and connect-remix.)
Common troubleshooting tips:
- If accountsChanged returns an empty array, the user may have locked the wallet. Ask them to unlock.
- chainChanged should trigger a reinitialization of network data (you can reload the page, but save UX state first).
- If wallet_switchEthereumChain fails with an error code for unknown chain, call wallet_addEthereumChain.
If connection seems broken, check the console for provider errors and consult the troubleshooting-connect page.
Who MetaMask is suitable for (pros & cons)
Who this software wallet is best for:
- Front-end web developers building DeFi dApps that expect an injected EVM-compatible provider.
- Users who prefer a desktop extension experience and those who use both desktop and mobile (the mobile app includes an in-app dApp browser).
Who should look elsewhere:
- Users or teams needing institutional custody or HSM-backed private key management.
- Apps that require guaranteed non-interactive signing flows (software wallets require user confirmation for most sensitive actions).
FAQ
Q: Is it safe to keep crypto in a hot wallet?
A: Hot wallets are convenient for daily DeFi use. They trade some security for usability. For larger holdings consider hardware or custodial options and use a software wallet for day-to-day activity. See backup-recovery for guidance on seed phrases and recovery.
Q: How do I revoke token approvals?
A: Revocation is outside the connect API itself, but your dApp can guide users to tools and contract calls that set allowances to zero. See token-approvals-revoke for step-by-step instructions and UI patterns.
Q: What happens if I lose my phone?
A: If the wallet was backed up with a seed phrase, you can restore on a new device using that seed phrase (or use cloud recovery if the user enabled it). For details see backup-recovery and backup-cloud-vs-paper.
Conclusion & next steps
The MetaMask Connect API (EIP-1193) gives you a predictable, event-driven way to talk to a user's software wallet. Implement explicit UX for connection, network switching, signing, and token onboarding, and pair that with robust error handling. If you're starting a dApp, try the sample code above and test on a local node or testnet (see connect-ganache-local and connect-remix).
Ready to implement a connect button? Start with the quick start above, then read the developer integration guide: developers-connect.