> ## 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.

# Displaying & Updating User Info

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

#### Show user profile information

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](/react-native/users/displaying-updating#working-with-user-metadata).**

#### Allow user to update their profile information

**How:** `client.auth.updateUser` and `client.auth.verifyUserUpdateOtp`

**Method:** [client.auth.updateUser](/react-native/reference/package-references/client#auth-module)

**Notes:** `updateUser` returns flags to indicate whether OTP is required for the change (`isEmailVerificationRequired` and `isSmsVerificationRequired`). Available from v4.38.0.

### Updating Email

```typescript React Native theme={"system"}
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

```typescript React Native theme={"system"}
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();
};
```

### Updating Meta

```typescript React Native theme={"system"}
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

```typescript React Native theme={"system"}
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:

```typescript React Native theme={"system"}
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

## Working with User Metadata

**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.

### What is Metadata?

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)

### Metadata Examples

```typescript theme={"system"}
// 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

<Tip>
  For how to add metadata to the user and update it, see [Custom Information Capture](/react-native/custom-fields/overview).
</Tip>

* 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.
