Multi-wallet linking and switching
Multi-wallet linking and switching ships in Web SDK v11 (@web3auth/modal for JavaScript, React, and Vue).
Users can link multiple external wallets to a single Embedded Wallets account and switch between them during an active session, including across chains. Your dapp receives one canonical user object instead of treating each wallet connection as a separate user.
How it works
- The user signs in with an embedded wallet method (for example, Google or email passwordless) through the AUTH connector.
- While authenticated, the user links an external wallet (for example, MetaMask or WalletConnect) to the same account.
- The linked wallet appears in
userInfo.linkedAccounts. - The user switches the active wallet with
switchAccount()or theuseWalletshook. - The SDK updates
connection.ethereumProviderorconnection.solanaWalletand emits aconnection_updatedevent so Wagmi and your UI resync.
Account linking requires an AUTH primary session. You cannot link wallets when the user's only sign-in method is an external wallet connection.
Linked account fields
Each entry in userInfo.linkedAccounts is a LinkedAccountInfo object:
| Field | Description |
|---|---|
id | Linked account identifier |
isPrimary | Whether this is the user's primary account |
eoaAddress | Externally owned account (EOA) address |
aaAddress | Smart account address, if configured |
aaProvider | Smart account provider name |
connector | Connector that owns this account |
active | Whether this account is currently active |
Link a wallet
Call linkAccount() after the user is connected through the AUTH connector:
import { useWeb3Auth } from '@web3auth/modal/react'
import { WALLET_CONNECTORS } from '@web3auth/modal'
function LinkWalletButton() {
const { web3Auth } = useWeb3Auth()
const handleLink = async () => {
if (!web3Auth) return
const result = await web3Auth.linkAccount({
connector: WALLET_CONNECTORS.METAMASK,
})
console.log('Linked address:', result.address)
}
return <button onClick={handleLink}>Link MetaMask</button>
}
Confirm the exact linkAccount parameter shape and return type for your SDK version in the
@web3auth/modal release notes.
Account linking may require accountLinking.serverUrl in Web3AuthOptions.
Switch the active wallet
Use switchAccount() with a LinkedAccountInfo entry from userInfo.linkedAccounts:
import { useWeb3Auth, useWeb3AuthUser } from '@web3auth/modal/react'
function WalletSwitcher() {
const { web3Auth } = useWeb3Auth()
const { userInfo } = useWeb3AuthUser()
const handleSwitch = async (accountId: string) => {
if (!web3Auth || !userInfo?.linkedAccounts) return
const account = userInfo.linkedAccounts.find(a => a.id === accountId)
if (!account) return
await web3Auth.switchAccount(account)
}
return (
<ul>
{userInfo?.linkedAccounts?.map(account => (
<li key={account.id}>
{account.eoaAddress}
{account.active ? ' (active)' : ''}
{!account.active && <button onClick={() => handleSwitch(account.id)}>Switch</button>}
</li>
))}
</ul>
)
}
React and Vue hooks
The Web SDK exports a useWallets hook (React) and composable (Vue) for wallet linking and switching.
Import from @web3auth/modal/react or @web3auth/modal/vue.
Add a dedicated hook reference page once the useWallets API surface is finalized in the SDK docs.
Unlink a wallet
Remove a linked wallet with unlinkAccount():
await web3Auth.unlinkAccount('<LINKED_EOA_ADDRESS>')
Why this matters for dapps
- Analytics: One user ID maps to every wallet the user owns, not one ID per connection.
- CRM: Store a single profile with multiple wallet addresses attached.
- UX: Users can bring a hot wallet, hardware wallet, and side-project wallet under one login without signing out.
Next steps
- External wallet aggregator: wallet discovery and connect-and-sign flow
- Session management: how sessions persist across reloads
- User details in ID token: configure identity token claims