Skip to main content

Connect a wallet to your dapp

Enabling users' wallets to connect to your dapp is critical, since it's the only way they can send transactions and sign messages that enable them to interact with underlying smart contracts.

In this guide, we'll go through several methods for connecting wallets to a React dapp.

Wagmi​

Wagmi is a library of React hooks for developing dapps that interact with Ethereum-based blockchains like Linea.

To get started, install the packages:

npm install wagmi viem@2.x @tanstack/react-query

Wagmi configuration​

Create a file named wagmi.ts in your in your project directory, and add this code:

import { http, createConfig } from 'wagmi'
import { linea, lineaSepolia, mainnet } from 'wagmi/chains'
import { injected, metaMask } from 'wagmi/connectors'

const projectId = '<WALLETCONNECT_PROJECT_ID>'

export const config = createConfig({
chains: [lineaSepolia, linea, mainnet],
connectors: [
injected(),
metaMask({
infuraAPIKey: process.env.NEXT_PUBLIC_INFURA_API_KEY!,
})],
transports: {
[lineaSepolia.id]: http(),
[linea.id]: http(),
[mainnet.id]: http(),
},
})

This configuration file ensures Wagmi works with Linea, Linea Sepolia, and Ethereum Mainnet, and also defines that we should use the injected wallet connector, which works with any wallet that uses the common EIP-1193 standard. There are a few wallets that also have separate connectors.

You can also use the metaMask connector, which works with MetaMask Wallet.

Add Wagmi and query providers​

Next, head to your app file.

Import the relevant providers from Wagmi and TanStack Query, as well as the QueryClient function we'll use:

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider } from 'wagmi'
import { config } from './wagmi' // path your wagmi.ts config file
TanStack Query

TanStack Query, formerly known as React Query, is a library that adds state management for the onchain data your dapp requests from the blockchain using Wagmi hooks. It's not essential, but recommended.

Then add the following code, so that your dapp is wrapped within the Wagmi and TanStack Query providers:

'use client'

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider } from 'wagmi'
import { config, metaMask } from './wagmi'

const queryClient = new QueryClient()

export default function App() {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<AppContent />
</QueryClientProvider>
</WagmiProvider>
);
}

Add a wallet connection​

There are several ways you could use Wagmi to connect wallets. The simplest is to create a wallet connector component that uses the useConnect hook.

Multi-wallet discovery

If you're up for the challenge, and particularly if you're creating a production dapp, we recommend you set up your dapp to support EIP-6963, a standard that defines "multi-wallet discovery". In short, this means that your dapp can detect the presence of multiple wallets on the user's device and give them the choice of which wallet to connect.

To see how, follow a guide like this one or this one.

To proceed with the simpler implementation, we'll create a new component, in a /components directory if you prefer, and add the below code. We'll call it ConnectButton.js, but choose whatever filename you like:

import { useConnect } from 'wagmi'
import { injected } from 'wagmi/connectors'

export function ConnectButton() {
const { connect } = useConnect()

return (
<>
<button onClick={() => connect({ connector: injected() })}>
Connect wallet
</button>
<button onClick={() => connect({ connector: metaMask() })}>
Connect MetaMask wallet
</button>
</>
)
}

The useConnect hook is the main object of note here.

Now that we've defined the component, we can import and insert it into the dapp:

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider } from 'wagmi'
import { config } from './wagmi'
import { ConnectButton } from '../components/ConnectButton'

const queryClient = new QueryClient()

export default function App() {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<ConnectButton />
</QueryClientProvider>
</WagmiProvider>
);
}

Now if you run npm run dev, you should be able to connect your wallet, such as MetaMask, on Linea, Linea Sepolia, or Ethereum Mainnet.

Note that this is a very basic implementation, with no CSS styling and missing a few other necessary features, such as displaying the connected wallet's address (useAccount), connection status, and a disconnect button.

MetaMask Embedded Wallets (Web3Auth)​

MetaMask Embedded Wallets brings one-click, OAuth-based onboarding to your dApp in every major developer environment, so your dApps, mobile apps, and games can all connect seamlessly to Linea.

PlatformSDK Documentation
Reactdocs.metamask.io/embedded-wallets/sdk/react
Vuedocs.metamask.io/embedded-wallets/sdk/vue
JavaScriptdocs.metamask.io/embedded-wallets/sdk/js
Node.jsdocs.metamask.io/embedded-wallets/sdk/node
Androiddocs.metamask.io/embedded-wallets/sdk/android
iOSdocs.metamask.io/embedded-wallets/sdk/ios
React Nativedocs.metamask.io/embedded-wallets/sdk/react-native
Flutterdocs.metamask.io/embedded-wallets/sdk/flutter
Unitydocs.metamask.io/embedded-wallets/sdk/unity
Unreal Enginedocs.metamask.io/embedded-wallets/sdk/unreal

