Wallets and tools · Explainer
MetaMask Snaps: How to Test Custom Wallet Experiences
MetaMask Snaps lets developers add custom screens, transaction warnings and new chain support to the wallet. This guide explains what snaps can change and how teams test those experiences safely before users see them.
By the DappsAtlas editorial team · Updated

What are MetaMask Snaps?
MetaMask Snaps is the extension system for the MetaMask wallet. A snap is a JavaScript program, published as an npm package, that adds features the core wallet does not include. Once a user approves it, MetaMask loads the snap into an isolated execution environment and calls it when something relevant happens, such as a transaction request, an incoming message from a website or a scheduled timer.
The idea behind snaps is that the wallet should not have to ship every feature itself. Teams can add support for blockchains that MetaMask does not handle natively, add security checks to transactions, or build their own screens inside the wallet. Because the snap runs inside MetaMask, the experience happens where the user already makes decisions, instead of in a separate tab or app.
A few points define the model:
- Snaps are sandboxed. They have no direct access to the page, the DOM or the browser. They can only call a defined set of wallet methods.
- Snaps are permissioned. Each capability, from showing a dialog to deriving keys, is declared in a manifest file and shown to the user at install time.
- Snaps are versioned and distributed through npm. The snap ID for a published snap takes the form of an npm package name.
- Snaps respond to handlers. You export functions with set names, and MetaMask calls them. You do not run a server that waits for requests.
The phrase 'custom user experience' covers a lot of ground here: a custom confirmation prompt, a home page tab inside MetaMask, a risk summary shown before signing, or a notification. Testing those experiences is a different job from testing a normal web app, because the surface is the wallet itself and mistakes can touch real assets.
What can a snap change about the wallet experience?
Snaps can shape several parts of the wallet experience. Which one you build on determines the handler you write, the permission you request and the way you test.
| Experience | What the user sees | Typical handler or method |
|---|---|---|
| Custom dialogs | An alert, confirmation or prompt with your own content | snap_dialog method |
| Transaction insights | Extra information or warnings in the transaction confirmation screen | onTransaction handler |
| Signature insights | Context shown while signing a message | onSignature handler |
| Home page | A dedicated snap page inside the wallet | onHomePage handler |
| Notifications | In-wallet or native alerts | snap_notify method |
| Scheduled tasks | Periodic checks, such as balance or status monitoring | onCronjob handler |
| Name resolution | Readable names in the address field | onNameLookup handler |
| Custom RPC | Methods that websites can call on your snap | onRpcRequest handler |
| Account or chain support | Non-EVM accounts and signing | Keyring snaps and key-derivation permissions |
Two patterns are especially common. The first is insight snaps, which examine a transaction before the user confirms and add plain-language context. A bridge or swap transaction, for example, can be hard to read in raw calldata, and an insight can say which contract is being called and what it will probably do. The second is companion snaps, which give a protocol a presence inside the wallet, such as a position summary or a status page.
Every one of these is a user-experience change, so the testing questions are about clarity as well as correctness. Does the screen say what will happen? Does it fail gracefully when the network is down? Does it still make sense on a small window?
How does the Snaps security model shape what you test?
Before testing the experience, it helps to understand the rules a snap runs under, because they define what can go wrong and what users are protected from.
Isolation. Snaps run in a locked-down JavaScript environment that limits access to globals and powerful browser features. A snap cannot reach into another snap or into the wallet's own state. Everything it does goes through the snap API.
Permissions. The manifest, a file named snap.manifest.json, lists the permissions the snap needs. These include handler permissions, called endowments, such as endowment:transaction-insight, endowment:cronjob and endowment:network-access. They also include method permissions such as snap_dialog, snap_manageState and snap_notify. Sensitive ones, such as key derivation through snap_getBip32Entropy, show up in the install prompt and are the ones users should read carefully.
Integrity. The manifest contains a hash of the built bundle. If public sources changes without the manifest being updated, MetaMask refuses to run it. Testers should treat a hash mismatch as a build-pipeline problem, not something to work around.
Storage. A snap can store its own data, encrypted, through snap_manageState. It cannot read other snaps' data.
No page access. A snap cannot render arbitrary HTML into a web page. Interfaces inside the wallet are built from a fixed set of components provided by the Snaps SDK, which is why snap screens look consistent.
For testing, the key consequence is that you should request the smallest permission set that supports the feature. Every extra permission is another thing a user, an auditor or MetaMask's review process has to trust, and another path to test.
How do you set up a snap test environment?
A snap test environment has four parts: a Node.js toolchain, the Snaps command line tools, MetaMask Flask and a way to call the snap.
1. Start from the template. The Snaps team provides a project template that you can scaffold with the npm create command for @metamask/snap. It generates a manifest, a source folder with a handler file, a configuration file and a test setup.
2. Use the CLI. The @metamask/snaps-cli package offers commands such as mm-snap build, mm-snap watch and mm-snap serve. Building produces public sources and updates the manifest hash. Serving publishes public sources on a local address so a wallet can load it.
3. Install MetaMask Flask. Flask is the developer distribution of MetaMask. It allows snaps loaded from a local address, and it exposes experimental snap features sooner than the stable wallet. Install it in a dedicated browser profile, because running Flask and the stable extension in the same profile can cause conflicts.
4. Use a test site. A simple web page that calls wallet_requestSnaps and then invokes your snap's RPC methods lets you trigger the flow as a real website would. The snap ID for a local build is written as local: followed by the local server address, while a published snap uses npm: followed by the package name.
Some hygiene rules for the environment:
- Use a fresh wallet with a throwaway recovery phrase and no real funds.
- Prefer test networks for anything that signs or sends.
- Keep a record of the Flask version and Snaps SDK version, since interface components and handler behavior can change between releases.
- Check the official Snaps documentation for the current supported Node.js version and any changed commands, as tooling evolves.
How do you build and test custom snap interfaces?
Snap interfaces are described as a tree of components rather than written as HTML. The Snaps SDK provides building blocks such as text, headings, buttons, form fields, dividers, links, images, tables and layout containers. Current SDK versions let you write these in JSX, and earlier versions used helper functions such as panel, heading and text. Check the SDK documentation for the version you use.
The interface appears in a few places:
- Dialogs. Call
snap_dialogwith a type of alert, confirmation or prompt. A confirmation returns the user's choice, which makes it the simplest way to test a decision flow. - Insights. Return content from
onTransactionoronSignatureand MetaMask displays it alongside the confirmation. Insights can also carry a severity marker for critical warnings. - Home page. Return content from
onHomePageto give the snap its own page in the wallet. - Interactive interfaces. Forms and buttons send events back through
onUserInput, so you can build multi-step flows.
What to test for each surface:
- Reading level. Show the text to someone who is not a developer. If they cannot say what will happen, rewrite it.
- Information order. The most important fact, such as an amount leaving the wallet, should come first.
- Empty and error states. Test no data, slow responses and failed requests.
- Long values. Addresses, token names and large numbers can break layouts.
- Cancellation. Confirm that dismissing a dialog leaves no half-finished state.
Because the wallet controls styling, you are testing content and flow, not visual design. That is a smaller surface, but wording mistakes in a signing screen can be costly.
How do you automate snap tests?
Clicking through Flask catches real wallet behavior, but it is slow. The Snaps team maintains a Jest-based testing framework, published as @metamask/snaps-jest, which runs your snap in a simulated environment so you can test handlers directly.
A typical test follows this pattern:
- Start the snap with the framework's install helper, which returns an object with methods to call it.
- Send an RPC request, a transaction or a signature to the snap through that object.
- Check the response, including the interface it returned.
- For interactive screens, simulate user input such as button clicks or form entries and check the next screen.
Useful things to cover in automated tests:
- Handler outputs. Given a sample transaction, does
onTransactionreturn the right warning text and severity? - Edge-case inputs. Unknown contracts, zero values, very large values, malformed data and unsupported chains.
- Network failure. Use the framework's mocking features to simulate a failed or slow API response, and confirm the snap degrades gracefully rather than showing a blank panel or a misleading all-clear.
- Cron jobs. Trigger the scheduled handler and check what it stores or notifies.
- State. Confirm stored data is written, read and cleared as intended.
- Permission paths. Check that your code handles a denied dialog or a missing optional capability.
Automated tests cannot replace a manual pass. The simulator does not reproduce every detail of the real wallet, including how a confirmation screen is laid out. A sensible split is to automate the logic and run a manual Flask pass for each release candidate, focused on what a person actually sees.
What should a manual UX test pass cover?
The install and update flow is part of the user experience, and it is where many snaps lose trust. Test it as a user would.
Install flow
- From a clean wallet, trigger
wallet_requestSnapsfrom your test site. - Read the connection and permission prompts. Do the permissions match what the feature needs and nothing more?
- Reject the install and check that your site handles the refusal without a broken state.
- Approve and confirm the snap answers its first call.
Usage flow
- Run the main task end to end on a test network.
- Switch accounts and networks mid-flow and check the snap reacts correctly.
- Lock and unlock the wallet, restart the browser and confirm stored state survives.
Update flow
- Publish or serve a new version with a changed permission and see how the wallet prompts for it. Added permissions should be rare and well explained.
- Check that state saved by the old version still works with the new one, or is migrated.
- Use lifecycle handlers such as
onInstallandonUpdatefor first-run guidance, and test both.
Removal flow
- Uninstall the snap from the wallet's settings and check your site detects that it is gone.
- Make sure no recurring notifications or cron behavior continue.
Accessibility and language
- Check long text, non-English names and tokens with unusual symbols.
- Keep messages short enough to read in a small confirmation window.
Write these steps down as a checklist and run them on every release. Most snap UX bugs show up in transitions, such as first install, upgrade or failure, rather than in the main happy path.
Which UX mistakes should testing catch?
Several mistakes recur in snap interfaces, and they are worth deliberately testing for.
False reassurance. An insight that shows 'no issues found' can be read as 'safe'. If the check only covers a known list of risks, say so. Show what was checked and what was not, and what the snap does when its data source is unreachable. A failed lookup should never look the same as a clean result.
Alert fatigue. If every transaction gets a warning, users stop reading. Reserve high-severity markers for genuinely critical conditions and test that ordinary transactions stay quiet.
Unexplained jargon. Terms like 'calldata', 'approval' and 'router' mean little to most users. Describe the effect: 'This lets the contract spend your tokens until you revoke it.'
Dialog overuse. Pop-up dialogs interrupt. Use them for decisions only. Information belongs in insights or the home page.
Stale data. Prices, risk scores and token metadata change. Show timestamps or sources where data matters, and test what the snap shows when the data is old.
Hidden network calls. A snap with endowment:network-access can contact outside servers. Make sure the user can tell when a feature depends on one, and test with the network blocked.
Over-broad permissions. Teams often request access early for convenience and never remove it. Review the manifest before every release and drop what you do not use.
A useful exercise is to run the same transaction through the snap with the data source working, slow, down and returning garbage. If the user would reach the same confident conclusion in all four cases, the experience is wrong.
How do you publish and review a snap?
Once a snap works locally, publishing is a matter of releasing the package to npm and, for broader visibility, getting it listed in the Snaps directory. Local local: snap IDs are for development in Flask; a published snap is referenced by its npm package.
Before release:
- Review the manifest. Check the name, description, permissions, supported chains and repository link. A clear description reduces user suspicion.
- Lock dependencies. Fewer and better-known dependencies mean a smaller attack surface in a sandboxed bundle.
- Reproducible builds. The manifest hash must match the published bundle, and teams should be able to rebuild from source and get the same result.
- Get an independent review. A snap that handles keys, signs, or influences transactions is security-critical code. Specialist security firms and audit contest platforms, Sherlock among them, review onchain and Web3 code, and an audit report gives users something concrete to check. Ask the reviewer to look at permissions and failure behavior, not just the code.
- Test on stable. Verify the installed experience in the stable MetaMask build, since Flask supports features and settings that may not match.
Distribution rules, directory requirements and the review process for listing can change. Check the official Snaps documentation and the directory's current guidelines before planning a launch, rather than relying on older guides.
Plan for maintenance too. A published snap can be updated, but each update that adds permissions asks users to approve again. Keeping permissions stable between versions makes updates smoother.
How should users evaluate and install snaps safely?
Users are the last line of defense, and snaps change what a wallet can do. The advice is defensive and simple.
Before installing
- Find the snap through a trusted listing and check the publisher's identity, repository and any audit report.
- Read the permission prompt line by line. Be cautious about anything involving private key derivation, broad network access or account management unless the snap's purpose clearly requires it.
- Be wary of any website that urges you to install a snap to claim a reward or fix a wallet problem.
While using it
- Treat insights as extra information, not as a guarantee. A snap that says a transaction looks fine does not make it safe.
- Keep checking the details MetaMask itself shows: the recipient, the amount, the network and any token approval.
- Use a small, separate wallet when trying a new snap.
After use
- Remove snaps you no longer need in the wallet's settings.
- Watch for update prompts that add permissions, and decline if the reason is unclear.
- Revoke token approvals through the wallet or a trusted approvals tool if you gave a contract spending access.
This matters in DeFi, where a user might bridge or swap across networks with apps such as Across, Stargate V2 or deBridge. A transaction-insight snap can make those transactions easier to read, but the user still decides. Privacy-focused protocols such as Railgun and Hinkal also work with wallets, and users should review any snap that claims to support them as carefully as any other software holding signing power.
Frequently asked questions
What is a MetaMask Snap in simple terms?
A snap is a JavaScript module, packaged and distributed through npm, that extends MetaMask. It runs in an isolated environment and can use only the permissions its manifest declares and the user approves. Snaps can show custom interfaces, add transaction insights, support other chains or run scheduled tasks.
Why do developers use MetaMask Flask for snap testing?
Flask is MetaMask's experimental build for developers. It lets you install snaps served from a local development server and test features before they reach the stable wallet. Because it is experimental, use it in a separate browser profile with no real funds, and keep it apart from the stable extension.
Can a snap take my funds automatically?
Not by default. A snap can only do what its manifest permissions allow, and the user sees those permissions before installing. A snap that requests broad access, such as key derivation, deserves much more scrutiny than one that only displays a dashboard or a transaction warning.
Can I automate snap tests without opening a browser?
Yes. The Snaps testing framework, built for Jest, lets you install a snap in a simulated environment and call its handlers. You can check the interfaces it returns, simulate transaction insights and test cron jobs without clicking through a browser every time. Manual passes in Flask are still worth doing for the real wallet flow.
How do I decide whether to install a snap as a user?
Check the snap's listing in the Snaps directory, read the permissions in the install prompt, and look at who publishes it and whether it has been audited. Then try it with a small wallet first. If the permissions seem broader than the feature needs, decline the install.
Mentioned in this guide
dApps in this guide
Sherlock is a Web3 security firm offering audits, contests, AI review and bug bounties for onchain teams, formerly known for DeFi coverage.
Railgun is a zk-SNARK privacy protocol for Ethereum, Arbitrum, BNB Chain and Polygon that shields DeFi transactions, for users wanting on-chain privacy.
Hinkal is a multichain privacy protocol for shielded stablecoin transfers and swaps, with viewing-key compliance, for users, developers and enterprises.
Across is an intent-based cross-chain bridge and swap protocol for moving tokens between Ethereum, rollups and other chains, with an API for apps.
Stargate V2 is a LayerZero-powered cross-chain bridge for moving USDC, USDT, ETH, BTC and OFTs across many chains, aimed at DeFi users and liquidity providers.
Hyperlane is a permissionless interoperability protocol and bridge for sending tokens and data across 150+ chains, aimed at builders and bridge users.
deBridge is a cross-chain protocol for swapping and transferring tokens and data between blockchains, aimed at users who move assets across networks.
Superfluid is a money streaming protocol that sends tokens by the second across ten chains, aimed at DAOs, builders and users of streaming apps.
Current is a Sui-based lending protocol with isolated markets and one-click yield multiply, focused on tokenized real-economy yield.
Keep reading
Related guides
Wallets and tools · How-to
How to Use a Ledger With the Coinbase Wallet App (2026 Guide)
Coinbase Wallet can be paired with a Ledger hardware device so your keys stay offline while you use the app. This guide covers preparation, setup, signing, dApp use and fixes for common pairing problems.
Wallets and tools · Explainer
Quicknode Explained: High-Performance Web3 Infrastructure
Quicknode is a hosted blockchain infrastructure provider that gives apps, wallets and trading teams RPC access and data tools across dozens of chains. This guide explains what it does, how it works and when it is the right fit.
Wallets and tools · How-to
How to Transfer Crypto From PayPal to a Wallet or Exchange
PayPal lets eligible users send supported crypto to wallets and exchanges they control. This guide covers the checks to make first, the step-by-step send, the fees and limits to expect, and the mistakes that cost people funds.
Wallets and tools · How-to
How to Install and Use Blocto Wallet on Flow (2026 Guide)
Blocto is a smart-contract wallet built around Flow's multi-key account model. This guide covers installing it, creating a Flow account, moving tokens, connecting to apps and keeping the account safe.
Wallets and tools · Review
MetaMask Swap Review: How In-Wallet Token Swaps Work in 2026
MetaMask Swap is the token exchange built into the MetaMask wallet, and its main appeal is that you can trade without leaving the wallet. This guide covers how it works, what it costs in practice, and the risks that matter more than the convenience.
Wallets and tools · Explainer
MetaMask Mobile Overhaul and Apple Pay Fiat On-Ramp Explained (2026)
MetaMask has expanded its fiat buy and sell options on mobile, and Apple Pay is one payment method that some on-ramp providers accept. This guide explains how the flow works, what to check before paying, and how to keep your wallet safe while converting money to crypto and back.
Wallets and tools · Comparison
MetaMask Swap vs SushiSwap: How to Choose a Token Swap Route
MetaMask Swap and SushiSwap both let you trade tokens from a self-custody wallet, but they work in different ways. This guide explains how each one routes trades, what to compare before you sign, and how to choose between them.
Wallets and tools · Explainer
MetaLend Explained: Crypto Tracking and DeFi Management Tool
MetaLend is presented as an all-in-one tool for tracking crypto holdings and managing DeFi positions. This guide explains what that kind of tool does, what to verify about MetaLend before using it, and how to connect safely.