Skip to content
Esc
navigateopen⌘Jpreview
Dashboard
On this page

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

Next.js router
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 { 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"
})

Access data

Next.js router
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 { 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)

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:

Next.js router
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 { 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
})

Delete the entire metadata object

Using this function deletes all the fields in the user metadata object for that user.

Next.js router
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 { 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)

See also

API reference

API schema and response details