A wallet your users control. No seed phrase required.
Sign in with email, social, passkeys, or your own auth and every user gets a non-custodial MPC wallet in seconds - no seed phrase, no extension. Create wallets on any chain, read balances and history, sponsor your users' network fees, and verify sessions on your own backend - built entirely on Dynamic.
@dynamic-labs-sdk/client@dynamic-labs-sdk/react-hooksCreate the client
DocsOne Dynamic client per app, created at module scope. Chain extensions register which networks the embedded wallet supports.
lib/dynamic/client.tsimport { createDynamicClient } from "@dynamic-labs-sdk/client"; import { addEvmExtension } from "@dynamic-labs-sdk/evm"; export const client = createDynamicClient({ environmentId: process.env.NEXT_PUBLIC_DYNAMIC_ENVIRONMENT_ID!, }); addEvmExtension(client);Wrap your app for hooks
DocsThe react-hooks package reads the client from context and uses TanStack Query under the hood, so mount QueryClientProvider outside DynamicProvider once - every hook below works anywhere inside.
app/providers.tsximport { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { DynamicProvider } from "@dynamic-labs-sdk/react-hooks"; import { client } from "@/lib/dynamic/client"; const queryClient = new QueryClient(); export function Providers({ children }: { children: React.ReactNode }) { return ( <QueryClientProvider client={queryClient}> <DynamicProvider client={client}>{children}</DynamicProvider> </QueryClientProvider> ); }Sign in with an email code
DocsSend a one-time passcode and verify it. No password, no seed phrase - the session lives in the client.
components/email-login.tsximport { useSendEmailOTP, useVerifyOTP } from "@dynamic-labs-sdk/react-hooks"; const { mutate: sendOtp, data: otpVerification } = useSendEmailOTP(); const { mutate: verifyOtp } = useVerifyOTP(); sendOtp({ email }); // User types the 6-digit code from their inbox: verifyOtp({ otp: code, otpVerification });Sign in with a social account
DocsKick off the provider's OAuth flow, then complete it when the user lands back - same session, same embedded wallet.
components/social-login.tsximport { useCompleteSocialRedirect, useSignInWithSocialRedirect, } from "@dynamic-labs-sdk/react-hooks"; const { mutate: signIn } = useSignInWithSocialRedirect(); const { mutate: completeRedirect } = useCompleteSocialRedirect(); signIn({ provider: "google", redirectUrl: window.location.origin }); // ...and when the provider redirects back: completeRedirect({ url: new URL(window.location.href) });