Documentation Index
Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
Use this file to discover all available pages before exploring further.
This guide will help you to create a user profile inside your own custom UI, including everything you see in the Dynamic SDK UI (client/WebView flow) described above.
Setup
Show the user’s profile based on whether they are logged in or not
How: Check if the user is logged in or not
Hook/Component: useIsLoggedIn
Notes: We start here assuming you have signup/login implemented already
Profile Info
How: Fetch info from user object on useDynamicContext
Hook/Component: useDynamicContext
Notes: The format of the user can be found here: userProfile. For working with custom metadata fields and storing additional user data, see User Metadata.
How: client.auth.updateUser and client.auth.verifyUserUpdateOtp
Method: client.auth.updateUser
Notes: updateUser returns flags to indicate whether OTP is required for the change (isEmailVerificationRequired and isSmsVerificationRequired). Available from v4.38.0.
Updating Email
import { client } from './dynamicClient';
import { useState } from 'react';
const [showVerifyEmailForm, setShowVerifyEmailForm] = useState(false);
const [loading, setLoading] = useState(false);
const onSubmitEmailUpdate = async (firstName: string, email: string, metadata?: Record<string, any>) => {
try {
setLoading(true);
// OTP is automatically sent to the new email when updateUser is called
const result = await client.auth.updateUser({ firstName, email, metadata });
if (result.isEmailVerificationRequired) setShowVerifyEmailForm(true);
} finally {
setLoading(false);
}
};
const onVerifyEmailFormSubmit = async (verificationToken: string) => {
try {
setLoading(true);
await client.auth.verifyUserUpdateOtp(verificationToken);
} finally {
setLoading(false);
setShowVerifyEmailForm(false);
}
};
// Resend if needed
const resendEmailOtp = async () => {
await client.auth.email.resendOTP();
};
Updating Phone
import { client } from './dynamicClient';
import { useState } from 'react';
const [showVerifySmsForm, setShowVerifySmsForm] = useState(false);
const [loading, setLoading] = useState(false);
const onSubmitPhoneUpdate = async (firstName: string, phoneNumber: string, metadata?: Record<string, any>) => {
try {
setLoading(true);
// phoneNumber should be E.164 format, e.g. +14155551234
// OTP is automatically sent to the new phone when updateUser is called
const result = await client.auth.updateUser({ firstName, phoneNumber, metadata });
if (result.isSmsVerificationRequired) setShowVerifySmsForm(true);
} finally {
setLoading(false);
}
};
const onVerifySmsFormSubmit = async (verificationToken: string) => {
try {
setLoading(true);
await client.auth.verifyUserUpdateOtp(verificationToken);
} finally {
setLoading(false);
setShowVerifySmsForm(false);
}
};
// Resend if needed
const resendSmsOtp = async () => {
await client.auth.sms.resendOTP();
};
import { client } from './dynamicClient';
const onSubmitMetadataOnly = async (metadata: Record<string, any>) => {
// Updating only metadata typically does not require OTP
await client.auth.updateUser({ metadata });
};
Updating General
import { client } from './dynamicClient';
const onSubmitGeneral = async (fields: { firstName?: string; lastName?: string; username?: string }) => {
// General fields (no email/phone change) typically do not require OTP
await client.auth.updateUser(fields);
};
Alternatively, you can use the Dynamic UI modal for a simpler integration:
import { client } from './dynamicClient';
const showUpdateUserModal = async () => {
try {
const updatedFields = await client.ui.updateUser.show({
fields: ['firstName', 'email', 'metadata'],
});
console.log('User updated:', updatedFields);
} catch (error) {
console.error('User cancelled or error occurred:', error);
}
};
Socials
Show users linked social accounts, allow linking/unlinking
How: useSocialAccounts hook from sdk-react-core
Hook/Component: useSocialAccounts
Notes: None
User metadata provides a powerful way to store additional information beyond the standard profile fields. This is perfect for storing user preferences, application state, custom attributes, and integration data.
Metadata is a flexible key-value storage system that allows you to:
- Store user preferences (theme, language, notification settings)
- Track application state (onboarding progress, feature flags)
- Store business-specific data (subscription tiers, referral codes)
- Maintain integration data (external service IDs, webhook configs)
// User preferences
metadata: {
theme: 'dark',
language: 'en',
notifications_enabled: true
}
// Application state
metadata: {
onboarding_completed: true,
feature_flags: ['beta_features', 'advanced_analytics']
}
// Business data
metadata: {
subscription_tier: 'premium',
referral_code: 'USER123',
last_purchase_date: '2024-01-15'
}
Best Practices
- Size limit: Metadata is limited to 2KB total
- Key naming: Use descriptive, lowercase keys with underscores
- Value types: Supports strings, numbers, booleans, and nested objects
- Validation: Always validate on your backend before storing
- Updated the “Allow user to update their profile information” section with distinct “Updating Email”, “Updating Phone”, “Updating Meta”, and “Updating General” subsections for both React and React Native, and used
isSmsVerificationRequired for phone updates.