clerk auth default metadata

hello,
to start this of some basic info:
i am currently working on a learning project which is a sass using react, next.js and clerk auth with the t3 stack
i currently am implementing a sort of token system (and basic role system but thats not very important) utilizing clerks user metadata feature for that as i currently am not using a stand alone db. i was wondering is there was a simple way to add default metadata when a user is created for example when a user is created the start with 100 tokens?

currently i am utilizing private metadata for this and the structure looks like this: { "role": "admin", "tokens": 99999 } and utilize these functions for basic manipulation of that metadata:

export async function GetTokenAmount(userId: string) {
  const user = await clerkClient().users.getUser(userId);
  const data = user.privateMetadata;
  const tokenAmount = data.tokens as number;

  return tokenAmount;
}


export async function AddTokens(userId: string, AddedAmount: number) {
  // TODO: Add validation! (Most Likely Stripe)
  //   const user = await clerkClient().users.getUser(userId);
  const currentTokenAmount = GetTokenAmount(userId);
  const newTokenAmount = (await currentTokenAmount) + AddedAmount;

  if (AddedAmount <= 0) {
    throw new Error("Invalid amount");
  } else {
    await clerkClient.users.updateUserMetadata(userId, {
      privateMetadata: {
        tokens: newTokenAmount,
      },
    });
  }
}


export async function RemoveTokens(userId: string, RemovedAmount: number) {
  const currentTokenAmount = GetTokenAmount(userId);
  const newTokenAmount = (await currentTokenAmount) - RemovedAmount;

  if (RemovedAmount <= 0) {
    throw new Error("Invalid amount");
  } else {
    await clerkClient.users.updateUserMetadata(userId, {
      privateMetadata: {
        tokens: newTokenAmount,
      },
    });
  }
}
Metadata allows for custom data to be saved on the User object.
Solution
after some messing around came up with a much simpler solution to use at least for the time being basically when retrieving the tokens in the navbar if it returns as undefined i run a nonblocking function to create the metadata and temporarily show the default amount
export async function GetTokenAmount(userId: string) {
  const user = await clerkClient().users.getUser(userId);
  const data = user.privateMetadata;
  const tokenAmount = data.tokens as number;

  if (tokenAmount === undefined) {
    // Call CreateTokenMetadata but don't await it to make it non-blocking
    CreateTokenMetadata(userId).catch((err) => {
      console.error("Error creating token metadata:", err);
    });
    return 100; // Immediately return the default value without waiting
  }

  return tokenAmount;
}


export async function CreateTokenMetadata(userId: string) {
  await clerkClient.users.updateUserMetadata(userId, {
    privateMetadata: {
      tokens: 100,
    },
  });
}
Was this page helpful?