---
title: User metadata
description: Store and manage user metadata using the backend SDK's UserMetadata recipe.
sidebar:
  order: 50
---

## 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

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
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(),
  ],
});
```
</Tab>
<Tab title="Go" value="go">
```go
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),
		},
	})
}
```
</Tab>
<Tab title="Python" value="python">
```python check=false reason="Partial configuration example"
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()
    ]
)
```
</Tab>
</CodeGroup>

---

## Store data

:::note[Only root-level properties merge into the stored object. Nested objects and all lower-level properties replace the existing ones.]
:::

<DependentContent passive group="backend-language">
<ContentOption title="Node.js" value="nodejs">
<DependentContent passive group="node-frameworks">
<ContentOption title="Next.js" value="nextjs">
<NextjsRouterTypeSelect />
</ContentOption>
</DependentContent>
</ContentOption>
</DependentContent>

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
<DependentContent group="node-frameworks" label="Node.js framework">
<ContentOption title="Express" value="express">
```tsx
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" });
});
```
</ContentOption>
<ContentOption title="Hapi" value="hapi">
```tsx
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);
  },
});
```
</ContentOption>
<ContentOption title="Fastify" value="fastify">
```tsx
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" });
  },
);
```
</ContentOption>
<ContentOption title="Aws Lambda" value="aws-lambda">
```tsx
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);
```
</ContentOption>
<ContentOption title="Koa" value="koa">
```tsx
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" };
});
```
</ContentOption>
<ContentOption title="LoopBack" value="loopback">
```tsx
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" };
  }
}
```
</ContentOption>
<ContentOption title="Next.js" value="nextjs">
<ConditionalContent propertyName="nextjsRouterType" condition="pages-router">

```tsx
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" });
}
```

</ConditionalContent>
</ContentOption>
<ContentOption title="Nestjs" value="nestjs">
```tsx check=false reason="Requires surrounding framework application context"
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" };
  }
}
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="Go" value="go">
```go
import "github.com/supertokens/supertokens-golang/recipe/usermetadata"

func main() {
	userId := "..."

	usermetadata.UpdateUserMetadata(userId, map[string]interface{}{
		"newKey": "data",
	})
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.usermetadata.asyncio import update_user_metadata


async def some_func():
    user_id = "..."

    await update_user_metadata(user_id, {
        "newKey": "data"
    })
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.usermetadata.syncio import update_user_metadata

user_id = "..."

update_user_metadata(user_id, {
    "newKey": "data"
})
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

<CodeGroup passive group="backend-language">
<Tab title="Node.js" value="nodejs">
<DependentContent group="node-frameworks" label="Node.js framework">
<ContentOption title="Next.js" value="nextjs">
<ConditionalContent propertyName="nextjsRouterType" condition="app-router">

```tsx check=false reason="Requires surrounding framework application context"
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" });
  });
}
```

</ConditionalContent>
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>


:::info[Multi Tenancy]
User metadata that associates with a user shares across all tenants that that user is a part of. If instead, you want to store user metadata on a tenant level, you can add a custom key in the JSON like:

```json
{
  "tenant1": {
    "someKey": "specific to teannt1"
  },
  "tenant2": {
    "someKey": "specific to teannt2"
  },
  "someKey": "common for all tenants"
}
```

and then read the appropriate key based on the `tenantId`.
:::

---

## Access data

<DependentContent passive group="backend-language">
<ContentOption title="Node.js" value="nodejs">
<DependentContent passive group="node-frameworks">
<ContentOption title="Next.js" value="nextjs">
<NextjsRouterTypeSelect />
</ContentOption>
</DependentContent>
</ContentOption>
</DependentContent>

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
<DependentContent group="node-frameworks" label="Node.js framework">
<ContentOption title="Express" value="express">
```tsx
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 });
});
```
</ContentOption>
<ContentOption title="Hapi" value="hapi">
```tsx
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);
  },
});
```
</ContentOption>
<ContentOption title="Fastify" value="fastify">
```tsx
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 });
  },
);
```
</ContentOption>
<ContentOption title="Aws Lambda" value="aws-lambda">
```tsx
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);
```
</ContentOption>
<ContentOption title="Koa" value="koa">
```tsx
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 };
});
```
</ContentOption>
<ContentOption title="LoopBack" value="loopback">
```tsx
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 };
  }
}
```
</ContentOption>
<ContentOption title="Next.js" value="nextjs">
<ConditionalContent propertyName="nextjsRouterType" condition="pages-router">

```tsx
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 });
}
```

</ConditionalContent>
</ContentOption>
<ContentOption title="Nestjs" value="nestjs">
```tsx check=false reason="Requires surrounding framework application context"
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 };
  }
}
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="Go" value="go">
```go
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)
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
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)
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.usermetadata.syncio import get_user_metadata

user_id = "..."

metadataResult = get_user_metadata(user_id)
exampleValue = metadataResult.metadata["exampleKey"]
print(exampleValue)
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

<CodeGroup passive group="backend-language">
<Tab title="Node.js" value="nodejs">
<DependentContent group="node-frameworks" label="Node.js framework">
<ContentOption title="Next.js" value="nextjs">
<ConditionalContent propertyName="nextjsRouterType" condition="app-router">

```tsx check=false reason="Requires surrounding framework application context"
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 });
  });
}
```

</ConditionalContent>
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

:::info[Important]
By default, all users have an empty metadata object.
:::


## 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:
```json
{
  "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:
```json
{
  "notifications": null
}
```

This would result in the final metadata object:
```json
{
  "preferences": { "theme": "dark" },
  "todos": ["use-text-notifs"]
}
```

:::info[Important]
You can only remove the root level fields in the metadata object in this way. From the above example, if you set `preferences.theme: null`, then it does not remove the `"theme"` field, but instead sets it to a JSON null value.
:::

In code, it would look like:

<DependentContent passive group="backend-language">
<ContentOption title="Node.js" value="nodejs">
<DependentContent passive group="node-frameworks">
<ContentOption title="Next.js" value="nextjs">
<NextjsRouterTypeSelect />
</ContentOption>
</DependentContent>
</ContentOption>
</DependentContent>

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
<DependentContent group="node-frameworks" label="Node.js framework">
<ContentOption title="Express" value="express">
```tsx
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" });
});
```
</ContentOption>
<ContentOption title="Hapi" value="hapi">
```tsx
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);
  },
});
```
</ContentOption>
<ContentOption title="Fastify" value="fastify">
```tsx
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" });
  },
);
```
</ContentOption>
<ContentOption title="Aws Lambda" value="aws-lambda">
```tsx
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);
```
</ContentOption>
<ContentOption title="Koa" value="koa">
```tsx
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" };
});
```
</ContentOption>
<ContentOption title="LoopBack" value="loopback">
```tsx
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" };
  }
}
```
</ContentOption>
<ContentOption title="Next.js" value="nextjs">
<ConditionalContent propertyName="nextjsRouterType" condition="pages-router">

```tsx
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" });
}
```

</ConditionalContent>
</ContentOption>
<ContentOption title="Nestjs" value="nestjs">
```tsx check=false reason="Requires surrounding framework application context"
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" };
  }
}
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="Go" value="go">
```go
import "github.com/supertokens/supertokens-golang/recipe/usermetadata"

func main() {
	userId := "..."

	usermetadata.UpdateUserMetadata(userId, map[string]interface{}{
		"notifications": nil,
	})
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.usermetadata.asyncio import update_user_metadata


async def some_func():
    user_id = "..."

    await update_user_metadata(user_id, {
        "notifications": None
    })
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.usermetadata.syncio import update_user_metadata

user_id = "..."

update_user_metadata(user_id, {
    "notifications": None
})
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

<CodeGroup passive group="backend-language">
<Tab title="Node.js" value="nodejs">
<DependentContent group="node-frameworks" label="Node.js framework">
<ContentOption title="Next.js" value="nextjs">
<ConditionalContent propertyName="nextjsRouterType" condition="app-router">

```tsx check=false reason="Requires surrounding framework application context"
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" });
  });
}
```

</ConditionalContent>
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

### Delete the entire metadata object

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

<DependentContent passive group="backend-language">
<ContentOption title="Node.js" value="nodejs">
<DependentContent passive group="node-frameworks">
<ContentOption title="Next.js" value="nextjs">
<NextjsRouterTypeSelect />
</ContentOption>
</DependentContent>
</ContentOption>
</DependentContent>

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
<DependentContent group="node-frameworks" label="Node.js framework">
<ContentOption title="Express" value="express">
```tsx
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 });
});
```
</ContentOption>
<ContentOption title="Hapi" value="hapi">
```tsx
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);
  },
});
```
</ContentOption>
<ContentOption title="Fastify" value="fastify">
```tsx
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 });
  },
);
```
</ContentOption>
<ContentOption title="Aws Lambda" value="aws-lambda">
```tsx
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);
```
</ContentOption>
<ContentOption title="Koa" value="koa">
```tsx
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 };
});
```
</ContentOption>
<ContentOption title="LoopBack" value="loopback">
```tsx
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 };
  }
}
```
</ContentOption>
<ContentOption title="Next.js" value="nextjs">
<ConditionalContent propertyName="nextjsRouterType" condition="pages-router">

```tsx
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 });
}
```

</ConditionalContent>
</ContentOption>
<ContentOption title="Nestjs" value="nestjs">
```tsx check=false reason="Requires surrounding framework application context"
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 };
  }
}
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="Go" value="go">
```go
import "github.com/supertokens/supertokens-golang/recipe/usermetadata"

func main() {
	userId := "..."

	usermetadata.ClearUserMetadata(userId)
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.usermetadata.asyncio import clear_user_metadata


async def some_func():
    user_id = "..."

    await clear_user_metadata(user_id)
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.usermetadata.syncio import clear_user_metadata

user_id = "..."

clear_user_metadata(user_id)
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

<CodeGroup passive group="backend-language">
<Tab title="Node.js" value="nodejs">
<DependentContent group="node-frameworks" label="Node.js framework">
<ContentOption title="Next.js" value="nextjs">
<ConditionalContent propertyName="nextjsRouterType" condition="app-router">

```tsx check=false reason="Requires surrounding framework application context"
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 });
  });
}
```

</ConditionalContent>
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

---

## See also

<CardGroup cols={3}>
  <Card title="Common User Management Actions" href="/post-authentication/user-management/common-actions" />
  <Card title="Session Management" href="/post-authentication/session-management/access-session-data" />
  <Card title="Allow Users to Update Their Data" href="/post-authentication/user-management/allow-users-to-update-their-data" />
  <Card title="Dashboard User Management" href="/post-authentication/dashboard/user-management" />
</CardGroup>
