User metadata
Store and manage user metadata using the backend SDK's UserMetadata recipe.
Overview
You can use the UserMetadata recipe to store your custom data about each user.
This can be any arbitrary values that are JSON serializable.
The following page shows you how to enable and use the feature.
Enable the UserMetadata recipe
import SuperTokens from "supertokens-node";
import UserMetadata from "supertokens-node/recipe/usermetadata";
SuperTokens.init({
supertokens: {
connectionURI: "...",
},
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "...",
},
recipeList: [
// Initialize other recipes as seen in the quick setup guide
UserMetadata.init(),
],
});import (
"github.com/supertokens/supertokens-golang/recipe/usermetadata"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
supertokens.Init(supertokens.TypeInput{
RecipeList: []supertokens.Recipe{
// Initialize other recipes as seen in the quick setup guide
usermetadata.Init(nil),
},
})
}from supertokens_python import InputAppInfo, init
from supertokens_python.recipe import usermetadata
init(
app_info=InputAppInfo(
api_domain="...", app_name="...", website_domain="..."
),
framework='...',
recipe_list=[
# Initialize other recipes as seen in the quick setup guide
usermetadata.init()
]
)Store data
import express from "express";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let app = express();
app.post("/updateinfo", verifySession(), async (req, res) => {
const session = req.session;
const userId = session.getUserId();
await UserMetadata.updateUserMetadata(userId, { newKey: "data" });
res.json({ message: "successfully updated user metadata" });
});import Hapi from "@hapi/hapi";
import { verifySession } from "supertokens-node/recipe/session/framework/hapi";
import { SessionRequest } from "supertokens-node/framework/hapi";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let server = Hapi.server({ port: 8000 });
server.route({
path: "/updateinfo",
method: "post",
options: {
pre: [
{
method: verifySession(),
},
],
},
handler: async (req: SessionRequest, res) => {
const session = req.session;
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { newKey: "data" });
return res.response({ message: "successfully updated user metadata" }).code(200);
},
});import Fastify from "fastify";
import { verifySession } from "supertokens-node/recipe/session/framework/fastify";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let fastify = Fastify();
fastify.post(
"/updateinfo",
{
preHandler: verifySession(),
},
async (req, res) => {
const session = req.session;
const userId = session.getUserId();
await UserMetadata.updateUserMetadata(userId, { newKey: "data" });
res.send({ message: "successfully updated user metadata" });
},
);import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda";
import { SessionEvent } from "supertokens-node/framework/awsLambda";
import UserMetadata from "supertokens-node/recipe/usermetadata";
async function updateinfo(awsEvent: SessionEvent) {
const session = awsEvent.session;
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { newKey: "data" });
return {
body: JSON.stringify({ message: "successfully updated user metadata" }),
statusCode: 200,
};
}
exports.handler = verifySession(updateinfo);import KoaRouter from "koa-router";
import { verifySession } from "supertokens-node/recipe/session/framework/koa";
import { SessionContext } from "supertokens-node/framework/koa";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let router = new KoaRouter();
router.post("/updateinfo", verifySession(), async (ctx: SessionContext, next) => {
const session = ctx.session;
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { newKey: "data" });
ctx.body = { message: "successfully updated user metadata" };
});import { inject, intercept } from "@loopback/core";
import { RestBindings, post, response } from "@loopback/rest";
import { verifySession } from "supertokens-node/recipe/session/framework/loopback";
import { SessionContext } from "supertokens-node/framework/loopback";
import UserMetadata from "supertokens-node/recipe/usermetadata";
class UpdateInfo {
constructor(@inject(RestBindings.Http.CONTEXT) private ctx: SessionContext) {}
@post("/updateinfo")
@intercept(verifySession())
@response(200)
async handler() {
const session = this.ctx.session;
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { newKey: "data" });
return { message: "successfully updated user metadata" };
}
}import { superTokensNextWrapper } from "supertokens-node/nextjs";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import { SessionRequest } from "supertokens-node/framework/express";
import UserMetadata from "supertokens-node/recipe/usermetadata";
export default async function updateInfo(req: any, res: any) {
await superTokensNextWrapper(
async (next) => {
await verifySession()(req, res, next);
},
req,
res,
);
const session = (req as SessionRequest).session;
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { newKey: "data" });
res.json({ message: "successfully updated user metadata" });
}import { Controller, Post, UseGuards, Session } from "@nestjs/common";
import { SessionContainer } from "supertokens-node/recipe/session";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { AuthGuard } from "./auth/auth.guard";
@Controller()
export class ExampleController {
// For more information about "AuthGuard" and the "Session" decorator please read our NestJS guide.
@Post("example")
@UseGuards(new AuthGuard())
async postExample(@Session() session: SessionContainer): Promise<{ message: string }> {
const userId = session.getUserId();
await UserMetadata.updateUserMetadata(userId, { newKey: "data" });
return { message: "successfully updated user metadata" };
}
}import "github.com/supertokens/supertokens-golang/recipe/usermetadata"
func main() {
userId := "..."
usermetadata.UpdateUserMetadata(userId, map[string]interface{}{
"newKey": "data",
})
}from supertokens_python.recipe.usermetadata.asyncio import update_user_metadata
async def some_func():
user_id = "..."
await update_user_metadata(user_id, {
"newKey": "data"
})from supertokens_python.recipe.usermetadata.syncio import update_user_metadata
user_id = "..."
update_user_metadata(user_id, {
"newKey": "data"
})import { NextResponse, NextRequest } from "next/server";
import SuperTokens from "supertokens-node";
import { withSession } from "supertokens-node/nextjs";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { backendConfig } from "@/app/config/backend";
SuperTokens.init(backendConfig());
export function POST(request: NextRequest) {
return withSession(request, async (err, session) => {
if (err) {
return NextResponse.json(err, { status: 500 });
}
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { newKey: "data" });
return NextResponse.json({ success: "successfully updated user metadata" });
});
}Access data
import express from "express";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let app = express();
app.post("/updateinfo", verifySession(), async (req, res) => {
const session = req.session;
const userId = session.getUserId();
const { metadata } = await UserMetadata.getUserMetadata(userId);
res.json({ preferences: metadata.preferences });
});import Hapi from "@hapi/hapi";
import { verifySession } from "supertokens-node/recipe/session/framework/hapi";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { SessionRequest } from "supertokens-node/framework/hapi";
let server = Hapi.server({ port: 8000 });
server.route({
path: "/updateinfo",
method: "post",
options: {
pre: [
{
method: verifySession(),
},
],
},
handler: async (req: SessionRequest, res) => {
const session = req.session;
const userId = session!.getUserId();
const { metadata } = await UserMetadata.getUserMetadata(userId);
return res.response({ preferences: metadata.preferences }).code(200);
},
});import Fastify from "fastify";
import { verifySession } from "supertokens-node/recipe/session/framework/fastify";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let fastify = Fastify();
fastify.post(
"/updateinfo",
{
preHandler: verifySession(),
},
async (req, res) => {
const session = req.session;
const userId = session.getUserId();
const { metadata } = await UserMetadata.getUserMetadata(userId);
res.send({ preferences: metadata.preferences });
},
);import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { SessionEvent } from "supertokens-node/framework/awsLambda";
async function updateinfo(awsEvent: SessionEvent) {
const session = awsEvent.session;
const userId = session!.getUserId();
const { metadata } = await UserMetadata.getUserMetadata(userId);
return {
body: JSON.stringify({ preferences: metadata.preferences }),
statusCode: 200,
};
}
exports.handler = verifySession(updateinfo);import KoaRouter from "koa-router";
import { verifySession } from "supertokens-node/recipe/session/framework/koa";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { SessionContext } from "supertokens-node/framework/koa";
let router = new KoaRouter();
router.post("/updateinfo", verifySession(), async (ctx: SessionContext, next) => {
const session = ctx.session;
const userId = session!.getUserId();
const { metadata } = await UserMetadata.getUserMetadata(userId);
ctx.body = { preferences: metadata.preferences };
});import { inject, intercept } from "@loopback/core";
import { RestBindings, post, response } from "@loopback/rest";
import { verifySession } from "supertokens-node/recipe/session/framework/loopback";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { SessionContext } from "supertokens-node/framework/loopback";
class UpdateInfo {
constructor(@inject(RestBindings.Http.CONTEXT) private ctx: SessionContext) {}
@post("/updateinfo")
@intercept(verifySession())
@response(200)
async handler() {
const session = this.ctx.session;
const userId = session!.getUserId();
const { metadata } = await UserMetadata.getUserMetadata(userId);
return { preferences: metadata.preferences };
}
}import { superTokensNextWrapper } from "supertokens-node/nextjs";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { SessionRequest } from "supertokens-node/framework/express";
export default async function updateInfo(req: any, res: any) {
await superTokensNextWrapper(
async (next) => {
await verifySession()(req, res, next);
},
req,
res,
);
const session = (req as SessionRequest).session;
const userId = session!.getUserId();
const { metadata } = await UserMetadata.getUserMetadata(userId);
res.json({ preferences: metadata.preferences });
}import { Controller, Post, UseGuards, Session } from "@nestjs/common";
import { SessionContainer } from "supertokens-node/recipe/session";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { AuthGuard } from "./auth/auth.guard";
@Controller()
export class ExampleController {
// For more information about "AuthGuard" and the "Session" decorator please read our NestJS guide.
@Post("example")
@UseGuards(new AuthGuard())
async postExample(@Session() session: SessionContainer): Promise<{ preferences: any }> {
const userId = session.getUserId();
const { metadata } = await UserMetadata.getUserMetadata(userId);
return { preferences: metadata.preferences };
}
}import (
"fmt"
"github.com/supertokens/supertokens-golang/recipe/usermetadata"
)
func main() {
userId := "..."
metadata, err := usermetadata.GetUserMetadata(userId)
if err != nil {
// TODO: handle error...
}
exampleValue := metadata["exampleKey"]
fmt.Println(exampleValue)
}from supertokens_python.recipe.usermetadata.asyncio import get_user_metadata
async def some_func():
user_id = "..."
metadataResult = await get_user_metadata(user_id)
exampleValue = metadataResult.metadata["exampleKey"]
print(exampleValue)from supertokens_python.recipe.usermetadata.syncio import get_user_metadata
user_id = "..."
metadataResult = get_user_metadata(user_id)
exampleValue = metadataResult.metadata["exampleKey"]
print(exampleValue)import { NextResponse, NextRequest } from "next/server";
import SuperTokens from "supertokens-node";
import { withSession } from "supertokens-node/nextjs";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { backendConfig } from "@/app/config/backend";
SuperTokens.init(backendConfig());
export function POST(request: NextRequest) {
return withSession(request, async (err, session) => {
if (err) {
return NextResponse.json(err, { status: 500 });
}
const userId = session!.getUserId();
const { metadata } = await UserMetadata.getUserMetadata(userId);
return NextResponse.json({ preferences: metadata.preferences });
});
}Delete metadata
You can either delete all the user’s metadata, or certain fields from them:
Delete specific fields
You can do this by calling the update metadata function and setting the field you want to remove to be null. For example, if you have the following metadata object for a user:
{
"preferences": { "theme": "dark" },
"notifications": { "email": true },
"todos": ["use-text-notifs"]
}
And you want to remove the "notifications" field, you can update the metadata object with the following JSON:
{
"notifications": null
}
This would result in the final metadata object:
{
"preferences": { "theme": "dark" },
"todos": ["use-text-notifs"]
}
In code, it would look like:
import express from "express";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let app = express();
app.post("/updateinfo", verifySession(), async (req, res) => {
const session = req.session;
const userId = session.getUserId();
await UserMetadata.updateUserMetadata(userId, { notifications: null });
res.json({ message: "successfully updated user metadata" });
});import Hapi from "@hapi/hapi";
import { verifySession } from "supertokens-node/recipe/session/framework/hapi";
import { SessionRequest } from "supertokens-node/framework/hapi";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let server = Hapi.server({ port: 8000 });
server.route({
path: "/updateinfo",
method: "post",
options: {
pre: [
{
method: verifySession(),
},
],
},
handler: async (req: SessionRequest, res) => {
const session = req.session;
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { notifications: null });
return res.response({ message: "successfully updated user metadata" }).code(200);
},
});import Fastify from "fastify";
import { verifySession } from "supertokens-node/recipe/session/framework/fastify";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let fastify = Fastify();
fastify.post(
"/updateinfo",
{
preHandler: verifySession(),
},
async (req, res) => {
const session = req.session;
const userId = session.getUserId();
await UserMetadata.updateUserMetadata(userId, { notifications: null });
res.send({ message: "successfully updated user metadata" });
},
);import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda";
import { SessionEvent } from "supertokens-node/framework/awsLambda";
import UserMetadata from "supertokens-node/recipe/usermetadata";
async function updateinfo(awsEvent: SessionEvent) {
const session = awsEvent.session;
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { notifications: null });
return {
body: JSON.stringify({ message: "successfully updated user metadata" }),
statusCode: 200,
};
}
exports.handler = verifySession(updateinfo);import KoaRouter from "koa-router";
import { verifySession } from "supertokens-node/recipe/session/framework/koa";
import { SessionContext } from "supertokens-node/framework/koa";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let router = new KoaRouter();
router.post("/updateinfo", verifySession(), async (ctx: SessionContext, next) => {
const session = ctx.session;
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { notifications: null });
ctx.body = { message: "successfully updated user metadata" };
});import { inject, intercept } from "@loopback/core";
import { RestBindings, post, response } from "@loopback/rest";
import { verifySession } from "supertokens-node/recipe/session/framework/loopback";
import { SessionContext } from "supertokens-node/framework/loopback";
import UserMetadata from "supertokens-node/recipe/usermetadata";
class UpdateInfo {
constructor(@inject(RestBindings.Http.CONTEXT) private ctx: SessionContext) {}
@post("/updateinfo")
@intercept(verifySession())
@response(200)
async handler() {
const session = this.ctx.session;
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { notifications: null });
return { message: "successfully updated user metadata" };
}
}import { superTokensNextWrapper } from "supertokens-node/nextjs";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import { SessionRequest } from "supertokens-node/framework/express";
import UserMetadata from "supertokens-node/recipe/usermetadata";
export default async function updateInfo(req: any, res: any) {
await superTokensNextWrapper(
async (next) => {
await verifySession()(req, res, next);
},
req,
res,
);
const session = (req as SessionRequest).session;
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { notifications: null });
res.json({ message: "successfully updated user metadata" });
}import { Controller, Post, UseGuards, Session } from "@nestjs/common";
import { SessionContainer } from "supertokens-node/recipe/session";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { AuthGuard } from "./auth/auth.guard";
@Controller()
export class ExampleController {
// For more information about "AuthGuard" and the "Session" decorator please read our NestJS guide.
@Post("example")
@UseGuards(new AuthGuard())
async postExample(@Session() session: SessionContainer): Promise<{ message: string }> {
const userId = session.getUserId();
await UserMetadata.updateUserMetadata(userId, { notifications: null });
return { message: "successfully updated user metadata" };
}
}import "github.com/supertokens/supertokens-golang/recipe/usermetadata"
func main() {
userId := "..."
usermetadata.UpdateUserMetadata(userId, map[string]interface{}{
"notifications": nil,
})
}from supertokens_python.recipe.usermetadata.asyncio import update_user_metadata
async def some_func():
user_id = "..."
await update_user_metadata(user_id, {
"notifications": None
})from supertokens_python.recipe.usermetadata.syncio import update_user_metadata
user_id = "..."
update_user_metadata(user_id, {
"notifications": None
})import { NextResponse, NextRequest } from "next/server";
import SuperTokens from "supertokens-node";
import { withSession } from "supertokens-node/nextjs";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { backendConfig } from "@/app/config/backend";
SuperTokens.init(backendConfig());
export function POST(request: NextRequest) {
return withSession(request, async (err, session) => {
if (err) {
return NextResponse.json(err, { status: 500 });
}
const userId = session!.getUserId();
await UserMetadata.updateUserMetadata(userId, { notifications: null });
return NextResponse.json({ message: "successfully updated user metadata" });
});
}Delete the entire metadata object
Using this function deletes all the fields in the user metadata object for that user.
import express from "express";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let app = express();
app.post("/updateinfo", verifySession(), async (req, res) => {
const session = req.session;
const userId = session!.getUserId();
await UserMetadata.clearUserMetadata(userId);
res.json({ success: true });
});import Hapi from "@hapi/hapi";
import { verifySession } from "supertokens-node/recipe/session/framework/hapi";
import { SessionRequest } from "supertokens-node/framework/hapi";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let server = Hapi.server({ port: 8000 });
server.route({
path: "/updateinfo",
method: "post",
options: {
pre: [
{
method: verifySession(),
},
],
},
handler: async (req: SessionRequest, res) => {
const session = req.session;
const userId = session!.getUserId();
await UserMetadata.clearUserMetadata(userId);
return res.response({ success: true }).code(200);
},
});import Fastify from "fastify";
import { verifySession } from "supertokens-node/recipe/session/framework/fastify";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let fastify = Fastify();
fastify.post(
"/updateinfo",
{
preHandler: verifySession(),
},
async (req, res) => {
const session = req.session;
const userId = session!.getUserId();
await UserMetadata.clearUserMetadata(userId);
res.send({ success: true });
},
);import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda";
import { SessionEvent } from "supertokens-node/framework/awsLambda";
import UserMetadata from "supertokens-node/recipe/usermetadata";
async function updateinfo(awsEvent: SessionEvent) {
const session = awsEvent.session;
const userId = session!.getUserId();
await UserMetadata.clearUserMetadata(userId);
return {
body: JSON.stringify({ success: true }),
statusCode: 200,
};
}
exports.handler = verifySession(updateinfo);import KoaRouter from "koa-router";
import { verifySession } from "supertokens-node/recipe/session/framework/koa";
import { SessionContext } from "supertokens-node/framework/koa";
import UserMetadata from "supertokens-node/recipe/usermetadata";
let router = new KoaRouter();
router.post("/updateinfo", verifySession(), async (ctx: SessionContext, next) => {
const session = ctx.session;
const userId = session!.getUserId();
await UserMetadata.clearUserMetadata(userId);
ctx.body = { success: true };
});import { inject, intercept } from "@loopback/core";
import { RestBindings, post, response } from "@loopback/rest";
import { verifySession } from "supertokens-node/recipe/session/framework/loopback";
import { SessionContext } from "supertokens-node/framework/loopback";
import UserMetadata from "supertokens-node/recipe/usermetadata";
class UpdateInfo {
constructor(@inject(RestBindings.Http.CONTEXT) private ctx: SessionContext) {}
@post("/updateinfo")
@intercept(verifySession())
@response(200)
async handler() {
const session = this.ctx.session;
const userId = session!.getUserId();
await UserMetadata.clearUserMetadata(userId);
return { success: true };
}
}import { superTokensNextWrapper } from "supertokens-node/nextjs";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import { SessionRequest } from "supertokens-node/framework/express";
import UserMetadata from "supertokens-node/recipe/usermetadata";
export default async function updateInfo(req: any, res: any) {
await superTokensNextWrapper(
async (next) => {
await verifySession()(req, res, next);
},
req,
res,
);
const session = (req as SessionRequest).session;
const userId = session!.getUserId();
await UserMetadata.clearUserMetadata(userId);
res.json({ success: true });
}import { Controller, Post, UseGuards, Session } from "@nestjs/common";
import { SessionContainer } from "supertokens-node/recipe/session";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { AuthGuard } from "./auth/auth.guard";
@Controller()
export class ExampleController {
@Post("example")
@UseGuards(new AuthGuard())
async postExample(@Session() session: SessionContainer): Promise<{ success: boolean }> {
const userId = session.getUserId();
// For more information about "AuthGuard" and the "Session" decorator please read our NestJS guide.
await UserMetadata.clearUserMetadata(userId);
return { success: true };
}
}import "github.com/supertokens/supertokens-golang/recipe/usermetadata"
func main() {
userId := "..."
usermetadata.ClearUserMetadata(userId)
}from supertokens_python.recipe.usermetadata.asyncio import clear_user_metadata
async def some_func():
user_id = "..."
await clear_user_metadata(user_id)from supertokens_python.recipe.usermetadata.syncio import clear_user_metadata
user_id = "..."
clear_user_metadata(user_id)import { NextResponse, NextRequest } from "next/server";
import SuperTokens from "supertokens-node";
import { withSession } from "supertokens-node/nextjs";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { backendConfig } from "@/app/config/backend";
SuperTokens.init(backendConfig());
export function POST(request: NextRequest) {
return withSession(request, async (err, session) => {
if (err) {
return NextResponse.json(err, { status: 500 });
}
const userId = session!.getUserId();
await UserMetadata.clearUserMetadata(userId);
return NextResponse.json({ success: true });
});
}