Skip to content

Commit e6949f6

Browse files
Docs: add headless mode and Solana batch guides (#2867)
* Docs: add headless mode and Solana batch guides Add a new Multichain headless-mode guide and a Solana batch-transactions guide; expand troubleshooting and several SDK docs. Updates include: headless-mode guide describing display_uri flow and UI.headless usage; new Solana signAndSendAllTransactions guidance and Chrome Android cautions; added Wallet Adapter timing tip and Chrome Android warning; expanded Multichain methods reference with error classes and getSession access; small EVM/Multichain quickstart copy edits (base64Icon guidance) and migrate-from-sdk event docs; register new guides in the sidebar. Also apply minor copy/formatting edits across related docs. * Update metamask-connect/evm/guides/migrate-from-sdk.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/multichain/guides/headless-mode.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/multichain/guides/headless-mode.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/multichain/guides/headless-mode.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/multichain/guides/headless-mode.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/solana/guides/batch-transactions.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/solana/guides/batch-transactions.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/solana/guides/batch-transactions.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/solana/guides/batch-transactions.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/solana/guides/send-legacy-transaction.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/solana/guides/use-wallet-adapter.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/troubleshooting/index.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Update metamask-connect/multichain/guides/headless-mode.md Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com> * Clarify RN polyfills and preferExtension behavior Refactor troubleshooting content: explain that preferExtension defaults to true and show how to force the MetaMask Wallet Protocol/QR flow. Remove inlined React Native polyfill guidance from the main troubleshooting page and point to the expanded Metro polyfill guide instead. Expand metro-polyfill-issues.md with improved metadata, split polyfills into base vs optional (wagmi) sections, add deeplink/preferredOpenLink examples, and clarify import order and Buffer/Event polyfills. * Fixing DApp to Dapp As per Alex's suggestion before. But please note that the rule is saying to use `dapp` and neither of these `DApp` or `Dapp` https://github.com/MetaMask/metamask-docs/blob/main/.cursor/rules/terminology.mdc#L14 * Normalize 'Wallet Standard' capitalization Standardize phrasing across MetaMask Connect docs by replacing occurrences of "wallet-standard"/"Wallet-standard" with "Wallet Standard" and updating related references (e.g., "wallet-standard features" -> "Wallet Standard features", "wallet-standard adapter" -> "Wallet Standard adapter"). Affects EVM and Solana docs: metamask-connect/evm/guides/migrate-from-sdk.md and multiple Solana pages (guides, quickstart, index, and reference methods) for consistency and clarity. * Link stateChanged event to events reference Update metamask-connect/multichain/guides/headless-mode.md to replace the inline `stateChanged` mention with a link to the events reference (../reference/methods.md#events) for clearer documentation and easier navigation. --------- Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com>
1 parent f629d78 commit e6949f6

24 files changed

Lines changed: 731 additions & 59 deletions

metamask-connect/evm/guides/migrate-from-sdk.md

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ recreate it on every render.
9292
// remove-start
9393
- const sdk = new MetaMaskSDK({
9494
- dappMetadata: {
95-
- name: 'My DApp',
95+
- name: 'My Dapp',
9696
- url: window.location.href,
9797
- },
9898
- infuraAPIKey: 'YOUR_INFURA_KEY',
@@ -113,7 +113,7 @@ recreate it on every render.
113113
// add-start
114114
+ const client = await createEVMClient({
115115
+ dapp: {
116-
+ name: 'My DApp',
116+
+ name: 'My Dapp',
117117
+ url: window.location.href,
118118
+ },
119119
+ api: {
@@ -195,7 +195,7 @@ The method returns the signature directly:
195195

196196
```typescript
197197
const signature = await client.connectAndSign({
198-
message: 'Sign in to My DApp',
198+
message: 'Sign in to My Dapp',
199199
chainIds: ['0x1'],
200200
})
201201
```
@@ -267,11 +267,15 @@ provider.on('disconnect', () => {
267267
})
268268
```
269269

270-
MetaMask Connect EVM also supports SDK-level event handlers that you register during initialization:
270+
MetaMask Connect EVM also supports SDK-level event handlers that you register during initialization.
271+
The `connect` handler receives both `chainId` and `accounts` (a MetaMask Connect extension of the
272+
standard EIP-1193 `connect` event, which only includes `chainId`).
273+
See the [Ethereum provider API events](../reference/provider-api.md#events) for the full event
274+
reference.
271275

272276
```typescript
273277
const client = await createEVMClient({
274-
dapp: { name: 'My DApp' },
278+
dapp: { name: 'My Dapp' },
275279
api: {
276280
supportedNetworks: {
277281
'0x1': 'https://mainnet.infura.io/v3/YOUR_KEY',
@@ -291,7 +295,13 @@ const client = await createEVMClient({
291295
})
292296
```
293297

294-
You can also listen for the `display_uri` event on the **provider** for custom QR code UI:
298+
You can also listen for the `display_uri` event on the **provider** for custom QR code UI.
299+
300+
:::note Event naming
301+
The `eventHandlers` option uses camel case (`displayUri`), while the provider event uses snake case
302+
(`display_uri`).
303+
Both deliver the same URI string for QR code rendering.
304+
:::
295305

296306
```typescript
297307
const provider = client.getProvider()
@@ -308,7 +318,7 @@ MetaMask Connect EVM introduces features that are not available in `@metamask/sd
308318
| ---------------------- | ---------------------------------------------------------------------------------------------------------- |
309319
| **Multichain client** | `createMultichainClient` from `@metamask/connect-multichain` supports CAIP-25 scopes across EVM and Solana |
310320
| **`invokeMethod`** | Call RPC methods on specific CAIP-2 scopes without switching chains |
311-
| **Solana support** | `createSolanaClient` from `@metamask/connect-solana` with wallet-standard adapter |
321+
| **Solana support** | `createSolanaClient` from `@metamask/connect-solana` with Wallet Standard adapter |
312322
| **`connectAndSign`** | Connect and sign a message in a single user approval |
313323
| **`connectWith`** | Connect and execute any RPC method in a single user approval |
314324
| **Partial disconnect** | `disconnect(scopes)` revokes specific CAIP scopes while keeping others active |
@@ -325,7 +335,7 @@ straightforward:
325335
import { createMultichainClient } from '@metamask/connect-multichain'
326336

327337
const multichainClient = await createMultichainClient({
328-
dapp: { name: 'My DApp', url: window.location.href },
338+
dapp: { name: 'My Dapp', url: window.location.href },
329339
api: {
330340
supportedNetworks: {
331341
'eip155:1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
@@ -392,7 +402,7 @@ export function EVMProvider({ children }: { children: React.ReactNode }) {
392402
if (initialized.current) return
393403
initialized.current = true
394404
createEVMClient({
395-
dapp: { name: 'My DApp', url: window.location.href },
405+
dapp: { name: 'My Dapp', url: window.location.href },
396406
api: { supportedNetworks: getInfuraRpcUrls({ infuraApiKey: 'YOUR_INFURA_API_KEY' }) },
397407
}).then(setClient)
398408
}, [])

metamask-connect/evm/guides/sign-data/index.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ import { createWalletClient, custom } from 'viem'
195195
import { mainnet } from 'viem/chains'
196196

197197
const evmClient = await createEVMClient({
198-
dapp: { name: 'My DApp', url: window.location.href },
198+
dapp: { name: 'My Dapp', url: window.location.href },
199199
api: {
200200
supportedNetworks: {
201201
'0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
@@ -284,7 +284,7 @@ import { ethers } from 'ethers'
284284
import { BrowserProvider, parseUnits } from 'ethers'
285285

286286
const evmClient = await createEVMClient({
287-
dapp: { name: 'My DApp', url: window.location.href },
287+
dapp: { name: 'My Dapp', url: window.location.href },
288288
api: {
289289
supportedNetworks: {
290290
'0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
@@ -377,7 +377,7 @@ import { createEVMClient } from '@metamask/connect-evm'
377377
import { Web3 } from 'web3'
378378

379379
const evmClient = await createEVMClient({
380-
dapp: { name: 'My DApp', url: window.location.href },
380+
dapp: { name: 'My Dapp', url: window.location.href },
381381
api: {
382382
supportedNetworks: {
383383
'0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
@@ -545,7 +545,7 @@ import { createWalletClient, custom } from 'viem'
545545
import { mainnet } from 'viem/chains'
546546

547547
const evmClient = await createEVMClient({
548-
dapp: { name: 'My DApp', url: window.location.href },
548+
dapp: { name: 'My Dapp', url: window.location.href },
549549
api: {
550550
supportedNetworks: {
551551
'0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
@@ -574,7 +574,7 @@ import { createEVMClient } from '@metamask/connect-evm'
574574
import { ethers } from 'ethers'
575575

576576
const evmClient = await createEVMClient({
577-
dapp: { name: 'My DApp', url: window.location.href },
577+
dapp: { name: 'My Dapp', url: window.location.href },
578578
api: {
579579
supportedNetworks: {
580580
'0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
@@ -599,7 +599,7 @@ import { createEVMClient } from '@metamask/connect-evm'
599599
import { Web3 } from 'web3'
600600

601601
const evmClient = await createEVMClient({
602-
dapp: { name: 'My DApp', url: window.location.href },
602+
dapp: { name: 'My Dapp', url: window.location.href },
603603
api: {
604604
supportedNetworks: {
605605
'0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',

metamask-connect/evm/quickstart/javascript.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ const evmClient = await createEVMClient({
154154
These examples configure MetaMask Connect EVM with the following options:
155155

156156
- `dapp` - Ensures trust by showing your dapp's `name`, `url`, and `iconUrl` during connection.
157+
Use `base64Icon` instead of `iconUrl` when a hosted URL is unavailable (for example, in React
158+
Native).
157159
- `api.supportedNetworks` - A map of hex chain IDs to RPC URLs for all networks supported by the app.
158160
Use the [`getInfuraRpcUrls`](../reference/methods.md#getinfurarpcurls) helper to generate URLs for all Infura-supported chains, or specify your own.
159161

metamask-connect/evm/quickstart/react-native.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ function getClient() {
256256
if (!clientPromise) {
257257
clientPromise = createEVMClient({
258258
dapp: {
259-
name: 'My RN DApp',
259+
name: 'My RN Dapp',
260260
url: 'https://mydapp.com',
261261
},
262262
api: {

metamask-connect/evm/reference/methods.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ eventHandlers: {
8787

8888
```javascript
8989
const signature = await evmClient.connectAndSign({
90-
message: 'Sign in to My DApp',
90+
message: 'Sign in to My Dapp',
9191
chainIds: ['0x1'],
9292
})
9393
console.log('Signature:', signature)
@@ -264,7 +264,7 @@ A `Record<string, string>` mapping hex chain IDs to Infura RPC URLs. When `chain
264264
import { createEVMClient, getInfuraRpcUrls } from '@metamask/connect-evm'
265265

266266
const evmClient = await createEVMClient({
267-
dapp: { name: 'My DApp', url: window.location.href },
267+
dapp: { name: 'My Dapp', url: window.location.href },
268268
api: {
269269
supportedNetworks: {
270270
// Each chain must be active in your Infura dashboard
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
---
2+
title: 'Use Headless Mode - MetaMask Connect Multichain'
3+
sidebar_label: Use headless mode
4+
description: Render a custom QR code or connection UI by using headless mode with MetaMask Connect Multichain.
5+
keywords:
6+
[
7+
headless,
8+
QR code,
9+
custom UI,
10+
display_uri,
11+
multichain,
12+
MetaMask,
13+
Connect,
14+
connection,
15+
modal,
16+
deeplink,
17+
]
18+
---
19+
20+
# Use headless mode
21+
22+
By default, MetaMask Connect renders its own QR code modal when connecting to MetaMask Mobile
23+
via MetaMask Wallet Protocol (MWP).
24+
Headless mode suppresses this built-in modal so you can render your own connection UI.
25+
26+
Use headless mode when you want to:
27+
28+
- Display a custom-styled QR code that matches your dapp's design.
29+
- Show the connection URI in a different format (for example, a deeplink button instead of a QR code).
30+
- Integrate the connection flow into an existing modal or onboarding wizard.
31+
32+
## Set up headless mode
33+
34+
### 1. Configure the client with headless mode
35+
36+
Initialize a MetaMask Connect Multichain client, and set `ui.headless` to `true` in the configuration options:
37+
38+
```javascript
39+
import { createMultichainClient, getInfuraRpcUrls } from '@metamask/connect-multichain'
40+
41+
const client = await createMultichainClient({
42+
dapp: {
43+
name: 'My Dapp',
44+
url: window.location.href,
45+
},
46+
api: {
47+
supportedNetworks: {
48+
...getInfuraRpcUrls({ infuraApiKey: '<YOUR_INFURA_API_KEY>' }),
49+
},
50+
},
51+
ui: { headless: true },
52+
})
53+
```
54+
55+
### 2. Register a `display_uri` listener before connecting
56+
57+
The `display_uri` event fires during the connecting phase with a one-time-use pairing URI.
58+
You **must** register the listener before calling `connect`, or you may miss the event:
59+
60+
```javascript
61+
client.on('display_uri', uri => {
62+
showCustomQrModal(uri)
63+
})
64+
```
65+
66+
### 3. Connect and handle the result
67+
68+
```javascript
69+
try {
70+
await client.connect(['eip155:1', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'], [])
71+
hideCustomQrModal()
72+
} catch (err) {
73+
hideCustomQrModal()
74+
if (err.code === 4001) {
75+
// User rejected — show retry UI
76+
} else {
77+
console.error('Connection failed:', err)
78+
}
79+
}
80+
```
81+
82+
## Important considerations
83+
84+
### URI is one-time-use
85+
86+
The pairing URI delivered by `display_uri` is a one-time-use token.
87+
Once used or expired, it cannot be reused.
88+
If the connection fails, call `connect` again to generate a fresh URI.
89+
90+
### `display_uri` only fires during connecting
91+
92+
The event fires only while the client status is `'connecting'`.
93+
After the connection resolves (success or error), `display_uri` stops firing.
94+
95+
### Extension connections skip QR
96+
97+
When the MetaMask browser extension is installed and `ui.preferExtension` is `true` (the default),
98+
the SDK connects directly through the extension.
99+
No `display_uri` event fires because no QR code is needed.
100+
101+
To display the QR connection option even when the extension is available, set `ui.preferExtension` to `false`:
102+
103+
```javascript
104+
const client = await createMultichainClient({
105+
dapp: { name: 'My Dapp', url: window.location.href },
106+
ui: {
107+
headless: true,
108+
preferExtension: false,
109+
},
110+
})
111+
```
112+
113+
### Monitor connection status
114+
115+
Use the [`stateChanged`](../reference/methods.md#events) event to track the connection lifecycle and update your UI accordingly:
116+
117+
```javascript
118+
client.on('stateChanged', status => {
119+
// status: 'loaded' | 'pending' | 'connecting' | 'connected' | 'disconnected'
120+
switch (status) {
121+
case 'connecting':
122+
showLoadingIndicator()
123+
break
124+
case 'connected':
125+
hideCustomQrModal()
126+
showConnectedUI()
127+
break
128+
case 'disconnected':
129+
showDisconnectedUI()
130+
break
131+
}
132+
})
133+
```
134+
135+
## Next steps
136+
137+
- [Send transactions on EVM and Solana](send-transactions.md) using `invokeMethod`.
138+
- [Sign messages on EVM and Solana](sign-transactions.md) using `invokeMethod`.
139+
- See the [Multichain methods reference](../reference/methods.md) for the full API.

metamask-connect/multichain/guides/sign-transactions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ const typedData = {
100100
},
101101
primaryType: 'Mail',
102102
domain: {
103-
name: 'My DApp',
103+
name: 'My Dapp',
104104
version: '1',
105105
chainId: 1,
106106
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',

metamask-connect/multichain/quickstart/javascript.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ const client = await createMultichainClient({
124124
dapp: {
125125
name: 'My Multichain Dapp',
126126
url: window.location.href,
127-
iconUrl: 'https://mydapp.com/icon.png',
127+
iconUrl: 'https://mydapp.com/icon.png', // Or use base64Icon for embedded icons (e.g., React Native)
128128
},
129129
api: {
130130
supportedNetworks: {

metamask-connect/multichain/quickstart/react-native.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ function getClient() {
265265
if (!clientPromise) {
266266
clientPromise = createMultichainClient({
267267
dapp: {
268-
name: 'My Multichain RN DApp',
268+
name: 'My Multichain RN Dapp',
269269
url: 'https://mydapp.com',
270270
},
271271
api: {

0 commit comments

Comments
 (0)