Skip to main content



This guide is adopted from Privy's ZeroDev guide.

Privy is in closed beta, but you can email to gain priority access to Privy.

Privy is a leading Web3 onboarding solution that powers the likes of, Blackbird, and Courtyard. It supports:

  • Connecting to DApps with both Web3 wallets and social accounts.
  • Fine-grained control over your wallet connection flow.
  • Creating a common user object for your app to easily manage identities and analytics.
  • Creating embedded wallets for users who don't have their own wallets.

You can easily integrate ZeroDev alongside Privy to create smart wallets from your user's embedded or external wallets, allowing you to enhance your app with gas sponsorship, batched transactions, and more!

Read below to learn how to configure your app to create smart wallets for all your users!


Want to see an end-to-end integration of Privy with ZeroDev? Check out our example app!

What is an EOA?

An EOA, or externally-owned account, is any Ethereum account that is controlled by a private key. Privy's embedded wallets and most external wallets (MetaMask, Coinbase Wallet, Rainbow Wallet, etc.) are EOAs.

EOAs differ from contract accounts, which are instead controlled by smart contract code and do not have their own private key. ZeroDev's smart wallet is a contract account. Contract accounts have enhanced capabilites, such as gas sponsorship and batched transactions.

Since they do not have their own private key, contract accounts cannot directly produce signatures and initiate transaction flows. Instead, each contract account is generally "managed" by an EOA, which authorizes actions taken by the contract account via a signature; this EOA is called a signer.

In this integration, the user's EOA (from Privy) serves as the signer for their smart wallet (from ZeroDev). The smart wallet (ZeroDev) holds all assets and submits all transactions to the network, but the signer (Privy) is responsible for producing signatures and "kicking off" transaction flows.

1. Install Privy and ZeroDev

In your app's repository, install the @privy-io/react-auth and @zerodev/privy SDKs:

npm i @privy-io/react-auth @zerodev/privy

2. Configure your app's PrivyProvider

First, follow the instructions in the Privy Quickstart to get your app set up with Privy.

Then, update the config.embeddedWallets property of your PrivyProvider to have the following values:

  • createOnLogin: 'users-without-wallets'. This will configure Privy to create an embedded wallet for users logging in via a web2 method (email, phone, socials), ensuring that all of your users have a wallet that can be used as an EOA.
  • noPromptOnSignature: true. This will configure Privy to not show its default UIs when your user must sign messages or send transactions. Instead, we recommend you use your own custom UIs for showing users the UserOperations they sign.

Your PrivyProvider should then look like:

/* Replace this with your desired login methods */
loginMethods: ['email', 'wallet'],
/* Replace this with your desired appearance configuration */
appearance: {
theme: 'light',
accentColor: '#676FFF',
logo: 'your-logo-url'
embeddedWallets: {
createOnLogin: true,
noPromptOnSignature: true
{/* Your app's components */}

3. Add ZeroDev to your app

First, go to the ZeroDev dashboard, set up a new project, and retrieve your ZeroDev Project ID. You can configure your ZeroDev project per the instructions here.

Then, where you render your PrivyProvider, wrap it with a ZeroDevProvider. In the projectId property of the ZeroDevProvider, add your Project ID from the ZeroDev dashboard.

For example, in NextJS or Create React App, this might look like:

import type {AppProps} from 'next/app';
import {PrivyProvider} from '@privy-io/react-auth';
import {ZeroDevProvider} from '@zerodev/privy';

function MyApp({Component, pageProps}: AppProps) {
return (
<ZeroDevProvider projectId='insert-your-zerodev-project-id'>
config={/* insert your PrivyProvider config */}
<Component {...pageProps} />
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {PrivyProvider} from '@privy-io/react-auth';
import {ZeroDevProvider} from '@zerodev/privy';

const root = ReactDOM.createRoot(document.getElementById('root'));

<ZeroDevProvider projectId='insert-your-zerodev-project-id'>
config={/* insert your PrivyProvider config */}
<App />

4. Just usePrivySmartAccount!

With the steps above, when a user logs into your app, they will either create a Privy embedded wallet or have an external wallet (e.g. MetaMask) that can be used as an EOA. Behind-the-scenes, ZeroDev will create a smart wallet for the user, and use this EOA as the smart wallet's signer.

You can now use the ZeroDev smart wallet from within your app's components, by calling ZeroDev's usePrivySmartAccount hook:

  • Before taking any actions with the smart wallet, you should verify that the smart wallet has initialized by inspecting the boolean zeroDevReady from usePrivySmartAccount.
  • Once zeroDevReady is true, you can then call methods like sendTransaction and getEthereumProvider to use the smart wallet.
Sending a transaction with the smart wallet
import {usePrivySmartAccount} from '@zerodev/privy';

const {zeroDevReady, sendTransaction} = usePrivySmartAccount();

if (zeroDevReady) {
const transactionHash = await sendTransaction({
to: '0xYourDestinationAddress',
value: 100000
} else {
throw new Error('Smart wallet has not yet initialized. Try again once zeroDevReady is true.');

usePrivySmartAccount will expose all of the same fields and methods as usePrivy, but will override all wallet-related flows (signMessage, sendTransaction, getEthereumProvider) to use the ZeroDev smart wallet instead of the user's EOA.

That's it! You've configured your app to create smart wallets for all of your users, and can seamlessly add in AA features like gas sponsorship, batched transactions, and more. 🎉