> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# User profile & settings

> Display the signed-in user, edit profile fields, verify email or phone changes, and delete the account.

## Prerequisites

Before this page: a signed-in user (see [Email & SMS OTP sign-in](/docs/javascript/building-ui/email-sms-otp-sign-in)).

## What you'll build

* **Display** the current user's profile.
* **Edit** profile fields like name and username.
* **Verify** a new email or phone number with a one-time code.
* **Delete** the account.

## Reading the profile

`useUser` returns a query result (`{ data: user, ... }`) that re-renders on any change — read the user from `data`. Outside React, read `getDefaultClient().user`.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={"system"}
    import { getDefaultClient } from '@dynamic-labs-sdk/client';

    function renderProfile(el: HTMLElement) {
      const user = getDefaultClient().user;
      if (!user) return;
      el.textContent = `${user.firstName ?? ''} ${user.lastName ?? ''}`.trim();
    }
    ```
  </Tab>

  <Tab title="React">
    ```tsx theme={"system"}
    import { useUser } from '@dynamic-labs-sdk/react-hooks';

    function Profile() {
      const { data: user } = useUser();
      if (!user) return null;
      return <p>{`${user.firstName ?? ''} ${user.lastName ?? ''}`.trim()}</p>;
    }
    ```
  </Tab>
</Tabs>

## Updating profile fields

`updateUser` accepts the fields you want to change. Most fields save immediately. Changing **email** or **phone number** returns an `OTPVerification` — prompt for the code and confirm it with `verifyOTP`.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={"system"}
    import { updateUser, verifyOTP } from '@dynamic-labs-sdk/client';
    import type { UpdateUserFields } from '@dynamic-labs-sdk/client';

    async function saveProfile(userFields: UpdateUserFields) {
      const otpVerification = await updateUser({ userFields });

      // No verification needed — the update is already saved.
      if (!otpVerification) return;

      // The code is sent to whichever contact changed: `email` is set for an
      // email change, `phoneNumber` (with country code) for a phone change.
      const sentToEmail = Boolean(otpVerification.email);
      const destination = sentToEmail
        ? otpVerification.email
        : `${otpVerification.phoneCountryCode ?? ''}${otpVerification.phoneNumber ?? ''}`;

      // promptForCode is your implementation — tell the user where to look.
      const verificationToken = await promptForCode(destination);
      await verifyOTP({ otpVerification, verificationToken });
    }
    ```
  </Tab>

  <Tab title="React">
    ```tsx theme={"system"}
    import { verifyOTP } from '@dynamic-labs-sdk/client';
    import { useUpdateUser } from '@dynamic-labs-sdk/react-hooks';

    function EditProfile() {
      const { mutateAsync: update, isPending } = useUpdateUser();

      return (
        <form
          onSubmit={async (event) => {
            event.preventDefault();
            const form = new FormData(event.currentTarget);
            const otpVerification = await update({
              userFields: {
                firstName: String(form.get('firstName')),
                username: String(form.get('username')),
              },
            });
            if (otpVerification) {
              // `email` is set for an email change, `phoneNumber` for a phone change.
              const destination =
                otpVerification.email ?? otpVerification.phoneNumber;
              // promptForCode is your implementation — tell the user where to look.
              const verificationToken = await promptForCode(destination);
              await verifyOTP({ otpVerification, verificationToken });
            }
          }}
        >
          <input name="firstName" />
          <input name="username" />
          <button type="submit" disabled={isPending}>Save</button>
        </form>
      );
    }
    ```
  </Tab>
</Tabs>

<Note>
  Only send the fields you actually changed. Updatable fields include `firstName`, `lastName`, `username`, `alias`, `email`, `phoneNumber`, `country`, and `metadata`.
</Note>

## Deleting the account

Offer account deletion from settings. Confirm clearly first — it's irreversible.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={"system"}
    import { deleteUser } from '@dynamic-labs-sdk/client';

    async function removeAccount() {
      // confirmDeletion is your implementation — require an explicit confirmation.
      if (!(await confirmDeletion())) return;
      await deleteUser();
    }
    ```
  </Tab>

  <Tab title="React">
    ```tsx theme={"system"}
    import { useState } from 'react';
    import { useDeleteUser } from '@dynamic-labs-sdk/react-hooks';

    function DeleteAccount() {
      const { mutateAsync: remove, isPending } = useDeleteUser();
      const [confirmed, setConfirmed] = useState(false);

      if (!confirmed) {
        return (
          <button type="button" onClick={() => setConfirmed(true)}>
            Delete account
          </button>
        );
      }

      return (
        <div>
          <p>This is permanent. Delete your account?</p>
          <button type="button" onClick={() => setConfirmed(false)}>
            Cancel
          </button>
          <button type="button" disabled={isPending} onClick={() => remove()}>
            {isPending ? 'Deleting…' : 'Confirm delete'}
          </button>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

## Handling errors

| Situation                                 | What to do                                                                       |
| ----------------------------------------- | -------------------------------------------------------------------------------- |
| `updateUser` returns an `OTPVerification` | Email/phone changed — collect the code and call `verifyOTP` to confirm.          |
| Wrong verification code                   | `verifyOTP` rejects — ask the user to re-enter the code sent to the new contact. |
| Username/email already taken              | Surface the field-level error and let the user pick another value.               |
| Account deletion confirmed                | The user is signed out — route them to your signed-out landing page.             |

## See also

* [Account merging](/docs/javascript/building-ui/account-merging) — combine two accounts into one
* Step-up authentication — require MFA before a profile update
* [Post-login user setup](/docs/javascript/building-ui/post-auth-user-setup) — collect required profile fields right after sign-in
