Server Side Rendering

When using the React hooks exported by Account Kit in a server-side rendered setting, you will see inconsistencies of the user state between the server and the client. This will lead to flashes of content when a user is logged in. To avoid this, the account state can be optimistically loaded on the server and passed to the client.

To enable this setting, you can set ssr: true when creating a config. We also make the config a function, so that we can call it once per request which allows for request-based isolation of the account state.

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
} from "@account-kit/react";
import {
const sepolia: Chain
sepolia
,
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
({
// required
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
({
rpcUrl: string
rpcUrl
: "/api/rpc" }),
chain: Chain
chain
:
const sepolia: Chain
sepolia
,
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,
});

This setting will defer hydration of the account state to the client after the initial mount.

Persisting the Account State

To consistently pass the state between the server and the client, you can pass in a cookie storage to the config object created above. The cookie storage allows the client state to be written serialized to a cookie which can be passed along to the server on each request. This allows the server to have access to certain parts of the account state when rendering, ensuring a consistent render between client and server (eg. user’s address displayed in the top nav). Instances which can only be created on the client will still not be available on the server, however. This includes the signer or smart contract account instances.

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 {
const sepolia: Chain
sepolia
,
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";
import {
class QueryClient
QueryClient
} from "@tanstack/react-query";
export const
const queryClient: QueryClient
queryClient
= new
new QueryClient(config?: QueryClientConfig): QueryClient
QueryClient
();
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
({
// required
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
({
rpcUrl: string
rpcUrl
: "/api/rpc" }),
chain: Chain
chain
:
const sepolia: Chain
sepolia
,
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
,
});

Now, depending on your application, you can get the state from cookies and pass in the initialState to the AlchemyAccountProvider to hydrate the account state on the client.

Next.js App Directory

If you are using NextJS App Directory, you can read the cookie state and pass it to the providers like so:

import React from "react";
import { 
function cookieToInitialState(config: AlchemyAccountsConfig, cookie?: string): StoredState | undefined

Converts a cookie into an initial state object

cookieToInitialState
} from "@account-kit/core";
import type {
import Metadata
Metadata
} from "next";
import {
import Inter
Inter
} from "next/font/google";
import {
import headers
headers
} from "next/headers";
import {
import config
config
} from "./config";
import "./globals.css"; import {
import Providers
Providers
} from "./providers";
const
const inter: any
inter
=
import Inter
Inter
({
subsets: string[]
subsets
: ["latin"] });
export const
const metadata: Metadata
metadata
:
import Metadata
Metadata
= {
title: string
title
: "Embedded Accounts Getting Started",
description: string
description
: "Embedded Accounts Quickstart Guide",
}; export default function
function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>): JSX.Element
RootLayout
({
children: React.ReactNode
children
,
}:
type Readonly<T> = { readonly [P in keyof T]: T[P]; }

Make all properties in T readonly

Readonly
<{
children: React.ReactNode
children
: React.
type React.ReactNode = string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<...> | null | undefined

Represents all of the things React can render.

Where ReactElement only represents JSX, ReactNode represents everything that can be rendered.

ReactNode
;
}>) { // This will allow us to persist state across page boundaries const
const initialState: StoredState | undefined
initialState
=
function cookieToInitialState(config: AlchemyAccountsConfig, cookie?: string): StoredState | undefined

Converts a cookie into an initial state object

cookieToInitialState
(
// the config here is just used to compute the initial state
import config
config
(),
import headers
headers
().
any
get
("cookie") ??
var undefined
undefined
,
); return ( <
React.JSX.IntrinsicElements.html: React.DetailedHTMLProps<React.HtmlHTMLAttributes<HTMLHtmlElement>, HTMLHtmlElement>
html
React.HTMLAttributes<HTMLHtmlElement>.lang?: string | undefined
lang
="en">
<
React.JSX.IntrinsicElements.body: React.DetailedHTMLProps<React.HTMLAttributes<HTMLBodyElement>, HTMLBodyElement>
body
React.HTMLAttributes<HTMLBodyElement>.className?: string | undefined
className
={
const inter: any
inter
.
any
className
}>
<
import Providers
Providers
initialState: StoredState | undefined
initialState
={
const initialState: StoredState | undefined
initialState
}>{
children: React.ReactNode
children
}</
import Providers
Providers
>
</
React.JSX.IntrinsicElements.body: React.DetailedHTMLProps<React.HTMLAttributes<HTMLBodyElement>, HTMLBodyElement>
body
>
</
React.JSX.IntrinsicElements.html: React.DetailedHTMLProps<React.HtmlHTMLAttributes<HTMLHtmlElement>, HTMLHtmlElement>
html
>
); }
"use client";

import React, { 
function useRef<T>(initialValue: T): React.RefObject<T> (+2 overloads)

useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

Note that useRef() is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.

useRef
} from "react";
import {
type AlchemyClientState = { alchemy: Omit<StoreState, "signer" | "accounts" | "bundlerClient">; wagmi?: State; }
AlchemyClientState
} from "@account-kit/core";
import {
const AlchemyAccountProvider: (props: React.PropsWithChildren<AlchemyAccountsProviderProps>) => JSX.Element

Provider for Alchemy accounts.

AlchemyAccountProvider
,
type
type AlchemyAccountsConfigWithUI = AlchemyAccountsConfig & { ui?: AlchemyAccountsUIConfig; }
AlchemyAccountsConfigWithUI
,
} from "@account-kit/react"; import {
const QueryClientProvider: ({ client, children, }: QueryClientProviderProps) => React.JSX.Element
QueryClientProvider
} from "@tanstack/react-query";
import {
type PropsWithChildren<P = unknown> = P & { children?: React.ReactNode | undefined; }
PropsWithChildren
,
const Suspense: React.ExoticComponent<React.SuspenseProps>

Lets you display a fallback until its children have finished loading.

Suspense
} from "react";
import {
import config
config
,
import queryClient
queryClient
} from "./config";
export const
const Providers: (props: PropsWithChildren<{ initialState?: AlchemyClientState; }>) => JSX.Element
Providers
= (
props: React.PropsWithChildren<{ initialState?: AlchemyClientState; }>
props
:
type PropsWithChildren<P = unknown> = P & { children?: React.ReactNode | undefined; }
PropsWithChildren
<{
initialState?: StoredState | undefined
initialState
?:
type AlchemyClientState = { alchemy: Omit<StoreState, "signer" | "accounts" | "bundlerClient">; wagmi?: State; }
AlchemyClientState
}>,
) => { const
const ref: React.RefObject<AlchemyAccountsConfigWithUI>
ref
=
useRef<AlchemyAccountsConfigWithUI>(initialValue: AlchemyAccountsConfigWithUI): React.RefObject<AlchemyAccountsConfigWithUI> (+2 overloads)

useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

Note that useRef() is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.

useRef
<
type AlchemyAccountsConfigWithUI = AlchemyAccountsConfig & { ui?: AlchemyAccountsUIConfig; }
AlchemyAccountsConfigWithUI
>();
if (!
const ref: React.RefObject<AlchemyAccountsConfigWithUI>
ref
.
React.RefObject<AlchemyAccountsConfigWithUI>.current: AlchemyAccountsConfigWithUI

The current value of the ref.

current
) {
const ref: React.RefObject<AlchemyAccountsConfigWithUI>
ref
.
React.RefObject<AlchemyAccountsConfigWithUI>.current: AlchemyAccountsConfigWithUI

The current value of the ref.

current
=
import config
config
();
} return ( <
const Suspense: React.ExoticComponent<React.SuspenseProps>

Lets you display a fallback until its children have finished loading.

Suspense
>
<
const QueryClientProvider: ({ client, children, }: QueryClientProviderProps) => React.JSX.Element
QueryClientProvider
client: QueryClient
client
={
import queryClient
queryClient
}>
<
const AlchemyAccountProvider: (props: React.PropsWithChildren<AlchemyAccountsProviderProps>) => JSX.Element

Provider for Alchemy accounts.

AlchemyAccountProvider
config: AlchemyAccountsConfigWithUI
config
={
const ref: React.RefObject<AlchemyAccountsConfigWithUI>
ref
.
React.RefObject<AlchemyAccountsConfigWithUI>.current: AlchemyAccountsConfigWithUI

The current value of the ref.

current
!}
queryClient: QueryClient
queryClient
={
import queryClient
queryClient
}
initialState?: StoredState | undefined
initialState
={
props: React.PropsWithChildren<{ initialState?: AlchemyClientState; }>
props
.
initialState?: StoredState | undefined
initialState
}
> {
props: React.PropsWithChildren<{ initialState?: AlchemyClientState; }>
props
.
children?: React.ReactNode
children
}
</
const AlchemyAccountProvider: (props: React.PropsWithChildren<AlchemyAccountsProviderProps>) => JSX.Element

Provider for Alchemy accounts.

AlchemyAccountProvider
>
</
const QueryClientProvider: ({ client, children, }: QueryClientProviderProps) => React.JSX.Element
QueryClientProvider
>
</
const Suspense: React.ExoticComponent<React.SuspenseProps>

Lets you display a fallback until its children have finished loading.

Suspense
>
); };
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 {
const sepolia: Chain
sepolia
,
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";
import {
class QueryClient
QueryClient
} from "@tanstack/react-query";
export const
const queryClient: QueryClient
queryClient
= new
new QueryClient(config?: QueryClientConfig): QueryClient
QueryClient
();
// When using SSR, you need to be able to create a config per request // This is to avoid sharing state between requests (eg. signed in users) 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
({
rpcUrl: string
rpcUrl
: "/api/rpc" }),
chain: Chain
chain
:
const sepolia: Chain
sepolia
,
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
,
});

Next.js Pages Directory

Coming soon!

Vanilla SSR

Coming soon!