Follow the steps below to integrate MetaMask Embedded Wallets into your dapp.

Dashboard Configuration​

All setup happens inside the MetaMask Embedded Wallets Dashboard — no SDK changes or code edits are required.

Get your Client ID​

After signing up and accessing your MetaMask Embedded Wallets Dashboard, create a new project on sapphire_devnetand navigate to Project Settings to find your Client ID. Copy this value as you'll need it for configuration.

Enable Linea networks on dashboard​

To enable Linea and Linea Sepolia networks:

  1. Go to your MetaMask Embedded Wallets Dashboard
  2. Navigate to the Chains & Networks tab in the sidebar of your project
  3. Search for "Linea" in the chains list
  4. Enable both Linea and Linea Sepolia networks
  5. Save your configuration

Once enabled, all MetaMask Embedded Wallets SDKs will automatically connect to these networks, no code updates needed.

Install dependencies​

Install the MetaMask Embedded Wallets SDK and other required packages:

npm install @web3auth/modal wagmi viem@2.x @tanstack/react-query

This installs:

  • @web3auth/modal: MetaMask Embedded Wallets SDK
  • wagmi: React hooks for Ethereum
  • viem: TypeScript interface for Ethereum
  • @tanstack/react-query: Required for Wagmi's data fetching

Configure Web3Auth & Wagmi Provider​

Create a configuration file for Web3Auth & Wagmi in your project. This file will be used to wrap your app state with the wallet & blockchain connection providers. In your components directory, create a new file called provider.tsx:

// Web3Auth Imports
import { Web3AuthProvider, type Web3AuthContextConfig } from "@web3auth/modal/react";
import { IWeb3AuthState, WEB3AUTH_NETWORK } from "@web3auth/modal";

// Wagmi Imports
import { WagmiProvider } from "@web3auth/modal/react/wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

// QueryClient for Wagmi Hooks Configuration
const queryClient = new QueryClient();

// Web3Auth Configuration
const web3AuthContextConfig: Web3AuthContextConfig = {
web3AuthOptions: {
clientId: 'YOUR_WEB3AUTH_CLIENT_ID', // Pass your Web3Auth Client ID, ideally using an environment variable // Get your Client ID from Web3Auth Dashboard
web3AuthNetwork: WEB3AUTH_NETWORK.SAPPHIRE_DEVNET, // or WEB3AUTH_NETWORK.SAPPHIRE_MAINNET
}
};

// Provider Component
export default function Provider({ children }:
{ children: React.ReactNode }) {
return (
<Web3AuthProvider config={web3AuthContextConfig}>
<QueryClientProvider client={queryClient}>
<WagmiProvider>
{children}
</WagmiProvider>
</QueryClientProvider>
</Web3AuthProvider>
);
}

Use the hooks to connect the wallet​

The useWeb3AuthConnect, useWeb3AuthDisconnect, and useWeb3AuthUser hooks are used to connect, disconnect, and get user information from the wallet. Similarly, many other hooks are available to interact with the wallet and blockchain.

import { useWeb3AuthConnect, useWeb3AuthDisconnect, useWeb3AuthUser } from "@web3auth/modal/react";

export default function ConnectWallet() {
const { connect, isConnected, loading: connectLoading, error: connectError } = useWeb3AuthConnect();
const { disconnect, loading: disconnectLoading, error: disconnectError } = useWeb3AuthDisconnect();
const { userInfo } = useWeb3AuthUser();

return (
<div>
{!isConnected ? (
<button
className="docs-button"
disabled={connectLoading}
onClick={connect}
>
{connectLoading ? 'Connecting...' : 'Connect Wallet'}
</button>
) : (
<div className="flex gap-2">
<span>Connected as: {userInfo?.email || userInfo?.name || 'User'}</span>
<button
className="docs-button"
disabled={disconnectLoading}
onClick={disconnect}
>
{disconnectLoading ? 'Disconnecting...' : 'Disconnect'}
</button>
</div>
)}
</div>
)
}

Dynamic​

Install the Dynamic SDK and the Ethereum connectors:

npm install @dynamic-labs/sdk-react-core @dynamic-labs/ethereum

The latter contains wallet connectors for all chains compatible with the Ethereum Virtual Machine (EVM), Linea included.

Set up Dynamic dashboard​

To properly configure the Dynamic component we're about to use, you need to sign up for Dynamic to access the Dynamic dashboard.

Once you're in the dashboard, you need to:

  1. Enable Linea (and Linea Sepolia, if you need it). See the guide to configuring your chains.
  2. Get the environmentId from Developers > SDK & API Keys.

Add the provider​

To set up the dapp to work with the Dynamic wallet connector button, we need to:

  • Wrap dapp contents in the DynamicContextProvider component.
  • Import the Dynamic Ethereum wallet connectors and pass these to the DynamicContextProvider in its settings.

Then, paste the following code into your dapp:

