Migrate your existing Thirdweb application to Para’s unified wallet system. Para provides similar wallet connection capabilities with additional features like embedded wallets and session management while maintaining a simple integration.

Installation

Replace Thirdweb with Para SDK:
Terminal
npm uninstall thirdweb
npm install @getpara/react-sdk @tanstack/react-query wagmi viem
For a full list of dependencies, refer to the Quick Start Guide.

Configuration Changes

Before: Thirdweb Client

Your existing Thirdweb client configuration:
lib/client.ts
import { createThirdwebClient } from "thirdweb";

export const client = createThirdwebClient({
  clientId: process.env.NEXT_PUBLIC_THIRDWEB_CLIENT_ID!,
});

After: Para Configuration

Replace with Para configuration:
src/config/constants.ts
import { Environment } from "@getpara/react-sdk";

export const API_KEY = process.env.NEXT_PUBLIC_PARA_API_KEY ?? "";
export const ENVIRONMENT = 
  (process.env.NEXT_PUBLIC_PARA_ENVIRONMENT as Environment) || Environment.BETA;

if (!API_KEY) {
  throw new Error("Missing NEXT_PUBLIC_PARA_API_KEY environment variable");
}

Provider Migration

Before: Thirdweb Provider

Your existing Thirdweb provider in the layout:
app/layout.tsx
import type { Metadata } from "next";
import { ThirdwebProvider } from "thirdweb/react";

export const metadata: Metadata = {
  title: "Your App",
  description: "Your App Description",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>
        <ThirdwebProvider>{children}</ThirdwebProvider>
      </body>
    </html>
  );
}

After: Para Provider Setup

Create a Para provider component:
src/context/ParaProvider.tsx
"use client";

import { ParaProvider as Provider } from "@getpara/react-sdk";
import { API_KEY, ENVIRONMENT } from "@/config/constants";
import { mainnet, polygon, arbitrum } from "wagmi/chains";

export function ParaProvider({ children }: { children: React.ReactNode }) {
  return (
    <Provider
      paraClientConfig={{
        apiKey: API_KEY,
        env: ENVIRONMENT,
      }}
      externalWalletConfig={{
        wallets: ["METAMASK", "COINBASE", "WALLETCONNECT", "RAINBOW"],
        evmConnector: {
          config: {
            chains: [mainnet, polygon, arbitrum],
          },
        },
        walletConnect: {
          projectId: process.env.NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID || "",
        },
      }}
      config={{
        appName: "Your App Name",
      }}
      paraModalConfig={{
        authLayout: ["AUTH:FULL", "EXTERNAL:FULL"],
        theme: { mode: "light" },
      }}
    >
      {children}
    </Provider>
  );
}
Update your layout:
src/app/layout.tsx
import type { Metadata } from "next";
import "@getpara/react-sdk/styles.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider } from "@/context/ParaProvider";

const queryClient = new QueryClient();

export const metadata: Metadata = {
  title: "Your App",
  description: "Your App Description",
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <QueryClientProvider client={queryClient}>
          <ParaProvider>
            {children}
          </ParaProvider>
        </QueryClientProvider>
      </body>
    </html>
  );
}

Connect Button Migration

Before: Thirdweb ConnectButton

app/page.tsx
"use client";
import { ConnectButton } from "thirdweb/react";
import { client } from "@/lib/client";

export default function Home() {
  return (
    <main>
      <ConnectButton client={client} />
    </main>
  );
}

After: Para Connect Button

src/components/ConnectButton.tsx
"use client";

import { useAccount, useModal, useWallet } from "@getpara/react-sdk";

export function ConnectButton() {
  const { openModal } = useModal();
  const { data: wallet } = useWallet();
  const { isConnected } = useAccount();

  if (isConnected && wallet?.address) {
    return (
      <button onClick={() => openModal()} className="connect-button">
        {wallet.address.slice(0, 6)}...{wallet.address.slice(-4)}
      </button>
    );
  }

  return (
    <button onClick={() => openModal()} className="connect-button">
      Connect Wallet
    </button>
  );
}
Use it in your page:
src/app/page.tsx
import { ConnectButton } from "@/components/ConnectButton";

