ReactQuickstart

Add to Existing Project

By the end of this tutorial, you’ll have embedded smart wallets with authentication integrated into your existing React application, allowing users to login without seed phrases and perform gasless transactions.

This tutorial assumes you’re using a React application with Next.js app router. If you’re using a different setup, the core concepts remain the same but you may need to adapt the provider setup to your framework.

1. Install the packages

Install the React and Infra packages from Smart Wallets along with required dependencies.

Prerequisites

  • React 18+
  • TypeScript 5+
$yarn add @account-kit/infra @account-kit/react @tanstack/react-query
>yarn add -D tailwindcss @tailwindcss/postcss postcss

Set up Tailwind CSS

Create a postcss.config.mjs file and add the Tailwind plugin:

postcss.config.mjs
1export default {
2 plugins: {
3 "@tailwindcss/postcss": {},
4 },
5};

Create a global.css file and import it in your app root:

global.css
1@import "tailwindcss";

Already using Tailwind? You can skip the setup above since you’ve already configured it.

2. Get your API Key

  1. Create an app in the Alchemy Dashboard

    • Make sure your desired network is enabled under the Networks tab
  2. Create a new configuration in your Smart Wallets Dashboard

    • Apply the config to your app from step 1
    Apply your config to the app from the first step
    • Enable the authentication methods you want (email, social login, etc.)
    • For testing, use http://localhost:3000 as your redirect URL
  3. Copy your API key from the dashboard - you’ll need it for the next step

    How to copy the API key

3. Configure your authentication and styling

Create two configuration files that will customize your authentication methods and UI styles.

Create your configuration files

  1. In your project root, create a config.ts file
  2. In your project root, create a tailwind.config.ts file

You can customize these by visiting our demo app - use the interactive sandbox to explore different authentication methods and styling options. When ready, click ‘Code preview’ to export your customized configuration files.

Basic configuration example

Here’s a basic configuration to get you started:

tailwind.config.ts

tailwind.config.ts
1import { withAccountKitUi } from "@account-kit/react/tailwind";
2
3export default withAccountKitUi(
4 {
5 // Your existing Tailwind config (if already using Tailwind).
6 // If using Tailwind v4, this will likely be left empty.
7 },
8 {
9 // AccountKit UI theme customizations
10 },
11);

Important: If your tailwind.config.ts already contains any existing config information, be sure to wrap it with withAccountKitUi as shown above. Don’t replace your existing config - just wrap it!

Update your global.css to include the config:

global.css
1@import "tailwindcss";
2@config '../../tailwind.config.ts';

Note: If still using Tailwind v3, skip this step as the tailwind.config.ts file is used by default.

config.ts

import { 
const createConfig: (props: CreateConfigProps, ui?: AlchemyAccountsUIConfig) => AlchemyAccountsConfigWithUI

Wraps the createConfig that is exported from @aa-sdk/core to allow passing an additional argument, the configuration object for the Auth Components UI (the modal and AuthCard).

createConfig
,
const cookieStorage: (config?: { sessionLength?: number; domain?: string; }) => Storage

Function to create cookie based Storage

cookieStorage
} from "@account-kit/react";
import {
class QueryClient
QueryClient
} from "@tanstack/react-query";
import {
const arbitrumSepolia: Chain
arbitrumSepolia
,
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
} from "@account-kit/infra";
export const
const config: AlchemyAccountsConfigWithUI
config
=
function createConfig(props: CreateConfigProps, ui?: AlchemyAccountsUIConfig): AlchemyAccountsConfigWithUI

Wraps the createConfig that is exported from @aa-sdk/core to allow passing an additional argument, the configuration object for the Auth Components UI (the modal and AuthCard).

createConfig
(
{
transport: AlchemyTransport
transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
({
// Replace with your API key
apiKey: string
apiKey
: "YOUR_API_KEY",
}),
chain: Chain
chain
:
const arbitrumSepolia: Chain
arbitrumSepolia
,
ssr?: boolean | undefined

Enable this parameter if you are using the config in an SSR setting (eg. NextJS) Turing this setting on will disable automatic hydration of the client store

ssr
: true,
storage?: CreateStorageFn | undefined
storage
:
const cookieStorage: (config?: { sessionLength?: number; domain?: string; }) => Storage

Function to create cookie based Storage

cookieStorage
,
enablePopupOauth?: boolean | undefined

If set, calls preparePopupOauth immediately upon initializing the signer. If you intend to use popup-based OAuth login, you must either set this option to true or manually ensure that you call signer.preparePopupOauth() at some point before the user interaction that triggers the OAuth authentication flow.

enablePopupOauth
: true,
// For gas sponsorship (optional) // Learn more here: https://www.alchemy.com/docs/wallets/react/sponsor-gas
policyId?: string | string[] | undefined
policyId
: "YOUR_POLICY_ID",
}, {
auth?: { addPasskeyOnSignup?: boolean; header?: React.ReactNode; hideError?: boolean; onAuthSuccess?: () => void; sections: AuthType[][]; hideSignInText?: boolean; } | undefined
auth
: {
sections: AuthType[][]

Each section can contain multiple auth types which will be grouped together and separated by an OR divider

sections
: [
[{
type: "email"
type
: "email" }],
[ {
type: "passkey"
type
: "passkey" },
{
type: "social"
type
: "social",
authProviderId: KnownAuthProvider
authProviderId
: "google",
mode: "popup"
mode
: "popup" },
], ],
addPasskeyOnSignup?: boolean | undefined

If this is true, then auth components will prompt users to add a passkey after signing in for the first time

addPasskeyOnSignup
: true,
}, }, ); export const
const queryClient: QueryClient
queryClient
= new
new QueryClient(config?: QueryClientConfig): QueryClient
QueryClient
();

