User metadata
To store information about a user that Clerk doesn't collect, you can use metadata, which will get stored on the user's User object.
Types of metadata
There are three types of metadata: "public", "private", and "unsafe".
Public metadata
Public metadata can be read by both the frontend and the backend, but can only be set on the backend. This is useful for storing data that you want to expose to the frontend, but don't want the user to be able to modify. For example, you could store a user's birthday.
Access public metadata
To access public metadata on the frontend, it's available on the User object, which can be accessed using the useUser() hook.
To access public metadata on the backend, it's available on the Backend User object which can be accessed using the getUser() method. This method will return the User object which contains the public metadata. However, this method is subject to rate limits, so if you are accessing the metadata frequently, it's recommended to attach it to the user's session token.
Set public metadata
To set public metadata, see the updateUserMetadata() reference.
Private metadata
Private metadata can only be read and set by the backend and webhook handlers, which makes this useful for storing sensitive data that you don't want to expose to the frontend. For example, you could store a user's Stripe customer ID.
Access private metadata
To access private metadata on the backend, it's available on the Backend User object which can be accessed using the getUser() method. This method will return the User object which contains the private metadata. However, this method is subject to rate limits, so if you are accessing the metadata frequently, it's recommended to attach it to the user's session token.
Set private metadata
To set private metadata, see the updateUserMetadata() reference.
Unsafe metadata
Unsafe metadata can be both read and set from the frontend and the backend. It's called "unsafe" metadata because it can be modified directly from the frontend, which means malicious users could potentially tamper with these values.
Unsafe metadata is the only metadata property that can be set during sign-up, so a common use case is to use it in custom onboarding flows. Custom data collected during the onboarding (sign-up) flow can be stored in the SignUpSignUp.unsafeMetadata is copied to the User object as User.unsafeMetadata. From that point on, the unsafe metadata is accessible as a direct attribute of the User object.
Access unsafe metadata
To access unsafe metadata on the frontend, it's available on the User
To access unsafe metadata on the backend, it's available on the Backend UserUser object which contains the unsafe metadata. However, this method is subject to rate limits, so if you are accessing the metadata frequently, it's recommended to attach it to the user's session token.
Set unsafe metadata
See the following examples to see how to set unsafe metadata on the frontend (client-side) and backend (server-side).
For React-based SDKs, such as Next.js, use the useUser() hook to update unsafe metadata.
export default function Page() {
  const { user } = useUser()
  const [birthday, setBirthday] = useState('')
  return (
    <div>
      <input type="text" value={birthday} onChange={(e) => setBirthday(e.target.value)} />
      <button
        onClick={() => {
          user?.update({
            unsafeMetadata: { birthday },
          })
        }}
      >
        Update birthday
      </button>
    </div>
  )
}When using the JavaScript SDK, use the User.update()
import { Clerk } from '@clerk/clerk-js'
// Initialize Clerk with your Clerk Publishable Key
const pubKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY
const clerk = new Clerk(pubKey)
await clerk.load()
if (clerk.isSignedIn) {
  await clerk.user
    .update({
      unsafeMetadata: {
        birthday: '01-01-2000',
      },
    })
    .then((res) => console.log(res))
    .catch((error) => console.log('An error occurred:', error.errors))
} else {
  document.getElementById('app').innerHTML = `
    <div id="sign-in"></div>
  `
  const signInDiv = document.getElementById('sign-in')
  clerk.mountSignIn(signInDiv)
}To update unsafe metadata on the server-side, see the updateUserMetadata()
Metadata in the session token
Retrieving metadata from the User object on the server-side requires making an API request to Clerk's Backend API, which is slower and is subject to rate limits. You can store it in the user's session token, which doesn't require making an API request as it's available on the user's authentication context. However, there is a size limitation to keep in mind. Clerk stores the session token in a cookie, and most browsers cap cookie size at 4KB. After accounting for the size of Clerk's default claims, the cookie can support up to 1.2KB of custom claims. Exceeding this limit will cause the cookie to not be set, which will break your app as Clerk depends on cookies to work properly.
If you need to store more than 1.2KB of metadata, you should store the extra data in your own database instead. If this isn't an option, you can move particularly large claims out of the token and fetch them using a separate API call from your backend, but this approach brings back the issue of making an API request to Clerk's Backend API, which is slower and is subject to rate limits.
Another limitation of storing metadata in the session token is that when you modify metadata server-side, the changes won't appear in the session token until the next refresh. To avoid race conditions, either force a JWT refresh after metadata changes or handle the delay in your application logic.
If you've considered the limitations, and you still want to store metadata in the session token:
- In the Clerk Dashboard, navigate to the Sessions page.
- Under Customize session token, in the Claims editor, you can add any claim to your session token that you need and select Save. To avoid exceeding the session token's 1.2KB limit, it's not recommended to add the entire user.public_metadataobject. Instead, add individual fields as claims, likeuser.public_metadata.birthday. When doing this, it's recommended to leave particularly large claims out of the token to avoid exceeding the session token's size limit. See the example for more information.
Feedback
Last updated on