This guide will help you migrate your Privy React SDK from v2.x.x to v3.0.0. To install the latest version:
npm i @privy-io/react-auth@3

New features and improvements 🎉

  • Simplified Solana integration with one wallet per account and direct method access
  • Streamlined peer dependencies required for Solana
  • Removal of deprecated fields and methods
For the full set of changes check out our changelog.

Solana Updates

Update Peer Dependencies

If your app uses Privy’s Solana wallets, the required peer dependencies have changed in v3.0: Remove these peer dependencies:
  • @solana/web3.js
  • @solana/spl-token
Install these new peer dependencies:
  • @solana/kit
  • @solana-program/memo
  • @solana-program/system
  • @solana-program/token

Solana RPC configuration

  • For Privy embedded wallet flows only (UI signTransaction and signAndSendTransaction), set RPCs in config.solana.rpcs. This replaces solanaClusters.
import {createSolanaRpc, createSolanaRpcSubscriptions} from '@solana/kit'; 

<PrivyProvider
  appId="your-privy-app-id"
  config={{
    ...theRestOfYourConfig,
    solanaClusters: [{name: 'mainnet-beta', rpcUrl: 'https://api.mainnet-beta.solana.com'}] 
    solana: {  
      rpcs: { 
        'solana:mainnet': { 
          rpc: createSolanaRpc('https://api.mainnet-beta.solana.com'), 
          rpcSubscriptions: createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com') 
        }, 
      }
    }
  }}
>
  {/* your app's content */}
</PrivyProvider>;

Replace useSolanaWallets

  • Replace useSolanaWallets with useWallets, useCreateWallet, and useExportWallet from the Solana entrypoint. The new useWallets hook returns ConnectedStandardSolanaWallet[].
import {useSolanaWallets} from '@privy-io/react-auth/solana'; 
import {useWallets, useCreateWallet, useExportWallet} from '@privy-io/react-auth/solana'; 

const {ready, wallets, createWallet, exportWallet} = useSolanaWallets(); 
const {ready, wallets} = useWallets(); 
const {createWallet} = useCreateWallet(); 
const {exportWallet} = useExportWallet(); 
Key differences between ConnectedSolanaWallet and ConnectedStandardSolanaWallet:
  • Each wallet represents a single connected account
  • Methods are available directly on the wallet instance:
    • wallet.signMessage({message})
    • wallet.signTransaction({transaction, chain})
    • wallet.signAndSendTransaction({transaction, chain})
    • wallet.signAndSendAllTransaction({transaction, chain}[])
    • wallet.disconnect()
  • The Solana standard wallet is available at wallet.standardWallet (for icon/name/etc.)
  • Removed wallet.loginOrLink() method - Use useLoginWithSiws and useLinkWithSiws instead:
import {useLoginWithSiws, useLinkWithSiws} from '@privy-io/react-auth'; 

const {generateSiwsMessage, loginWithSiws} = useLoginWithSiws(); 
const {generateSiwsMessage, linkWithSiws} = useLinkWithSiws(); 

// Login flow
await wallets[0].loginOrLink(); 
const message = await generateSiwsMessage({address: wallets[0].address}); 
const encodedMessage = new TextEncoder().encode(message); 
const results = await wallets[0].signMessage({message: encodedMessage}); 
await loginWithSiws({message: encodedMessage, signature: results.signature}); 

// Link flow (similar pattern with linkWithSiws)
const results = await wallets[0].signMessage({message: encodedMessage}); 
await linkWithSiws({message: encodedMessage, signature: results.signature}); 

Rename useSendTransaction

  • Update useSendTransaction from @privy-io/react-auth/solana to useSignAndSendTransaction from @privy-io/react-auth/solana
import {useSendTransaction} from '@privy-io/react-auth/solana'; 
import {useSignAndSendTransaction} from '@privy-io/react-auth/solana'; 

...

const {sendTransaction} = useSendTransaction(); 
const {signAndSendTransaction} = useSignAndSendTransaction(); 

Usage Examples

  • All Solana RPCs now expect buffer inputs.

New solana wallet usage

import {useWallets, type ConnectedStandardSolanaWallet} from '@privy-io/react-auth/solana';
import {TextEncoder} from '@solana/kit';

export function SolanaWallets() {
  const {ready, wallets} = useWallets();
  if (!ready) return <p>Loading...</p>;

  return (
    <div>
      {wallets.map((wallet: ConnectedStandardSolanaWallet) => (
        <div key={wallet.address}>
          <img src={wallet.standardWallet.icon} width={16} height={16} />
          <span>{wallet.standardWallet.name}</span>
          <code>{wallet.address}</code>
          <button
            onClick={async () => {
              const message = new TextEncoder().encode('Hello, world!');
              const {signature} = await wallet.signMessage({message});
              console.log('signature', signature);
            }}
          >
            Sign message
          </button>
        </div>
      ))}
    </div>
  );
}

Sign and send via hooks (with optional UI configuration)

import {
  useWallets,
  useSignMessage,
  useSignTransaction,
  useSignAndSendTransaction
} from '@privy-io/react-auth/solana';

