Privy supports connecting external wallet on both EVM networks (e.g. MetaMask, Rainbow) and Solana (e.g. Phantom, Solflare) to your application to request signatures and transactions.
Configuring connectors
To connect external wallets on EVM networks, there is no additional configuration required for your app. Simply continue with the instructions below to prompt connections to external EVM wallets, like MetaMask or Coinbase Wallet.
To connect external wallets on Solana, your application must first explicitly configure Solana connectors for Privy. To do so:
- Import and configure the
toSolanaWalletConnectors function from @privy-io/react-auth/solana
- Enable
'solana-only' or 'ethereum-and-solana' as the config.appearance.walletChainType prop of your PrivyProvider
You do not need to configure config.solana.rpcs for external wallets. RPC clients under
solana.rpcs are only required when using Privy’s embedded wallet UIs (UI signTransaction and
signAndSendTransaction).
As an example, you might set up your PrivyProvider like so:import {toSolanaWalletConnectors} from '@privy-io/react-auth/solana';
import {createSolanaRpc, createSolanaRpcSubscriptions} from '@solana/kit';
const solanaConnectors = toSolanaWalletConnectors({
// By default, shouldAutoConnect is enabled
shouldAutoConnect: true
});
const Provider: React.FC<PropsWithChildren> = ({children}) => {
return (
<PrivyProvider
config={{
solana: {
rpcs: {
// Only needed if you need to use Privy wallets for sending transactions
'solana:mainnet': {
rpc: createSolanaRpc('https://api.mainnet-beta.solana.com'), // or your custom RPC endpoint
rpcSubscriptions: createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com') // or your custom RPC endpoint
}
}
},
appearance: {
// Use 'solana-only' or 'ethereum-and-solana'
walletChainType: 'solana-only'
},
externalWallets: {
solana: {
connectors: solanaConnectors
}
}
}}
>
{children}
</PrivyProvider>
);
};
Note that some Solana wallet connectors do not gracefully support autoConnect, which will result in an extension pop-up on page load. If you would like to disable this feature, set it to false in the toSolanaWalletConnectors function.
Connecting the wallet
To prompt a user to connect an external wallet (on EVM networks or Solana) to your app, use Privy’s connectWallet method:
import {usePrivy} from '@privy-io/react-auth';
const {connectWallet} = usePrivy();
This method will prompt the user to select the wallet they want to connect, and will show users EVM and/or Solana external wallet options based off of the config.appearance.walletChainType configured in your app’s PrivyProvider. You can prompt users to connect as many wallets as you’d like to your app.
For example, you might have a “Connect” button in your app that prompts users to connect their wallet, like so:
import {usePrivy} from '@privy-io/react-auth';
export default function ConnectWalletButton() {
const {connectWallet} = usePrivy();
// Prompt user to connect a wallet with Privy modal
return <button onClick={connectWallet}>Connect wallet</button>;
}
As an optional parameter to connectWallet, you may pass an object with the following optional fields:
| Field | Type | Description |
|---|
description | string | A description for the wallet connection prompt, which will be displayed in Privy’s UI. |
walletList | WalletListEntry[] | A list of wallet optionsthat you would like Privy to display in the connection prompt. |
connectWallet({
description: 'Connect your wallet to access the app',
walletList: ['metamask', 'safe']
});
connectWallet({
description: 'Connect your wallet to access the app',
walletList: ['phantom', 'solflare']
});
Once a user has connected their external wallet to your app, the wallet will appear in either of Privy’s useWallets arrays, which you can then use to request signatures and transactions from the connected wallet.
Connecting or creating a wallet
You can also use Privy to connect a user’s external wallet if they have one, or to create an embedded wallet for them if they do not. To do so, use the connectOrCreateWallet method of the usePrivy hook:
const {connectOrCreateWallet} = usePrivy();
This method will prompt the user to connect an external wallet, or log in with email, SMS, or socials, depending on your configured loginMethods, to create an embedded wallet.
Privy’s connectOrCreate interface currently only supports external and embedded wallets on EVM
networks.
For example, you might have a “Connect” button in your app that prompts users to connect their wallet, like so:
import {usePrivy} from '@privy-io/react-auth';
export default function ConnectWalletButton() {
const {connectOrCreateWallet} = usePrivy();
// Prompt user to connect a wallet with Privy modal
return <button onClick={connectOrCreateWallet}>Connect wallet</button>;
}
This method functions exactly the same as Privy’s login method, except when users connect their
external wallet, they will not automatically be prompted to authenticate that wallet by signing a
message
Authenticating a connected wallet
Once a user has connected their wallet to your app, and the wallet is available in either of the useWallets arrays, you can also prompt them to login with that wallet or link that wallet to their existing account, instead of prompting the entire login or linkWallet flow.
To do so, find the ConnectedWallet or ConnectedStandardSolanaWallet object from Privy, and call the object’s loginOrLink method for EVM wallets and use the useLoginWithSiws or useLinkWithSiws hooks for the Solana wallets:
import {useWallets} from '@privy-io/react-auth';
const {wallets} = useWallets();
wallets[0].loginOrLink();
import {useWallets} from '@privy-io/react-auth/solana';
const {wallets} = useWallets();
const {generateSiwsMessage, loginWithSiws} = useLoginWithSiws();
const message = await generateSiwsMessage({address: wallets[0].address});
const encodedMessage = new TextEncoder().encode(message);
const results = await wallets[0].signMessage({message: encodedMessage});
const signatureBase64 = Buffer.from(results.signature).toString('base64');
await loginWithSiws({message, signature: signatureBase64});
When called, loginOrLink will directly request a SIWE signature from the user’s connected wallet to authenticate the wallet.
If the user was not authenticated when the method was called, the user will become authenticated after signing the message.
If the user was already authenticated when the method was called, the user will remain authenticated after signing the message, and the connected wallet will become one of the user’s linkedAccounts in their user object.
You might use the methods above to “split up” the connect and sign steps of external wallet login, like so:
import {useConnectWallet, useWallets} from '@privy-io/react-auth';
export default function WalletButton() {
const {connectWallet} = useConnectWallet();
const {wallets} = useWallets();
// Prompt user to connect a wallet with Privy modal
return (
<>
{/* Button to connect wallet */}
<button onClick={connectWallet}>
Connect wallet
</button>
{/* Button to login with or link the most recently connected wallet */}
<button
disabled={!wallets[0]}
onClick={() => { wallets[0].loginOrLink() }}
>
Login with wallet
</button>
</>
);
}
import {useConnectWallet, useLoginWithSiws} from '@privy-io/react-auth';
import {useWallets} from '@privy-io/react-auth/solana';
export default function WalletButton() {
const {connectWallet} = useConnectWallet();
const {wallets} = useWallets();
const {generateSiwsMessage, loginWithSiws} = useLoginWithSiws()
// Prompt user to connect a wallet with Privy modal
return (
{/* Button to connect wallet */}
<button onClick={connectWallet}>
Connect wallet
</button>
{/* Button to login with or link the most recently connected wallet */}
<button
disabled={!wallets[0]}
onClick={async () => {
const message = await generateSiwsMessage({address: wallets[0].address})
const encodedMessage = new TextEncoder().encode(message)
const results = await wallets[0].signMessage({message: encodedMessage})
const signatureBase64 = Buffer.from(results.signature).toString('base64');
await loginWithSiws({message, signature: signatureBase64})
}}
>
Login with wallet
</button>
);
}