Skip to main content

Using our UI

The Dynamic Widget UI component and Dynamic Embedded Widget UI component both contain a user profile section where the user can see their profile information and update it easily. You can check it out at https://demo.dynamic.xyz/.

Using your UI

This guide will help you to create a completely headless user profile including everything you see in the regular Dynamic Widget UI component/Dynamic Embedded Widget UI component described above.

Prerequisites

Like with all this series of headless guides, “headless” is defined a way to use the Dynamic SDK without the need for Dynamic UI components (i.e. DynamicWidget, DynamicUserProfile). You still need to add the SDK and set up the Dynamic Context Provider (complete the quickstart if you haven’t done so already, or refer to an example app)

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
  • React
React provides the useIsLoggedIn hook to check authentication status and conditionally render components.
React
import { useIsLoggedIn } from "@dynamic-labs/sdk-react-core";

const isLoggedIn = useIsLoggedIn();

return <>{isLoggedIn ? <Profile /> : </Login>}</>

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
React provides the useDynamicContext hook to access user information and display profile details.
React
import { useDynamicContext } from "@dynamic-labs/sdk-react-core";

const { user } = useDynamicContext();

return (
  <div className="user-details">
    {user?.firstName && <p>First name: {user.firstName} </p>}
    {user?.email && <p>E-Mail: {user.email} </p>}
    {user?.alias && <p>Alias: {user.alias} </p>}
    {user?.lastName && <p>Last name: {user.lastName} </p>}
    {user?.jobTitle && <p>Job: {user.jobTitle} </p>}
    {user?.phoneNumber && <p>Phone: {user.phoneNumber} </p>}
    {user?.tShirtSize && <p>Tshirt size: {user.tShirtSize} </p>}
    {user?.team && <p>Team: {user.team} </p>}
    {user?.country && <p>Country: {user.country} </p>}
    {user?.username && <p>Username: {user.username} </p>}
    {user?.metadata && Object.keys(user.metadata).length > 0 && (
      <div>
        <h4>Custom Metadata Fields:</h4>
        <p><em>Additional user data and preferences stored in metadata</em></p>
        {Object.entries(user.metadata).map(([key, value]) => (
          <p key={key}><strong>{key}:</strong> {String(value)}</p>
        ))}
      </div>
    )}
  </div>
);

Allow user to update their profile information

  • React
  • React Native
How: useUserUpdateRequest and useOtpVerificationRequestHook/Component: useUserUpdateRequestNotes: Use the appropriate verification flag: isEmailVerificationRequired for email changes; isSmsVerificationRequired for phone changes. Metadata updates and general text fields typically do not require OTP.

Updating Email

React
import { useUserUpdateRequest, useOtpVerificationRequest } from "@dynamic-labs/sdk-react-core";
import { useState } from "react";

const { updateUser } = useUserUpdateRequest();
const { verifyOtp } = useOtpVerificationRequest();

const [showVerifyEmailForm, setShowVerifyEmailForm] = useState(false);
const [loading, setLoading] = useState(false);

const onSubmitEmailUpdate = async (firstName: string, email: string, metadata?: Record<string, any>) => {
  try {
    setLoading(true);
    const { isEmailVerificationRequired } = await updateUser({ firstName, email, metadata });
    if (isEmailVerificationRequired) setShowVerifyEmailForm(true);
  } finally {
    setLoading(false);
  }
};

const onVerifyEmailOtp = async (verificationToken: string) => {
  try {
    setLoading(true);
    await verifyOtp(verificationToken); // Uses active email verification context
  } finally {
    setLoading(false);
    setShowVerifyEmailForm(false);
  }
};

Updating Phone

React
import { useUserUpdateRequest, useOtpVerificationRequest } from "@dynamic-labs/sdk-react-core";
import { useState } from "react";

const { updateUser } = useUserUpdateRequest();
const { verifyOtp } = useOtpVerificationRequest();

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
    const { isSmsVerificationRequired } = await updateUser({ firstName, phoneNumber, metadata });
    if (isSmsVerificationRequired) setShowVerifySmsForm(true);
  } finally {
    setLoading(false);
  }
};

const onVerifySmsOtp = async (verificationToken: string) => {
  try {
    setLoading(true);
    await verifyOtp(verificationToken); // Uses active SMS verification context
  } finally {
    setLoading(false);
    setShowVerifySmsForm(false);
  }
};

Updating Meta

React
import { useUserUpdateRequest } from "@dynamic-labs/sdk-react-core";

const { updateUser } = useUserUpdateRequest();

const onSubmitMetadataOnly = async (metadata: Record<string, any>) => {
  // Updating only metadata typically does not require OTP
  await updateUser({ metadata });
};

Updating General

React
import { useUserUpdateRequest } from "@dynamic-labs/sdk-react-core";

const { updateUser } = useUserUpdateRequest();

const onSubmitGeneral = async (fields: { firstName?: string; lastName?: string; username?: string }) => {
  // General fields (no email/phone change) typically do not require OTP
  await updateUser(fields);
};

Socials

Show users linked social accounts, allow linking/unlinking

How: useSocialAccounts hook from sdk-react-core Hook/Component: useSocialAccounts Notes: None
  • React
React provides the useSocialAccounts hook to manage social account linking and unlinking with a comprehensive UI component.
React
import { useSocialAccounts } from "@dynamic-labs/sdk-react-core";
import { SocialIcon } from '@dynamic-labs/iconic';

const Avatar = ({ avatarUrl }) => {
  return (
    <div className="avatar">
      <img src={avatarUrl} alt="avatar" />
    </div>
  );
};


const Icon = ({ provider }) => {
  return (
    <div className="icon-container">
    <SocialIcon name={provider} />
    </div>
  );
};

const UserProfileSocialAccount = ({ provider }) => {
  const {
    linkSocialAccount,
    unlinkSocialAccount,
    isProcessing,
    isLinked,
    getLinkedAccountInformation,
  } = useSocialAccounts();

  const isProviderLinked = isLinked(provider);
  const connectedAccountInfo = getLinkedAccountInformation(provider);

  return (
    <div className="social-account">
      <div className="icon">
        {isProviderLinked ? (
          <Avatar avatarUrl={connectedAccountInfo?.avatar} />
        ) : (
          <Icon provider={provider} />
        )}
      </div>
      <div className="label">
        <p>{isProviderLinked ? connectedAccountInfo?.publicIdentifier : provider}</p>
      </div>
      {isProviderLinked ? (
        <button
          onClick={() => unlinkSocialAccount(provider)}
          disabled={isProcessing}
        >
          Disconnect
        </button>
      ) : (
        <button
          onClick={() => linkSocialAccount(provider)}
          disabled={isProcessing}
        >
          Connect
        </button>
      )}
    </div>
  );
};

const Socials = () => {
  const providers = [
    "discord",
    "facebook",
    "github",
    "google",
    "instagram",
    "twitch",
    "twitter",
  ];

  return (
    <div className="social-accounts">
      {providers.map((provider) => (
        <UserProfileSocialAccount key={provider} provider={provider} />
      ))}
    </div>
  );
};

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

// 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
For how to add metadata to the user and update it, see Custom Information Capture.
  • 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.