Remember to replace "YOUR_API_KEY" with the API key from step 2.

Important: The chain you import (like arbitrumSepolia) must come from the @account-kit/infra package, not from viem. Additionally, make sure this chain is enabled in both your Alchemy app and Account Kit config policy in the dashboard.

Note: You can add an "external_wallets" auth method to your config to allow connecting existing external EOAs (such as MetaMask) using our built-in connectors and WalletConnect. Learn more here

[
  {
    
type: string
type
: "external_wallets",
walletConnect: { projectId: string; }
walletConnect
: {
projectId: string
projectId
: "your-project-id" },
}, ];

4. Set up the Alchemy Provider

Wrap your application with the Alchemy Provider to enable embedded wallet functionality.

Create providers.tsx

app/providers.tsx
1"use client";
2import { config, queryClient } from "@/config";
3import { AlchemyAccountProvider } from "@account-kit/react";
4import { QueryClientProvider } from "@tanstack/react-query";
5import { PropsWithChildren } from "react";
6
7export const Providers = (
8 props: PropsWithChildren<{
9 initialState?: AlchemyAccountsProviderProps["initialState"];
10 }>,
11) => {
12 return (
13 <QueryClientProvider client={queryClient}>
14 <AlchemyAccountProvider
15 config={config}
16 queryClient={queryClient}
17 initialState={props.initialState}
18 >
19 {props.children}
20 </AlchemyAccountProvider>
21 </QueryClientProvider>
22 );
23};

Update your layout.tsx

app/layout.tsx
1import { config } from "@/config";
2import { cookieToInitialState } from "@account-kit/core";
3import type { Metadata } from "next";
4import { Inter } from "next/font/google";
5import { headers } from "next/headers";
6import "./globals.css";
7import { Providers } from "./providers";
8
9const inter = Inter({ subsets: ["latin"] });
10
11export const metadata: Metadata = {
12 title: "My App with Embedded Wallets",
13 description: "My app with Alchemy Smart Wallets integration",
14};
15
16export default function RootLayout({
17 children,
18}: Readonly<{
19 children: React.ReactNode;
20}>) {
21 const initialState = cookieToInitialState(
22 config,
23 headers().get("cookie") ?? undefined,
24 );
25
26 return (
27 <html lang="en">
28 <body className={inter.className}>
29 <Providers initialState={initialState}>{children}</Providers>
30 </body>
31 </html>
32 );
33}

5. Add authentication to your app

Now you can use the Alchemy React components to add wallet authentication anywhere in your app.

Example page with login functionality

app/page.tsx
1"use client";
2import {
3 useAuthModal,
4 useLogout,
5 useSignerStatus,
6 useUser,
7} from "@account-kit/react";
8
9export default function Home() {
10 const user = useUser();
11 const { openAuthModal } = useAuthModal();
12 const signerStatus = useSignerStatus();
13 const { logout } = useLogout();
14
15 return (
16 <main className="flex min-h-screen flex-col items-center p-24 gap-4 justify-center text-center">
17 {signerStatus.isInitializing ? (
18 <>Loading...</>
19 ) : user ? (
20 <div className="flex flex-col gap-2 p-2">
21 <p className="text-xl font-bold">Success!</p>
22 You're logged in as {user.email ?? "anon"}.
23 <button
24 className="akui-btn akui-btn-primary mt-6"
25 onClick={() => logout()}
26 >
27 Log out
28 </button>
29 </div>
30 ) : (
31 <button className="akui-btn akui-btn-primary" onClick={openAuthModal}>
32 Login
33 </button>
34 )}
35 </main>
36 );
37}

6. Test your integration

  1. Start your development server
  2. Navigate to your app in the browser
  3. Click the “Login” button
  4. Try authenticating with different methods (email, social login, etc.)
  5. Once authenticated, you should see the success message with the user’s information

Congratulations! You now have embedded smart wallets working in your React application.

What’s next?

Now that you have basic authentication working, you can explore additional features: