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 Webhooks Just Got More Reliable

Insight Webhooks Just Got More Reliable

We’ve re-architected how Insight webhooks are delivered — introducing a durable execution model that improves reliability, observability, and resilience. 🔂 Durable by Design Webhook delivery is now handled through a stateful, retry-capable execution engine. This means: * Delivery persists through failures – Webhooks won’t silently fail or get lost due to transient
May 15, 2025 1 min read
Nebula v0.0.14: Code Agent & Real-time Streaming

Nebula v0.0.14: Code Agent & Real-time Streaming

We're excited to announce a major upgrade to Nebula that introduces powerful new capabilities through the implementation of a code generation agent and real-time response streaming. These changes are live now at nebula.thirdweb.com! Overview This release transforms Nebula with the integration of an agent that can
May 14, 2025 2 min read
Onramp to Any Token from 160+ Countries

Onramp to Any Token from 160+ Countries

Universal Bridge now supports extended onramping via Transak
May 13, 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