thirdweb
  • Homepage ↗
  • Guides
  • Case Studies
  • Changelog
  • Docs ↗
  • YouTube ↗
Smart Wallets

Integrating Smart Wallet in a React App

  • Avneesh Agarwal

Avneesh Agarwal

Sep 11, 2023 • 6 min read
Integrating Smart Wallet in a React App

⚠️ Warning: This guide currently uses v4 of the Connect SDK. For v5 (latest) code snippets, please check out our documentation while this guide is being updated. ⚠️

This guide will show you how to create a react app where users can connect their smart wallets to your front end!

What is a smart contract wallet?

A smart contract wallet is a type of non-custodial web3 wallet that uses smart contracts to operate and manage assets. By adding logic to the smart contract's code, smart contract wallets unlock powerful new features:

  • Multi-sig recoverable wallets.
  • Multiple signers.
  • Invisible transactions.
  • Batched transactions.

To learn more about smart contract wallets, check out the documentation:

Overview | thirdweb developer portal
Everything you need to build ERC-4337 Smart Wallets for your users.
thirdweb docs

Deploy the Smart Wallet Contract

To begin, head to the Contracts page in your thirdweb Dashboard and hit Deploy Contract:

deploy new contract

You will be taken to the thirdweb Explore page — where you can browse smart contracts built by the top protocols in Web3 and deploy them in just a few clicks!

Note: You can also use the thirdweb CLI to set up a smart contract project to create your own contracts by running the below command from your terminal:
npx thirdweb create contract
This will take you through an easy-to-follow flow of steps for you to create your contract. Learn more about this in our CLI guide.

Otherwise, let's get back to Explore:

Choose Account Factory (Beta) on the explore page

Select one of the Smart Wallet contracts based on your requirements. I am going with the Account Factory (Beta) contract for this guide. Clicking on it will take you to the following page:

Account Factory contract

Once you are on this page, click Deploy Now, and you should see a drawer slide in from the right. You can change the advanced configuration here if you want.

Finally, select the network/chain you want to deploy to and hit Deploy Now. This will trigger two transactions in your wallet that you will need to confirm:

Click on confirm to deploy your loyalty card program

Once the transactions go through, you will be able to see the dashboard for your contract:

Account Factory Dashboard

We don't have to do anything else with the contract for now. Let's use the contract in a Vite app!

Creating the Vite App

Before we begin, you can access the complete source code for this template on GitHub.

Using the thirdweb CLI, create a new Vite & TypeScript project with the React SDK preconfigured for you using the following command:

npx thirdweb create app --vite --ts
💡
An API key is required to use thirdweb's infrastructure services, such as storage, RPCs, and Smart Wallet infrastructure from within the SDK. If you haven't created a key yet, you can do so for free from the thirdweb dashboard.

To use an API key with the React SDK, pass the clientId to the ThirdwebProvider. Create a new .env file and add the clientId:

VITE_TEMPLATE_CLIENT_ID=

Next, we need to update the chain that our contract is deployed on. Open main.tsx and change the activeChain variable to the chain that you deployed your contract to. In this case, it is Mumbai:

// This is the chainId your dApp will work on.
const activeChain = "mumbai";

There are two ways for your users to connect their smart wallets:

  • Using the pre-built ConnectWallet component.
  • Using the useConnect hook and a custom UI.

Let's go through both!

Connect Wallet

To use the pre-built UI component to connect your users to your app using smart wallet, we need to pass a smartWallet as a supportedWallet to the ThirdwebProvider. First, let's set up our configuration for the smart wallet. In main.tsx add the following:

export const smartWalletConfig = smartWallet({
  factoryAddress: "your-factory-address",
  gasless: true,
  personalWallets: [localWallet()],
});
💡
Make sure to update the factory address to the address of your deployed contract.

You can change the configuration based on your requirements, but for this demo, we will enable gasless transactions and use a local wallet as the personal wallet. You can learn more about the configuration on our portal.

Pass the configuration to the provider:

<ThirdwebProvider
      clientId={import.meta.env.VITE_TEMPLATE_CLIENT_ID}
      activeChain={activeChain}
      supportedWallets={[smartWalletConfig]}
    >
      <App />
    </ThirdwebProvider>

Now, import the ConnectWallet component from the React package and add it to your app:

import { ConnectWallet } from "@thirdweb/react";

function App() {
  return (
    <div className="App">
      <ConnectWallet />
    </div>
  );
}

Since we already added Smart Wallet as a supported wallet, it will automatically be used in the ConnectWallet component to connect users to your app. Clicking on the connect button will show a popup:

You can now create a new wallet with a password or import a previously created wallet. This will create a smart wallet for you and connect it to the application:

Custom UI

Now let's create our own UI using the useConnect hook.

Create a new component connect.tsx in the components folder and add the structure of a component:

export const ConnectComponent = () => {
  return <></>;
};

