Migrate your existing Web3Modal application to Para’s unified wallet system. Since both Web3Modal and Para use Wagmi internally, the migration involves replacing the Web3Modal provider with Para’s ParaProvider while maintaining your existing Wagmi configuration.

Installation

Replace Web3Modal packages with Para SDK while keeping Wagmi:
Terminal
npm uninstall @web3modal/wagmi
npm install @getpara/react-sdk
npm run postinstall
For a full list of dependencies, refer to the Quick Start Guide.

Configuration Changes

Before: Web3Modal Config

Your existing Web3Modal configuration likely looks like this:
config/index.ts
import { cookieStorage, createStorage } from 'wagmi';
import { mainnet } from 'wagmi/chains';
import { http, createConfig } from 'wagmi';
import { walletConnect, injected, coinbaseWallet } from 'wagmi/connectors';

export const projectId = process.env.NEXT_PUBLIC_PROJECT_ID;
if (!projectId) throw new Error('Project ID is not defined');

const metadata = {
  name: 'Web3Modal Example',
  description: 'Web3Modal Example',
  url: 'https://web3modal.com',
  icons: ['https://avatars.githubusercontent.com/u/37784886'],
};

export const config = createConfig({
  chains: [mainnet],
  transports: {
    [mainnet.id]: http(),
  },
  connectors: [
    walletConnect({ projectId, metadata, showQrModal: false }),
    injected({ shimDisconnect: true }),
    coinbaseWallet({
      appName: metadata.name,
      appLogoUrl: metadata.icons[0],
    }),
  ],
  ssr: true,
  storage: createStorage({
    storage: cookieStorage,
  }),
});

After: Para Config

Transform your configuration for Para:
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;
export const PROJECT_ID = process.env.NEXT_PUBLIC_PROJECT_ID ?? "";

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

Provider Migration

Before: Web3Modal Provider

Your existing Web3Modal provider:
context/Web3ModalProvider.tsx
'use client';
import React, { ReactNode } from 'react';
import { config, projectId } from '@/config';
import { createWeb3Modal } from '@web3modal/wagmi/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { State, WagmiProvider } from 'wagmi';

const queryClient = new QueryClient();
createWeb3Modal({
  wagmiConfig: config,
  projectId,
  enableAnalytics: true,
});

export default function Web3ModalProvider({
  children,
  initialState,
}: {
  children: ReactNode;
  initialState?: State;
}) {
  return (
    <WagmiProvider config={config} initialState={initialState}>
      <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
    </WagmiProvider>
  );
}

After: Para Provider

Replace with Para’s provider, passing your Wagmi config:
src/context/ParaProvider.tsx
"use client";

import { ParaProvider as Provider } from "@getpara/react-sdk";
import { API_KEY, ENVIRONMENT, PROJECT_ID } from "@/config/constants";
import { mainnet } from "wagmi/chains";
import { cookieStorage, createStorage, http } from "wagmi";

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],
            transports: {
              [mainnet.id]: http(),
            },
            ssr: true,
            storage: createStorage({
              storage: cookieStorage,
            }),
          },
        },
        walletConnect: {
          projectId: PROJECT_ID,
        },
      }}
      config={{
        appName: "Your App Name",
        description: "Your App Description",
      }}
      paraModalConfig={{
        authLayout: ["AUTH:FULL", "EXTERNAL:FULL"],
        theme: { mode: "light" },
      }}
    >
      {children}
    </Provider>
  );
}

Layout Update

Before: Web3Modal Layout

app/layout.tsx
import './globals.css';
import type { Metadata } from 'next';
import { headers } from 'next/headers';
import { cookieToInitialState } from 'wagmi';
import { config } from '@/config';
import Web3ModalProvider from '@/context/Web3ModalProvider';

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

export default function RootLayout({ children }: { children: React.ReactNode }) {
  const initialState = cookieToInitialState(config, headers().get('cookie'));
  return (
    <html lang="en">
      <body>
        <Web3ModalProvider initialState={initialState}>
          {children}
        </Web3ModalProvider>
      </body>
    </html>
  );
}

After: Para 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: Web3Modal Button

components/ConnectButton.tsx
'use client';
import { useWeb3Modal } from '@web3modal/wagmi/react';

export default function ConnectButton() {
  const { open } = useWeb3Modal();
  return <button onClick={() => open()}>Connect Wallet</button>;
}

After: Para 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>
  );
}

Configuration Mapping

Para maintains full Wagmi compatibility. Your existing Wagmi hooks and configuration continue to work seamlessly.
Web3Modal ConfigPara ConfigLocation
projectIdwalletConnect.projectIdexternalWalletConfig
wagmiConfig.chainsevmConnector.config.chainsexternalWalletConfig
wagmiConfig.transportsevmConnector.config.transportsexternalWalletConfig
wagmiConfig.ssrevmConnector.config.ssrexternalWalletConfig
wagmiConfig.storageevmConnector.config.storageexternalWalletConfig
metadata.nameconfig.appNameRoot config
metadata.descriptionconfig.descriptionRoot config

Advanced Configuration

Multiple Chains

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

// In ParaProvider
externalWalletConfig={{
  evmConnector: {
    config: {
      chains: [mainnet, polygon, arbitrum, optimism],
      transports: {
        [mainnet.id]: http(),
        [polygon.id]: http(),
        [arbitrum.id]: http(),
        [optimism.id]: http(),
      },
    },
  },
}}

Custom RPC Endpoints

src/context/ParaProvider.tsx
import { http } from "wagmi";

// In ParaProvider
externalWalletConfig={{
  evmConnector: {
    config: {
      transports: {
        [mainnet.id]: http("https://your-custom-rpc.com"),
      },
    },
  },
}}

Social Login Support

Para adds embedded wallet support automatically:
src/context/ParaProvider.tsx
paraModalConfig={{
  authLayout: ["AUTH:FULL", "EXTERNAL:FULL"],
  oAuthMethods: ["GOOGLE", "APPLE", "DISCORD", "TWITTER"],
  disableEmailLogin: false,
  disablePhoneLogin: false,
}}

Using Wagmi Hooks

Your existing Wagmi code continues to work without changes:
src/components/AccountInfo.tsx
import { useAccount, useBalance, useEnsName } from "wagmi";

export function AccountInfo() {
  const { address } = useAccount();
  const { data: balance } = useBalance({ address });
  const { data: ensName } = useEnsName({ address });

  if (!address) return null;

  return (
    <div>
      <p>{ensName || address}</p>
      <p>{balance?.formatted} {balance?.symbol}</p>
    </div>
  );
}

Migration Checklist

Common Issues

SSR Hydration: Para handles SSR internally. Remove manual cookie state management from your layout.
Connector Configuration: Para manages wallet connectors internally. Remove explicit connector imports from Wagmi.

Next Steps