Skip to main content
Privy enables complete control over user management flows, so you can match every user action to your app’s brand and experience. Build your own UI for linking and unlinking accounts, managing user profiles, and more, while Privy handles the backend logic securely.
Privy supports whitelabeling user management for linking and unlinking accounts.
To whitelabel linking social accounts, use the useLinkAccount hook and call link<Provider>.
import {useLinkAccount} from '@privy-io/react-auth';
const {linkGoogle, linkTwitter} = useLinkAccount();
linkGoogle();
linkTwitter();
To whitelabel linking wallets, use the useLinkWithSiwe hook for Ethereum wallets or useLinkWithSiws hook for Solana wallets. These hooks allow you to generate messages, request signatures, and link wallets without using Privy’s modal UI.
To link an Ethereum wallet to a user via SIWE, use the React SDK’s useLinkWithSiwe hook.

Generate SIWE message

generateSiweMessage({ address: string, chainId: string }) => Promise<string>

Sign the SIWE message

Request an EIP-191 personal_sign signature for the message returned by generateSiweMessage from the wallet.
import {useWallets} from '@privy-io/react-auth';

const {wallets} = useWallets();
const signature = await wallets[0].sign(message);
Alternatively, you can request a signature from any external wallet or smart account:
const signature = await wallet.signMessage({message});
linkWithSiwe({
  signature: string,
  message: string,
  chainId: string,
  walletClientType?: string,
  connectorType?: string
}) => Promise<void>

Usage

import {useLinkWithSiwe, useWallets} from '@privy-io/react-auth';

export function LinkWalletButton() {
  const {generateSiweMessage, linkWithSiwe} = useLinkWithSiwe();
  const {wallets} = useWallets();

  const handleLink = async () => {
    if (!wallets?.length) return;
    const activeWallet = wallets[0];

    const message = await generateSiweMessage({
      address: activeWallet.address,
      chainId: 'eip155:1'
    });

    const signature = await activeWallet.sign(message);
    await linkWithSiwe({
      message,
      chainId: 'eip155:1',
      signature
    });
  };

  return <button onClick={handleLink}>Link wallet</button>;
}

Callbacks

You can optionally pass callbacks into useLinkWithSiwe:
const {generateSiweMessage, linkWithSiwe} = useLinkWithSiwe({
  onSuccess: ({user, linkMethod, linkedAccount}) => {
    console.log('Wallet linked successfully', linkedAccount);
  },
  onError: (error) => {
    console.error('Failed to link wallet', error);
  }
});
To whitelabel updating a user’s email address, use the useUpdateEmail hook:
import {useUpdateEmail} from '@privy-io/react-auth';

const {state, sendCode, verifyCode} = useUpdateEmail();

Send an OTP

First, use the sendCode method to send an OTP verification code to the user’s new email address:
sendCode: ({newEmailAddress: string}) => Promise<void>;
This sends a one-time passcode to the new email address, which the user must enter to verify and confirm the update.

Verify the OTP

Prompt the user for the OTP they received and verify it using the verifyCode method:
verifyCode: ({code: string}) => Promise<{user: User} | undefined>;

State

The state property provides the current state of the OTP flow:
StatusDescription
'initial'The flow has not started
'sending-code'The code is being sent
'awaiting-code-input'Waiting for the user to enter the code
'submitting-code'The code is being verified
'done'The email was updated successfully
'error'An error occurred (includes an error field)

Usage

import {useState} from 'react';
import {useUpdateEmail} from '@privy-io/react-auth';

function UpdateEmailForm() {
  const {state, sendCode, verifyCode} = useUpdateEmail();
  const [newEmailAddress, setNewEmailAddress] = useState('');
  const [code, setCode] = useState('');

  if (state.status === 'initial' || state.status === 'sending-code') {
    return (
      <div>
        <input
          type="email"
          value={newEmailAddress}
          onChange={(e) => setNewEmailAddress(e.target.value)}
          placeholder="New email address"
        />
        <button
          onClick={() => sendCode({newEmailAddress})}
          disabled={state.status === 'sending-code'}
        >
          Send code
        </button>
      </div>
    );
  }

  return (
    <div>
      <input
        value={code}
        onChange={(e) => setCode(e.target.value)}
        placeholder="Enter verification code"
      />
      <button onClick={() => verifyCode({code})} disabled={state.status === 'submitting-code'}>
        Verify
      </button>
    </div>
  );
}

Callbacks

You can optionally pass callbacks into useUpdateEmail:
const {state, sendCode, verifyCode} = useUpdateEmail({
  onSuccess: ({user, updateMethod, updatedAccount}) => {
    console.log('Email updated successfully', user);
  },
  onError: (error, details) => {
    console.error('Failed to update email', error, details);
  }
});
To whitelabel unlinking an account, use the usePrivy hook and call unlink<Provider>.
import {usePrivy} from '@privy-io/react-auth';
const {unlinkEmail, unlinkGoogle, unlinkWallet} = usePrivy();
unlinkEmail();
unlinkGoogle();
unlinkWallet();