Firstly, we will use the useAddress hook to get the address of the connected wallet and check if the user is connected:

const address = useAddress();

We can now use it like this:

return address ? (
    <h3>
      Connected as:
      <br />{" "}
      <a
        href={`https://thirdweb.com/${activeChain.chainId}/${address}/account`}
        target="_blank"
      >
        {address}
      </a>
    </h3>
  ) : (
    <></>
  );

Here, we are checking if there is an address and then rendering the address with a link; otherwise, it does nothing. Now, let's create the logic of connecting the wallet using a custom UI.

Using useState, store the inputted password:

const [password, setPassword] = useState("");

If the address isn't present we can now show an input and button log in:

<>
  <input
    className="input"
    type="password"
    placeholder="Enter Password"
    onChange={(e) => setPassword(e.target.value)}
  />
  <button className="button" onClick={loadLocalWalletAndConnect}>
    Log in
  </button>
</>

As you can see, we are missing the loadLocalWalletAndConnect function, so let's create that:

const loadLocalWalletAndConnect = async () => {
    if (!password) {
      alert("Please enter a password");
      return;
    }
    try {
      const personalWallet = new LocalWallet({
        chain: Mumbai,
      });
      await personalWallet.loadOrCreate({
        strategy: "encryptedJson",
        password: password,
      });
      await connect(smartWalletConfig, {
        personalWallet: personalWallet,
      });
    } catch (e) {
      alert((e as any).message);
    }
  };

This creates an instance of a LocalWallet class and uses the loadOrCreate function to get the wallet, and finally connects the wallet using the useConnect hook which you need to add:

const connect = useConnect();

The final code should look like this:

import { Mumbai } from "@thirdweb-dev/chains";
import { useAddress, useConnect } from "@thirdweb-dev/react";
import { LocalWallet } from "@thirdweb-dev/wallets";
import { activeChain, smartWalletConfig } from "../main";
import { useState } from "react";

export const ConnectComponent = () => {
  const connect = useConnect();
  const address = useAddress();
  const [password, setPassword] = useState("");

  const loadLocalWalletAndConnect = async () => {
    if (!password) {
      alert("Please enter a password");
      return;
    }
    try {
      const personalWallet = new LocalWallet({
        chain: Mumbai,
      });
      await personalWallet.loadOrCreate({
        strategy: "encryptedJson",
        password: password,
      });
      await connect(smartWalletConfig, {
        personalWallet: personalWallet,
      });
    } catch (e) {
      alert((e as any).message);
    }
  };

  return address ? (
    <h3>
      Connected as:
      <br />{" "}
      <a
        href={`https://thirdweb.com/${activeChain.chainId}/${address}/account`}
        target="_blank"
      >
        {address}
      </a>
    </h3>
  ) : (
    <>
      <input
        className="input"
        type="password"
        placeholder="Enter Password"
        onChange={(e) => setPassword(e.target.value)}
      />
      <button className="button" onClick={loadLocalWalletAndConnect}>
        Log in
      </button>
    </>
  );
};

You can now go ahead and add this component to your App.tsx file!

When running this app, you will see the following:

Go ahead and fill in your password, and you will see that it shows the address of your smart wallet!

Wrapping up

In this guide, we learned how to connect users to a React app using two methods:

  • With a pre-built UI component
  • With a custom UI component

Take a look at the GitHub Repository for the full source code!

You learned a lot. Now pat yourself on the back and share your amazing apps with us on the thirdweb discord!


Need help?

For support, join the official thirdweb Discord server or share your thoughts on our feedback board.

Insight - Filter NFT Transfers By Type

Insight - Filter NFT Transfers By Type

Insight adds support for filtering NFT transfers by type. On the v1/nfts/transfers endpoint you can specify a transfer_type query parameter and choose to filter transfer, sale, mint or burn transfers. transfer - Any transfer without additional sale data sale - A transfer that has additional sale data*
Jun 6, 2025 1 min read
Crypto as the Internet's Native Payment Layer

Crypto as the Internet's Native Payment Layer

When you send a text message, you tap send and it arrives instantly. No loading screens, no confirmation steps, no wondering if it worked. The entire experience feels natural and effortless, even though complex technical processes happen behind the scenes routing your message across networks, protocols, and devices. This is
Jun 5, 2025 5 min read
Nebula v0.0.17 - Onramping, Aggregations & Agent Improvements

Nebula v0.0.17 - Onramping, Aggregations & Agent Improvements

This release introduces significant improvements to Nebula's agent capabilities, adding fiat onramping through Universal Bridge, new NFT collection tools, and aggregated transaction and events data. Improvements have been made to Nebula’s memory handling, leading to faster responses in some cases and helping us prepare for our next
Jun 5, 2025 2 min read

Build web3 apps easily

Deploy smart contracts and build dApps on 700+ blockchains, in minutes.

Start building Contact us
thirdweb © 2025