import { DynamicContextProvider } from "@dynamic-labs/sdk-react-core";
import { EthereumWalletConnectors } from "@dynamic-labs/ethereum";

export default function App() {
return (
<DynamicContextProvider
settings={{
environmentId: "YOUR_ENVIRONMENT_ID",
walletConnectors: [EthereumWalletConnectors]
}}
>
<AppContent />
</DynamicContextProvider>
);
}

Replace YOUR_ENVIRONMENT_ID with the environmentId with your own. This enables Dynamic to pull your configured chains and any other preferences you set up in the dashboard.

note

If you intend to use Wagmi in your project, you also need to add a DynamicWagmiProvider component and wrap it with WagmiProvider, like this:

<DynamicContextProvider>
<WagmiProvider>
<DynamicWagmiProvider>
<AppContent />
</DynamicWagmiProvider>
</WagmiProvider>
</DynamicContextProvider>

Add the component​

Next, select a wallet component. For example, you can use the DynamicWidget component if you want a wallet connector button that you can configure to use various user onboarding methods such as email, phone number, or even embedded wallets.

For simplicity, let's go with DynamicConnectButton, which is a classic wallet connection button for connecting external wallets.

Add it to your import statement:

import { DynamicContextProvider, DynamicConnectButton } from "@dynamic-labs/sdk-react-core";

Then slot it into your dapp, adding some text:

import { DynamicContextProvider, DynamicConnectButton } from "@dynamic-labs/sdk-react-core";
import { EthereumWalletConnectors } from "@dynamic-labs/ethereum";

export default function App() {
return (
<DynamicContextProvider
settings={{
environmentId: "7cc1f95f-6015-4f0b-888d-e52178b1b27d",
walletConnectors: [EthereumWalletConnectors]
}}
>
<DynamicConnectButton>
Connect wallet
</DynamicConnectButton>
</DynamicContextProvider>
);
}

Now, run your dapp locally and click the button to test your work:

npm run dev

You should be able to connect to Linea and Linea Sepolia.

Privy​

Privy provides multiple SDKs for building dapps. Their React SDK is an easy way to get a flexible, configurable wallet connection component into your dapp.

Install the Privy SDK with this command:

npm install @privy-io/react-auth@latest

Set up Privy dashboard​

Sign up for Privy to access the dashboard.

Go to Login Methods in the sidebar to configure login methods for your dapp, and make sure that external wallets are enabled. Optionally, feel free to toggle any other methods you want to use.

Now go to App Settings and get your App ID. We'll need to add this to the dapp code to ensure Privy functions correctly.

Add the provider​

Now we need to import the Privy provider to the dapp and then use it to wrap the dapp contents:

'use client'

import { PrivyProvider } from '@privy-io/react-auth';

export default function App() {
return (
<PrivyProvider
appId="your-privy-app-id" // add your App ID here
config={{
appearance: {
theme: 'dark',
},
}}
>
<AppContent />
</PrivyProvider>
);
}

The appearance configuration is optional.

Configure Linea​

To enable Privy to use Linea, we need to import it from Viem. First, install Viem with this command:

npm install viem

And then add this import statement to your dapp:

import { linea, lineaSepolia } from 'viem/chains'

Now we need to add the Linea chains to the PrivyProvider config:

'use client'

import { PrivyProvider } from '@privy-io/react-auth';
import { linea, lineaSepolia } from 'viem/chains'

export default function App() {
return (
<PrivyProvider
appId="cm4tv4knx03yv4baen04ozlhv"
config={{
appearance: {
theme: 'dark',
},
defaultChain: linea,
supportedChains: [linea, lineaSepolia],
}}
>
<AppContent />
</PrivyProvider>
);
}

We've chosen Linea Mainnet as the defaultChain, but you can set this with Linea Sepolia instead, if you prefer.

Add the component​

To implement the wallet connection button, we'll create a new component that uses the usePrivy hook, which enables you to trigger the Privy login modal to appear.

Create a new file named ConnectButton.js in your /components directory, and add the following code:

import { usePrivy } from '@privy-io/react-auth';

function ConnectButton() {
const { login } = usePrivy();

return (
<button onClick={login}>
Connect wallet
</button>
);
}

Now we can import the component and insert it into the dapp. Ensure your dapp reflects this code:

'use client'

import { PrivyProvider } from '@privy-io/react-auth';
import { linea, lineaSepolia } from 'viem/chains'
import { ConnectButton } from '../components/ConnectButton';

export default function App() {
return (
<PrivyProvider
appId="cm4tv4knx03yv4baen04ozlhv"
config={{
appearance: {
theme: 'dark',
},
defaultChain: linea,
supportedChains: [linea, lineaSepolia],
}}
>
<ConnectButton />
</PrivyProvider>
);
}

Now if you run your dapp with npm run dev, the Privy modal will appear when you click the button.