Skip to main content
Use Privy when you want Pods widgets to feel like a Web2 product while still keeping wallet custody and transaction execution in your host app.

Resources

Verified integration contract

Install the current verified package set:
Do not install @privy-io/react-auth/smart-wallets as a separate dependency. Import it from the @privy-io/react-auth package subpath.

Environment variables

Styles

Import the widget stylesheet before your host CSS. For Next.js App Router:
For Vite React:
For Vite hosts, keep the same names by enabling:
For non-Next hosts, add the shim used by that alias:

Provider setup

Host integration pattern

Inside your widget host component:
  • Use usePrivy, useWallets, useCreateWallet, getEmbeddedConnectedWallet, and useSmartWallets.
  • Reuse the current embedded wallet when it already exists.
  • If the user is authenticated but still has no smart wallet, show a “Create smart wallet” action before mounting the widget.
  • Keep Privy supportedChains in sync with every EVM chain that Pods bytecode can target; sendTransaction, switchChain, and getClientForChain({ id }) fail when the target chain is not supported.
  • Pass the smart-wallet address into DeframeProvider.config.walletAddress.
  • Use the branded NEXT_PUBLIC_PODS_API_URL, NEXT_PUBLIC_PODS_API_KEY, and NEXT_PUBLIC_PODS_WEBSOCKET_URL env names.
  • Map those env values into the current DeframeProvider API config fields.
  • Set enableCrossChainInvestments: true.

Complete EarnWidgetHost reference implementation

If you want a full working host example instead of just the smaller integration fragments, use this as a reference implementation:
Suggested host CSS for that example:

Add Swap to the Same Privy Host

When your app exposes both Invest and Swap, keep the Privy wallet logic, config, and processBytecode in one shared provider component, register the Pods Wallet-style swap view in that provider config, then mount either widget inside it.
Keep the provider mounted only after the Privy smart-wallet session is ready. Use the SwapWidget guide for URL prefill and remount-key handling.

processBytecode expectations

The host still owns execution. Your processBytecode bridge must:
  • group legs by chainId and submit one batched transaction per chain (the example below uses client.sendTransaction({ calls }) — do not send legs individually)
  • emit HOST_ACK
  • emit SIGNATURE_PROMPTED
  • submit transactions through the Privy smart-wallet session
  • emit TX_SUBMITTED
  • wait for confirmation through the wallet provider
  • emit TX_CONFIRMED
  • emit TX_FINALIZED
  • map user cancellations to SIGNATURE_DECLINED
  • map other pre-submit failures to SIGNATURE_ERROR
For the full transaction lifecycle contract, see processBytecode Contract.

Branding / theme customization

Use DeframeProvider.config.theme as the main theme API:
You can also apply widget-scoped CSS variables from the host shell:
Keep those overrides scoped to .deframe-widget, never global on body or :root.

Authentication flow

Before creating wallets or rendering an authenticated Earn host, users must be logged in. At a minimum, your app should provide:
  • a way to start login
  • a way to complete login
  • a boolean gate for authenticated vs unauthenticated UI
  • a logout path
Helpful hooks from @privy-io/react-auth:

usePrivy()

useLoginWithEmail()

Embedded wallet + smart wallet flow

The practical flow is:
  1. authenticate the user
  2. create or reuse the embedded Privy wallet
  3. let Privy expose the smart-wallet client for transaction submission
  4. pass the smart-wallet address to Pods

Create or reuse the embedded wallet

useWallets()

useCreateWallet()

Access the smart-wallet client

useSmartWallets()

Smart wallets are commonly counterfactual. You may have an address before the contract is deployed on a specific chain.Before depending on a smart wallet on a target network:
  • check whether the contract is deployed on that chain
  • if needed, trigger deployment with a minimal transaction
  • ensure your paymaster or sponsorship setup has enough balance

Verify whether the smart wallet is deployed

Trigger deployment with a minimal transaction

In Pods integrations, the smart-wallet address is the address you normally pass into DeframeProvider.config.walletAddress.

Fetching strategies and bytecode directly from Pods API

Even when you use the widget, it can still help to understand the underlying API calls for debugging or custom host flows. All examples below use:
  • NEXT_PUBLIC_PODS_API_URL as base URL
  • NEXT_PUBLIC_PODS_API_KEY in x-api-key

List strategies

Get strategy details for a wallet

Generate strategy bytecode

Typical response shape:

Executing strategy bytecodes with Privy

After you receive strategy bytecodes, execute them with the smart-wallet client for the target chain.
If you are using sponsorship or a paymaster, make sure it has enough balance before testing the flow.