export default function Home() {
  return (
    <main>
      <ConnectButton />
    </main>
  );
}

Hook Migration

Account Information

import { useActiveAccount } from "thirdweb/react";

function Account() {
  const account = useActiveAccount();
  
  return (
    <div>
      Address: {account?.address}
    </div>
  );
}

Wallet Connection Status

import { useActiveWalletConnectionStatus } from "thirdweb/react";

function ConnectionStatus() {
  const status = useActiveWalletConnectionStatus();
  
  return (
    <div>
      Status: {status}
    </div>
  );
}

Disconnect Wallet

import { useDisconnect } from "thirdweb/react";

function DisconnectButton() {
  const { disconnect } = useDisconnect();
  
  return (
    <button onClick={disconnect}>
      Disconnect
    </button>
  );
}

Smart Contract Interaction

Para uses Wagmi for contract interactions, providing a different approach than Thirdweb:

Reading Contract Data

import { getContract } from "thirdweb";
import { useReadContract } from "thirdweb/react";
import { client } from "@/lib/client";

const contract = getContract({
  client,
  chain: ethereum,
  address: "0x...",
});

function ContractRead() {
  const { data } = useReadContract({
    contract,
    method: "function balanceOf(address) returns (uint256)",
    params: ["0x..."],
  });
  
  return <div>{data?.toString()}</div>;
}

Writing to Contract

import { prepareContractCall } from "thirdweb";
import { useSendTransaction } from "thirdweb/react";

function ContractWrite() {
  const { mutate: sendTransaction } = useSendTransaction();
  
  const handleTransfer = () => {
    const transaction = prepareContractCall({
      contract,
      method: "function transfer(address, uint256)",
      params: ["0x...", 100n],
    });
    sendTransaction(transaction);
  };
  
  return <button onClick={handleTransfer}>Transfer</button>;
}

Feature Comparison

FeatureThirdwebPara
Wallet Connection
Social LoginVia Auth SDK✅ Built-in
Email/Phone LoginVia Auth SDK✅ Built-in
Smart ContractsCustom SDKWagmi hooks
Chain Switching
Session ManagementLimited✅ Advanced
Gas SponsorshipVia Engine✅ Built-in

Advanced Features

Social Login

Para includes social login without additional configuration:
src/context/ParaProvider.tsx
paraModalConfig={{
  oAuthMethods: ["GOOGLE", "APPLE", "DISCORD", "TWITTER", "FACEBOOK"],
  disableEmailLogin: false,
  disablePhoneLogin: false,
}}

Multi-Chain Support

src/context/ParaProvider.tsx
import { mainnet, polygon, arbitrum, optimism, base } from "wagmi/chains";

externalWalletConfig={{
  evmConnector: {
    config: {
      chains: [mainnet, polygon, arbitrum, optimism, base],
    },
  },
}}

Custom Theme

src/context/ParaProvider.tsx
paraModalConfig={{
  theme: {
    mode: "dark",
    foregroundColor: "#FFFFFF",
    backgroundColor: "#1A1A1A",
    accentColor: "#6366F1",
    borderRadius: "medium",
    font: "Inter",
  },
  logo: "/logo.svg",
}}

Migration Checklist

Common Patterns

Balance Display

src/components/Balance.tsx
import { useAccount, useBalance } from "wagmi";
import { formatEther } from "viem";

export function Balance() {
  const { address } = useAccount();
  const { data } = useBalance({ address });

  if (!data) return null;

  return (
    <div>
      {formatEther(data.value)} {data.symbol}
    </div>
  );
}

Transaction History

src/components/TransactionHistory.tsx
import { useWallet } from "@getpara/react-sdk";

export function TransactionHistory() {
  const { data: wallet } = useWallet();
  
  // Para provides transaction history through the wallet object
  const transactions = wallet?.transactions || [];
  
  return (
    <ul>
      {transactions.map((tx) => (
        <li key={tx.hash}>{tx.hash}</li>
      ))}
    </ul>
  );
}

Next Steps