How to use Para with thirdweb

Learn how to connect Para with thirdweb. This guide shows you how to integrate Para’s embedded wallets with the thirdweb SDK to onboard users without seed phrases, while enabling full EVM and Solana compatibility, account abstraction, and seamless in-app payments.
Prerequisites
Before proceeding, ensure your application has the necessary setup for the Para SDK.
Step 1: Create a thirdweb Project
To access a client for authentication and transactions, follow these steps:
- Navigate to the thirdweb Dashboard.
- Click on Create a new project.
- Enter a project name (e.g., "My thirdweb project").
- Configure allowed domains:
- Add your production domain (e.g.,
mydomain.com
). - Add
localhost:<port>
for local development.
- Add your production domain (e.g.,
- Click Create to generate your project.
- Securely save your Client ID and Secret Key.
Add your keys to .env.local
Use either yarn or npm to install the required package:At the root of your project, create (or update) a .env.local
fi
NEXT_PUBLIC_THIRDWEB_CLIENT_ID=your_thirdweb_client_id
NEXT_PUBLIC_PARA_API_KEY=your_para_api_key
Step 2: Configure the thirdweb SDK
Install Dependencies
Use either yarn
or npm
to install the required package:
yarn add thirdweb
# or
npm install thirdweb
Set Up the Provider
// app/providers.tsx (or _app.tsx)
"use client";
import { ReactNode } from "react";
import { ThirdwebProvider } from "thirdweb/react";
import { Environment, ParaProvider, ParaModal } from "@getpara/react-sdk";
export default function Providers({ children }: { children: ReactNode }) {
return (
<ThirdwebProvider>
<ParaProvider
paraClientConfig={{
env: Environment.BETA, // use PROD for live
apiKey: process.env.NEXT_PUBLIC_PARA_API_KEY!,
}}
config={{ appName: "Para Modal Example" }}
>
{children}
</ParaProvider>
</ThirdwebProvider>
);
}
Step 3: Implement Login and Wallet Connection
Import Required Dependencies
In your login page or main application file, include the necessary imports:
"use client";
import { useEffect } from "react";
import { defineChain } from "thirdweb";
import { viemAdapter } from "thirdweb/adapters/viem";
import { createWalletAdapter } from "thirdweb";
import { useSetActiveWallet, useActiveWallet, ConnectButton, PayEmbed } from "thirdweb/react";
import { useViemClient, useViemAccount, useModal } from "@getpara/react-sdk";
import { client } from "@/lib/thirdwebClient";
Initialize thirdweb client
const client = createThirdwebClient({
clientId: process.env.NEXT_PUBLIC_TEMPLATE_CLIENT_ID!,
});
// (Optional) choose your active chain the same way you do elsewhere
const chain = defineChain(1); // e.g., Ethereum mainnet, or your target EVM chain
Handle Wallet Connection
"use client";
import { useEffect } from "react";
import { defineChain } from "thirdweb";
import { viemAdapter } from "thirdweb/adapters/viem";
import { createWalletAdapter } from "thirdweb";
import { useSetActiveWallet, useActiveWallet, ConnectButton, PayEmbed } from "thirdweb/react";
import { useViemClient, useViemAccount } from "@getpara/react-sdk"; // Para hooks
import { client } from "@/lib/thirdwebClient"; // ← shared client
export function WalletBridge() {
const { viemClient } = useViemClient(); // Para-provided viem WalletClient
const { viemAccount } = useViemAccount(); // { address, status } etc.
const setActiveWallet = useSetActiveWallet();
const thirdwebWallet = useActiveWallet();
const isConnected = Boolean(viemAccount?.address);
// Bridge Para's viem wallet client into a thirdweb wallet
useEffect(() => {
let cancelled = false;
const setActive = async () => {
if (!viemClient || !viemAccount?.address) return;
// Determine current chain id from the Para viem client
const chainId =
(await viemClient.getChainId?.()) ??
viemClient.chain?.id ??
1; // fallback: Ethereum mainnet
const personalAccount = viemAdapter.walletClient.fromViem({
walletClient: viemClient as any,
});
const w = createWalletAdapter({
client,
adaptedAccount,
chain: defineChain(chainId),
onDisconnect: async () => {
// optional: any local cleanup you need
},
switchChain: async (next) => {
// If you support user-initiated chain switching, implement it here.
// Typically you’d re-create the adapter with the new chain or
// call your own chain-switch UX before re-bridging.
},
});
if (!cancelled) setActiveWallet(w);
};
setActive();
return () => {
cancelled = true;
};
}, [viemClient, viemAccount?.address, setActiveWallet]);
}
Managing Wallet Disconnection
// If the Para account goes away (user logs out / session expired),
// make sure thirdweb disconnects too so state stays in sync.
useEffect(() => {
const syncDisconnect = async () => {
if (thirdwebWallet && !viemAccount?.address) {
await thirdwebWallet.disconnect();
}
};
syncDisconnect();
}, [thirdwebWallet, viemAccount?.address]);
Render UI Components
return (
<>
{isConnected ? (
<div className="connected-container">
<div className="component-card">
<h2 className="component-title">thirdweb Pay</h2>
<PayEmbed client={client} theme="light" />
</div>
<div className="component-card">
<h2 className="component-title">Wallet Management</h2>
<ConnectButton client={client} theme="light" />
</div>
</div>
) : (
<div className="disconnected-message">
Connect with Para to share the wallet between both libraries!
</div>
)}
</>
);
}
Using Para x Thirdweb Together: Camp Network
Teams like Camp Network are already using Para wallets with thirdweb Account Abstraction tooling to power seamless onboarding and in-app transactions. Para provides the universal embedded wallet layer (Distributed MPC, passkeys, and multi-chain support), while thirdweb’s AA SDK gives Camp flexible smart account features like gas sponsorship, batched transactions, session keys.
The result: users log in once with Para and get a gasless and bundled transaction experience through thirdweb, without ever touching seed phrases or juggling multiple wallets.