Skip to main content
@dynamic-labs-sdk/react-hooks is a thin React layer over @dynamic-labs-sdk/client. It exposes a <DynamicProvider> and a set of hooks that subscribe to client state and re-render your components when that state changes.
The JavaScript SDK is headless — there is no built-in modal, wallet picker, or login form. You build all UI yourself. See the JavaScript SDK Overview for details.
New to the hooks? Read How React Hooks Work first — it covers the naming rule (each client function maps to a same-named use hook), which functions get a hook, and the three shapes a hook can take (query, mutation, state). This page is the reference for setup and the headline state hooks.

Installation

npm i @dynamic-labs-sdk/react-hooks
The package has @dynamic-labs-sdk/client and react as peer dependencies.

Setup

Wrap your app in DynamicProvider and pass the client instance you created with createDynamicClient:
import { DynamicProvider } from '@dynamic-labs-sdk/react-hooks';
import { dynamicClient } from './dynamicClient';

function App() {
  return (
    <DynamicProvider client={dynamicClient}>
      <YourApp />
    </DynamicProvider>
  );
}
Any hook used outside a DynamicProvider throws MissingProviderError.

State hooks

These hooks read directly from the client and re-render the component when the underlying state changes. Like all hooks in this package, they return the full TanStack Query result ({ data, isLoading, error, refetch, … }). They have no parameters. Each state hook returns the full react-query result — { data, isLoading, error, refetch, ... } — so the value you want lives on data. Destructure it: const { data: user } = useUser(). The descriptions below refer to what data holds.

useUser

data is the current authenticated user, or null if no user is signed in. Re-renders on sign-in, sign-out, and profile updates.
import { useUser } from '@dynamic-labs-sdk/react-hooks';

function ProfileBadge() {
  const { data: user } = useUser();
  if (!user) return <SignInButton />;
  return <span>{user.email ?? user.firstName}</span>;
}

useGetWalletAccounts

Returns all wallet accounts on the current session, verified and unverified. Re-renders when accounts are added, removed, or verified.
import { useGetWalletAccounts } from '@dynamic-labs-sdk/react-hooks';

function WalletList() {
  const { data: walletAccounts = [] } = useGetWalletAccounts();
  return (
    <ul>
      {walletAccounts.map((account) => (
        <li key={account.id}>
          {account.chain}: {account.address}
        </li>
      ))}
    </ul>
  );
}

useGetUserSocialAccounts

Returns the user’s linked social accounts (SocialAccount[]). Re-renders when the user changes. Empty array when no user is signed in.
import { useGetUserSocialAccounts } from '@dynamic-labs-sdk/react-hooks';

function LinkedSocials() {
  const { data: accounts = [] } = useGetUserSocialAccounts();
  return accounts.map((account) => (
    <div key={account.verifiedCredentialId}>
      {account.provider}: {account.displayName ?? account.emails[0]}
    </div>
  ));
}
See Social Account Linking for the management APIs.

useGetAvailableWalletProvidersData

Returns the wallet providers available to connect and their metadata (WalletProviderData[]). Re-renders when the available providers change (for example on a network switch).
import { useGetAvailableWalletProvidersData } from '@dynamic-labs-sdk/react-hooks';

function AvailableWallets() {
  const { data: providers = [] } = useGetAvailableWalletProvidersData();
  return providers.map((provider) => (
    <button key={provider.key}>Connect {provider.metadata.name}</button>
  ));
}

useInitStatus

Returns the client’s initialization status: 'uninitialized' | 'in-progress' | 'finished' | 'failed'. Use this to gate UI that depends on SDK methods until the client is ready.
import { useInitStatus } from '@dynamic-labs-sdk/react-hooks';

function Bootstrap({ children }) {
  const { data: initStatus } = useInitStatus();
  if (initStatus !== 'finished') return <Splash />;
  return children;
}
See Initializing the Dynamic Client for init-status semantics.

useSessionExpiresAt

Returns the session expiration Date, or null if there is no active session. Re-renders on session updates.
import { useSessionExpiresAt } from '@dynamic-labs-sdk/react-hooks';

function SessionCountdown() {
  const { data: expiresAt } = useSessionExpiresAt();
  if (!expiresAt) return null;
  return <span>Session ends at {expiresAt.toLocaleTimeString()}</span>;
}

Event hook

useOnEvent

Subscribes to any client event for the lifetime of the component. The subscription is cleaned up on unmount or when the event name changes. The listener is wrapped in a ref, so updating its identity between renders does not re-subscribe.
import { useOnEvent } from '@dynamic-labs-sdk/react-hooks';

function LogoutLogger() {
  useOnEvent({
    event: 'logout',
    listener: ({ reason } = {}) => {
      console.log('Logged out:', reason);
    },
  });
  return null;
}
The listener signature is inferred from the event name. See the Events Catalog for the full event surface. For state-change events (userChanged, walletAccountsChanged, tokenChanged, etc.) prefer the dedicated state hooks above — they subscribe for you and avoid manual subscription bookkeeping.

Client access

useDynamicClient

Returns the DynamicClient instance from context. Throws MissingProviderError if used outside a DynamicProvider. Most code should not need this — use the state hooks for reactive state, and import client functions directly (signMessage, getMultichainTokenBalances, etc.) for one-shot calls.
import { useDynamicClient } from '@dynamic-labs-sdk/react-hooks';

function ClientDebugger() {
  const client = useDynamicClient();
  return <pre>{JSON.stringify(client.initStatus, null, 2)}</pre>;
}

Multiple clients

If your app uses more than one Dynamic client, mount a separate DynamicProvider for each subtree. Hooks resolve the closest provider, so state from one client never leaks into a tree wrapped in a different one.
Last modified on June 26, 2026