export function Actions() {
  const {wallets} = useWallets();
  const {signMessage} = useSignMessage();
  const {signTransaction} = useSignTransaction();
  const {signAndSendTransaction} = useSignAndSendTransaction();

  const wallet = wallets[0];
  if (!wallet) return null;

  return (
    <div>
      <button
        onClick={async () => {
          const message = new TextEncoder().encode('Hello from Privy');
          const {signature} = await signMessage({
            wallet,
            message,
            options: {uiOptions: {showWalletUIs: true}}
          });
          console.log(signature);
        }}
      >
        Sign message (hook)
      </button>

      <button
        onClick={async () => {
          // Create an encoded transaction using @solana/kit or @web3.js
          const transaction = tx; // type Uint8Array
          const {signedTransaction} = await signTransaction({
            wallet,
            transaction,
            chain: 'solana:devnet'
          });
          console.log(signedTransaction);
        }}
      >
        Sign transaction (hook)
      </button>

      <button
        onClick={async () => {
          // Create an encoded transaction using @solana/kit or @web3.js
          const transaction = tx; // type Uint8Array
          const {signature} = await signAndSendTransaction({
            wallet,
            transaction,
            chain: 'solana:devnet'
          });
          console.log(signature);
        }}
      >
        Sign & send (hook)
      </button>
    </div>
  );
}

Other interface changes

Funding

  • Updated fundWallet interface
import {useFundWallet: useFundSolanaWallet} from '@privy-io/react-auth/solana';
import {useFundWallet: useFundEthereumWallet} from '@privy-io/react-auth';

...

const {fundWallet} = useFundSolanaWallet();
await fundWallet('<solana address>', {amount: '1', asset: 'native-currency', chain: 'solana:devnet'}); 
await fundWallet({ 
  address: '<solana address>', 
  options: {amount: '1', asset: 'SOL', chain: 'solana:devnet'} 
}); 

const {fundWallet} = useFundEthereumWallet();
await fundWallet('<ethereum address>', {amount: '1000', asset: 'native-currency', chain: {id: 1}}); 
await fundWallet({ 
  address: '<ethereum address>', 
  options: {amount: '1000', asset: 'native-currency', chain: {id: 1}} 
}); 

Removed/Deprecated Items

  • Removed suggestedAddress from connectWallet and linkWallet
connectWallet({suggestedAddress: '0x123...'}); 
connectWallet({description: `Connect the wallet with address ${address}`}); 
  • Removed detected_wallets from wallet lists/configuration
<PrivyProvider
  config={{
    walletList: [
      'detected_wallets', 
      'detected_ethereum_wallets', 
      'detected_solana_wallets', 
      'metamask'
      // ...
    ]
    // ...
  }}
>
  {/* your app's content */}
</PrivyProvider>
  • Removed deprecated Moonpay config and types, add config to PrivyProviderConfig instead
fundEvmWallet(address, {
  config: {
    currencyCode: 'ETH_ETHEREUM', 
    quoteCurrencyAmount: 0.01
  }, 
  provider: 'moonpay'
});

<PrivyProvider
  config={{
    fundingMethodConfig: {moonpay: {useSandbox: true}} 
    // ...
  }}
>
  ...
</PrivyProvider>;

fundEvmWallet(address, {
  chain: mainnet, 
  amount: '0.01', 
  defaultFundingMethod: 'card'
});
  • Removed deprecated requireUserPasswordOnCreate and related embedded wallet config fields
  • **Removed embeddedWallets level createOnLogin field. Use embeddedWallets.etherum.createOnLogin or embeddedWallets.solana.createOnLogin instead. **
<PrivyProvider
  config={{
    embeddedWallets: {
      requireUserPasswordOnCreate: true, 
      createOnLogin: 'all-users', 
      ethereum: {createOnLogin: 'all-users'} 
      // ...
    }
    // ...
  }}
>
  {/* your app's content */}
</PrivyProvider>
  • Removed useLoginToFrame and replaced with useLoginToMiniApp
export {useLoginToFrame} from '@privy-io/react-auth'; 
export {useLoginToMiniApp} from '@privy-io/react-auth'; 
  • Removed useSignAuthorization() - Use useSign7702Authorization() instead
import {useSignAuthorization} from '@privy-io/react-auth'; 
import {useSign7702Authorization} from '@privy-io/react-auth'; 

const {signAuthorization} = useSignAuthorization(); 
const {sign7702Authorization} = useSign7702Authorization(); 
  • Removed useSetWalletPassword() - Use useSetWalletRecovery instead
import {useSetWalletPassword} from '@privy-io/react-auth'; 
import {useSetWalletRecovery} from '@privy-io/react-auth'; 

const {setWalletPassword} = useSetWalletPassword(); 
const {setWalletRecovery} = useSetWalletRecovery(); 

Updated Types

  • Removed verifiedAt from LinkMetadata and all linked accounts. Use firstVerifiedAt and latestVerifiedAt instead of the deprecated verifiedAt.
const verifiedDate = user.wallet.verifiedAt; 
const verifiedDate = user.wallet.firstVerifiedA;