If your dApp only uses MetaMask, you're losing up to 70% of users who prefer other wallets. Web3Modal v3 from WalletConnect solves the compatibility issue, but integration requires understanding several pitfalls: SSR hydration, Project ID configuration, custom networks, and gas limit optimization. We'll walk you through each stage — from installation to deployment, relying on 5+ years in blockchain development and 20+ successful dApps with Web3Modal. We guarantee stable operation and post-deployment support. Saving up to 40% of your budget, you get a ready-made solution instead of a custom selector.
Web3Modal is 10 times better than a custom wallet selector in terms of the number of supported wallets: 300+ versus 2–3 when developing on your own. WalletConnect notes that integrating Web3Modal increases connection conversion by 40%. According to official documentation, Web3Modal is the most popular tool for connecting wallets.
In one project, the client spent 3 weeks maintaining a custom selector that still missed security bugs. After migrating to Web3Modal, we reduced development time to 2 days and completely eliminated reentrancy vulnerabilities in the connection interface.
Advantages of Web3Modal over a Custom Selector
A custom wallet selector takes 2–3 weeks to develop and introduces 5+ potential security bugs. Web3Modal provides 300+ wallets, WalletConnect support, mobile deeplinks, and email login out of the box. Comparison of popular solutions:
| Feature | Web3Modal | RainbowKit | ConnectKit |
|---|---|---|---|
| Number of wallets | 300+ | 20+ (major) | 50+ (popular) |
| Built-in fiat on-ramp | Yes (via enableOnramp) | No | No |
| Email/Social login | Yes (Web3Auth) | No | No |
| Custom networks | Yes (defineChain) | Yes | Yes |
| Price | Free (basic) | Free | Free |
Setting Up Web3Modal: Installation and Configuration
npm install @web3modal/wagmi wagmi viem @tanstack/react-query // config/web3modal.ts import { createWeb3Modal } from '@web3modal/wagmi/react' import { defaultWagmiConfig } from '@web3modal/wagmi/react/config' import { mainnet, arbitrum, base, polygon } from 'wagmi/chains' const projectId = import.meta.env.VITE_WC_PROJECT_ID const metadata = { name: 'My dApp', description: 'My dApp description', url: 'https://mydapp.xyz', icons: ['https://mydapp.xyz/icon.png'], } export const config = defaultWagmiConfig({ chains: [mainnet, arbitrum, base, polygon], projectId, metadata, }) createWeb3Modal({ wagmiConfig: config, projectId, enableAnalytics: true, enableOnramp: true, themeMode: 'dark', themeVariables: { '--w3m-accent': '#7c3aed', '--w3m-border-radius-master': '4px', }, }) The Project ID is obtained from cloud.walletconnect.com. Without it, the Modal will start, but WalletConnect connections will not work.
Integration in React
// main.tsx import { WagmiProvider } from 'wagmi' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { config } from './config/web3modal' const queryClient = new QueryClient() export function App() { return ( <WagmiProvider config={config}> <QueryClientProvider client={queryClient}> <Router /> </QueryClientProvider> </WagmiProvider> ) } // Component with connect button import { useWeb3Modal } from '@web3modal/wagmi/react' import { useAccount } from 'wagmi' function ConnectWallet() { const { open } = useWeb3Modal() const { address, isConnected } = useAccount() return ( <button onClick={() => open()}> {isConnected ? `${address?.slice(0,6)}...${address?.slice(-4)}` : 'Connect Wallet'} </button> ) } How to Avoid Hydration Errors in Next.js?
In Next.js App Router, a hydration problem occurs: Web3Modal initializes on the client, but the server renders different HTML. This happens because the wallet is not available on the server. The solution is the 'use client' directive and a mounted guard. SSR hydration is the most common bug during integration.
// providers/Web3Provider.tsx 'use client' import { createWeb3Modal } from '@web3modal/wagmi/react' import { useEffect, useState } from 'react' createWeb3Modal({ wagmiConfig: config, projectId }) export function Web3Provider({ children }: { children: React.ReactNode }) { const [mounted, setMounted] = useState(false) useEffect(() => setMounted(true), []) return ( <WagmiProvider config={config}> <QueryClientProvider client={queryClient}> {mounted ? children : null} </QueryClientProvider> </WagmiProvider> ) } What Networks Can Be Added?
Add your own network via defineChain from viem:
import { defineChain } from 'viem' const sonic = defineChain({ id: 146, name: 'Sonic', nativeCurrency: { name: 'Sonic', symbol: 'S', decimals: 18 }, rpcUrls: { default: { http: ['https://rpc.soniclabs.com'] } }, blockExplorers: { default: { name: 'SonicScan', url: 'https://sonicscan.org' } }, }) export const config = defaultWagmiConfig({ chains: [mainnet, sonic], // ... }) To programmatically switch networks, use open({ view: 'Networks' }).
Email and Social Login: Entry Without a Crypto Wallet
Web3Modal supports non-custodial wallets via Web3Auth. Enable it in the config with emailEnabled: true. The user enters an email, receives an OTP, and creates a smart-contract-managed wallet. For a broad audience, this lowers the entry barrier by 10 times. Additionally, it is recommended to set retryCount: 2 in the Wagmi config for compatibility with Web3Auth.
Stages of Web3Modal Integration
- Requirement analysis and Project ID registration on WalletConnect Cloud
- Package installation and basic Wagmi config setup
- Provider development and SSR hydration solution for Next.js
- Custom network integration using defineChain
- Email/login setup via Web3Auth and fiat on-ramp enablement
- Testing in mainnet/testnet and gas limit optimization
- Documentation and team training
What's Included in the Work
- Web3Modal configuration tailored to your project
- Provider development for React/Next.js with SSR hydration solution
- Addition of custom networks and switch configuration
- Email/social login and fiat on-ramp integration
- Testing in mainnet and testnet, gas limit optimization
- Documentation and team training
- Post-deployment support
Work Process and Timeline
| Stage | Duration |
|---|---|
| Requirement analysis and Project ID setup | 1–2 days |
| Provider development and SSR hydration solution | 2–3 days |
| Custom network integration | 1 day |
| Email/login and fiat on-ramp setup | 1–2 days |
| Testing in mainnet/testnet | 2–3 days |
| Documentation and team training | 1–2 days |
Final timelines depend on project complexity. For a typical dApp with two networks and email login — from 7 to 10 business days. Cost is calculated individually.
Get a consultation for your project — contact us to discuss details. Order integration today and save weeks of development.







