User metadata
Metadata allows for custom data to be saved on the User
object. There are three types of metadata: "unsafe", "public", and "private".
Metadata | Frontend API | Backend API |
---|---|---|
Private | No read or write access | Read & write access |
Public | Read access | Read & write access |
Unsafe | Read & write access | Read & write access |
Private metadata
Private metadata is only accessible by the backend, 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.
Set private metadata
import { NextRequest, NextResponse } from 'next/server'
import { clerkClient } from '@clerk/nextjs/server'
export async function POST(request: NextRequest) {
const { stripeId, userId } = await request.json()
const client = await clerkClient()
await client.users.updateUserMetadata(userId, {
privateMetadata: {
stripeId: stripeId,
},
})
return NextResponse.json({ success: true })
}
import { clerkClient } from '@clerk/express'
app.post('/updateStripe', async (req, res) => {
const { stripeId, userId } = req.body
await clerkClient.users.updateUserMetadata(userId, {
privateMetadata: {
stripeId: stripeId,
},
})
res.status(200).json({ success: true })
})
var client clerk.Client
func addStripeCustomerID(user *clerk.User, stripeCustomerID string) error {
stripeID := map[string]interface{}{
"stripeID": stripeCustomerID,
}
user, err := s.clerkClient.Users().UpdateMetadata(sess.UserID, &clerk.updateMetadataRequest{
PrivateMetadata: stripeID,
})
if err != nil {
panic(err)
}
}
# ruby json example with a private metadata and stripe id
require 'clerk'
require 'json'
privateMetadata = {
"stripeID": stripeCustomerID
}
clerk = Clerk::SDK.new(api_key: "your_clerk_secret_key")
clerk.users.updateMetadata("user_xyz", private_metadata: privateMetadata)
curl -XPATCH -H 'Authorization: Bearer CLERK_SECRET_KEY' -H "Content-type: application/json" -d '{
"private_metadata": {
"stripeId": "12356"
}
}' 'https://api.clerk.com/v1/users/{user_id}/metadata'
Retrieve private metadata
You can retrieve the private metadata for a user by using the JavaScript Backend SDK's getUser()
method. This method will return the User
object which contains the private metadata.
import { NextRequest, NextResponse } from 'next/server'
import { clerkClient } from '@clerk/nextjs/server'
export async function GET(request: NextRequest) {
const { userId } = await request.json()
const client = await clerkClient()
const user = await client.users.getUser(userId)
return NextResponse.json(user.privateMetadata)
}
import { clerkClient } from '@clerk/express'
app.post('/updateStripe', async (req, res) => {
const { userId } = req.body
const user = await clerkClient.users.getUser(userId)
res.status(200).json(user.privateMetadata)
})
curl -XGET -H 'Authorization: CLERK_SECRET_KEY' -H "Content-type: application/json" 'https://api.clerk.com/v1/users/{user_id}'
var client clerk.Client
func GetUserMetadata(user *clerk.User, stripeCustomerID string) error {
user, err := s.clerkClient.Users().Read(sess.UserID)
if err != nil {
panic(err)
}
}
# ruby json example with a private metadata and stripe id
require 'clerk'
clerk = Clerk::SDK.new(api_key: "your_clerk_secret_key")
clerk.users.getUser("user_xyz")
Public metadata
Public metadata is accessible 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 custom role for a user.
Set public metadata
import { NextRequest, NextResponse } from 'next/server'
import { clerkClient } from '@clerk/nextjs/server'
export async function POST(request: NextRequest) {
const { stripeId, userId } = await request.json()
const client = await clerkClient()
await client.users.updateUserMetadata(userId, {
publicMetadata: {
stripeId: stripeId,
},
})
return NextResponse.json({ success: true })
}
import { clerkClient } from '@clerk/express'
app.post('/updateRole', async (req, res) => {
const { role, userId } = req.body
await clerkClient.users.updateUserMetadata(userId, {
publicMetadata: {
role,
},
})
res.status(200).json({ success: true })
})
var client clerk.Client
func addStripeCustomerID(user *clerk.User, role string) error {
Role := map[string]interface{}{
"role": role,
}
user, err := s.clerkClient.Users().UpdateMetadata(sess.UserID, &clerk.updateMetadataRequest{
PublicMetadata: role,
})
if err != nil {
panic(err)
}
}
# ruby json example with a private metadata and stripe id
require 'clerk'
require 'json'
publicMetadata = {
"role": "awesome-user",
}
clerk = Clerk::SDK.new(api_key: "your_clerk_secret_key")
clerk.users.updateMetadata("user_xyz", public_metadata: publicMetadata)
curl -XPATCH -H 'Authorization: Bearer CLERK_SECRET_KEY' -H "Content-type: application/json" -d '{
"public_metadata": {
"role": "shopper"
}
}' 'https://api.clerk.com/v1/users/{user_id}/metadata'
Retrieve public metadata
There are multiple ways to retrieve public metadata.
On the frontend, it's available on the User
object which can be accessed using the useUser()
hook.
On the backend, it's available on the Backend User
object which can be accessed using the JavaScript Backend SDK's getUser()
method. It can also be attached to a session token, and the sessionClaims
of the session token can be retrieved on the Auth
object. If you need to retrieve public metadata frequently in the backend, the best option is to attach it to the session token and retrieve it from the session token. See the guide on customizing your session token.
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 SignUp
object. After a successful sign-up, SignUp.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.
Set unsafe metadata
The following examples demonstrate how to update unsafe metadata for an existing user. Updating unsafeMetadata
replaces the previous value; it doesn't perform a merge. To merge data, you can pass a combined object such as { …user.unsafeMetadata, …newData }
to the unsafeMetadata
parameter.
The following examples demonstrate how to update unsafeMetadata
using the Backend API or the Frontend SDKs.
Using the Backend API
import { NextRequest, NextResponse } from 'next/server'
import { clerkClient } from '@clerk/nextjs/server'
export async function POST(request: NextRequest) {
const { userId } = await request.json()
const client = await clerkClient()
await client.users.updateUserMetadata(userId, {
unsafeMetadata: {
birthday: '11-30-1969',
},
})
return NextResponse.json({ success: true })
}
import { clerkClient } from '@clerk/express'
app.post('/updateStripe', async (req, res) => {
const { stripeId, userId } = await req.body
await clerkClient.users.updateUserMetadata(userId, {
unsafeMetadata: {
birthday: '11-30-1969',
},
})
res.status(200).json({ success: true })
})
var client clerk.Client
func addStripeCustomerID(user *clerk.User, stripeCustomerID string) error {
birthday := map[string]interface{}{
"birthday": "04-20-1969",
}
user, err := s.clerkClient.Users().UpdateMetadata(sess.UserID, &clerk.updateMetadataRequest{
UnsafeMetadata: birthday,
})
if err != nil {
panic(err)
}
}
require 'clerk'
require 'json'
unsafeMetadata = {
"birthday": "04-20-1969"
}
clerk = Clerk::SDK.new(api_key: "your_clerk_secret_key")
clerk.users.updateMetadata("user_123", unsafe_metadata: unsafeMetadata)
curl -XPATCH -H 'Authorization: Bearer CLERK_SECRET_KEY' -H "Content-type: application/json" -d '{
"unsafe_metadata": {
"birthday": "11-30-1969"
}
}' 'https://api.clerk.com/v1/users/{user_id}/metadata'
'use client'
import { useUser } from '@clerk/nextjs'
import { useState } from 'react'
export default function UnSafePage() {
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>
)
}
import { useUser } from '@clerk/clerk-react'
import { useState } from 'react'
export default function UnSafePage() {
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>
)
}
import { useUser } from '@clerk/remix'
import { useState } from 'react'
export default function UnSafePage() {
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>
)
}
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.user) {
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)
}
Retrieve unsafe metadata
There are multiple ways to retrieve unsafe metadata.
On the frontend, it is available on the User
object, which you can access by using the useUser()
hook.
On the backend, it's available on the Backend User
object which can be accessed using the JavaScript Backend SDK's getUser()
method. It can also be attached to a session token, and the sessionClaims
of the session token can be retrieved on the Auth
object. If you need to retrieve unsafe metadata frequently in the backend, the best option is to attach it to the session token and retrieve it from the session token. See the guide on customizing your session token.
Feedback
Last updated on