MetaMask injects an EIP-1193-compatible provider into web pages (accessible as window.ethereum). That provider is what many dApps use to request accounts, sign messages, send transactions, and react to account or chain changes. The term "MetaMask Connect API" is commonly used to describe the developer-facing surface that apps call when they want the user to connect their software wallet.
In practice this means you treat the provider like an RPC bridge between your dApp and the user's non-custodial wallet. I believe the clearest mental model is: your UI requests an action; the provider prompts the user; the user approves or rejects (and the provider returns a result or an error).
(If you want a step-by-step install primer for users, see the install guides: extension and mobile app.)
A minimal connect flow (plain JavaScript):
// 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]
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.
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).
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.
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.
But don't implement signing flows that assume the user understands every low-level parameter. Make gas and recipient fields explicit in your UI.
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 connection seems broken, check the console for provider errors and consult the troubleshooting-connect page.
Who this software wallet is best for:
Who should look elsewhere:
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.
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.