---
title: Common actions
description: Discover how to manage users using SuperTokens.
sidebar:
  order: 20
---

## Overview

**SuperTokens** exposes a set of functions and APIs that you can use to have manual control over your users.
Actions like fetching users or deleting them are available through different SDK calls.

---

## Get user

### By email

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import supertokens from "supertokens-node";

async function getUserInfo() {
  let usersInfo = await supertokens.listUsersByAccountInfo("public", {
    email: "test@example.com",
  });

  /**
   *
   * userInfo contains the following info:
   * - emails
   * - id
   * - timeJoined
   * - tenantIds
   * - phone numbers
   * - third party login info
   * - all the login methods associated with this user.
   * - information about if the user's email is verified or not.
   *
   */
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"fmt"
	"github.com/supertokens/supertokens-golang/recipe/emailpassword"
)

func main() {

	// Note that usersInfo has type User[]
	// You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki
	userInfo, err := emailpassword.GetUserByEmail("public", "test@example.com")
	if err != nil {
		// TODO: Handle error
		return
	}
	fmt.Println(userInfo)
	//...
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.asyncio import list_users_by_account_info
from supertokens_python.types.base import AccountInfoInput


async def some_func():
    # Note that users_info has type List[User]
    user_info = await list_users_by_account_info("public", AccountInfoInput(email="test@example.com"))
    print(user_info)

    #
    # user_info contains the following info:
    # - emails
    # - id
    # - timeJoined
    # - tenantIds
    # - phone numbers
    # - third party login info
    # - all the login methods associated with this user.
    # - information about if the user's email is verified or not.
    #
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.syncio import list_users_by_account_info
from supertokens_python.types.base import AccountInfoInput


def some_func():
    # Note that users_info has type List[User]
    user_info = list_users_by_account_info("public", AccountInfoInput(email="test@example.com"))
    print(user_info)

    #
    # user_info contains the following info:
    # - emails
    # - id
    # - timeJoined
    # - tenantIds
    # - phone numbers
    # - third party login info
    # - all the login methods associated with this user.
    # - information about if the user's email is verified or not.
    #
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

:::info[Multi Tenancy]
Notice that the first argument of the above function is `"public"`. This is the default `tenantId`, which means that SuperTokens returns information about the user whose email is `"test@example.com"` in the `"public"` tenant.

If you are using the multi-tenancy feature, you can pass in a different `tenantId` to get information about a user in a different tenant.
:::

### By phone number

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import supertokens from "supertokens-node";

async function handler() {
  let usersInfo = await supertokens.listUsersByAccountInfo("public", {
    phoneNumber: "+1234567890",
  });

  /**
   *
   * userInfo contains the following info:
   * - emails
   * - id
   * - timeJoined
   * - tenantIds
   * - phone numbers
   * - third party login info
   * - all the login methods associated with this user.
   * - information about if the user's email is verified or not.
   *
   */
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"fmt"

	"github.com/supertokens/supertokens-golang/recipe/passwordless"
)

func main() {

	tenantId := "public"
	userInfo, err := passwordless.GetUserByPhoneNumber(tenantId, "+1234567890")
	if err != nil {
		// TODO: Handle error
		return
	}
	fmt.Println(userInfo)
	//...
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.asyncio import list_users_by_account_info
from supertokens_python.types.base import AccountInfoInput


async def some_func():
    _ = await list_users_by_account_info(
        "public", AccountInfoInput(phone_number="+1234567890")
    )
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.syncio import list_users_by_account_info
from supertokens_python.types.base import AccountInfoInput


def some_func():
    _ = list_users_by_account_info(
        "public", AccountInfoInput(phone_number="+1234567890")
    )
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

:::info[Multi Tenancy]
Notice that the `"public"` `tenantId` appears in the function call above. This is the default `tenantId` and returns the user with the given phone number that belongs to the `public` tenant. You can provide a different `tenantId` if required.
:::

### By User ID

<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 { SessionRequest } from "supertokens-node/framework/express";
import supertokens from "supertokens-node";

let app = express();
app.get("/get-user-info", verifySession(), async (req: SessionRequest, res) => {
  let userId = req.session!.getUserId();

  let userInfo = await supertokens.getUser(userId);

  /**
   *
   * userInfo contains the following info:
   * - emails
   * - id
   * - timeJoined
   * - tenantIds
   * - phone numbers
   * - third party login info
   * - all the login methods associated with this user.
   * - information about if the user's email is verified or not.
   *
   */
});
```
</ContentOption>
<ContentOption title="Hapi" value="hapi">
```tsx
import { verifySession } from "supertokens-node/recipe/session/framework/hapi";
import Hapi from "@hapi/hapi";
import { SessionRequest } from "supertokens-node/framework/hapi";
import supertokens from "supertokens-node";

let server = Hapi.server({ port: 8000 });

server.route({
  path: "/get-user-info",
  method: "get",
  options: {
    pre: [
      {
        method: verifySession(),
      },
    ],
  },
  handler: async (req: SessionRequest, res) => {
    let userId = req.session!.getUserId();

    let userInfo = await supertokens.getUser(userId);

    /**
     *
     * userInfo contains the following info:
     * - emails
     * - id
     * - timeJoined
     * - tenantIds
     * - phone numbers
     * - third party login info
     * - all the login methods associated with this user.
     * - information about if the user's email is verified or not.
     *
     */
  },
});
```
</ContentOption>
<ContentOption title="Fastify" value="fastify">
```tsx
import Fastify from "fastify";
import { verifySession } from "supertokens-node/recipe/session/framework/fastify";
import { SessionRequest } from "supertokens-node/framework/fastify";
import supertokens from "supertokens-node";

const fastify = Fastify();

fastify.post(
  "/like-comment",
  {
    preHandler: verifySession(),
  },
  async (req: SessionRequest, res) => {
    let userId = req.session!.getUserId();

    let userInfo = await supertokens.getUser(userId);

    /**
     *
     * userInfo contains the following info:
     * - emails
     * - id
     * - timeJoined
     * - tenantIds
     * - phone numbers
     * - third party login info
     * - all the login methods associated with this user.
     * - information about if the user's email is verified or not.
     *
     */
  },
);
```
</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 supertokens from "supertokens-node";

async function getUserInfo(awsEvent: SessionEvent) {
  let userId = awsEvent.session!.getUserId();

  let userInfo = await supertokens.getUser(userId);

  /**
   *
   * userInfo contains the following info:
   * - emails
   * - id
   * - timeJoined
   * - tenantIds
   * - phone numbers
   * - third party login info
   * - all the login methods associated with this user.
   * - information about if the user's email is verified or not.
   *
   */
}

exports.handler = verifySession(getUserInfo);
```
</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 supertokens from "supertokens-node";

let router = new KoaRouter();

router.get("/get-user-info", verifySession(), async (ctx: SessionContext, next) => {
  let userId = ctx.session!.getUserId();

  let userInfo = await supertokens.getUser(userId);

  /**
   *
   * userInfo contains the following info:
   * - emails
   * - id
   * - timeJoined
   * - tenantIds
   * - phone numbers
   * - third party login info
   * - all the login methods associated with this user.
   * - information about if the user's email is verified or not.
   *
   */
});
```
</ContentOption>
<ContentOption title="LoopBack" value="loopback">
```tsx
import { inject, intercept } from "@loopback/core";
import { RestBindings, MiddlewareContext, get, response } from "@loopback/rest";
import { verifySession } from "supertokens-node/recipe/session/framework/loopback";
import Session from "supertokens-node/recipe/session";
import { SessionContext } from "supertokens-node/framework/loopback";
import supertokens from "supertokens-node";

class GetUserInfo {
  constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) {}
  @get("/get-user-info")
  @intercept(verifySession())
  @response(200)
  async handler() {
    let userId = ((this.ctx as any).session as Session.SessionContainer).getUserId();

    let userInfo = await supertokens.getUser(userId);

    /**
     *
     * userInfo contains the following info:
     * - emails
     * - id
     * - timeJoined
     * - tenantIds
     * - phone numbers
     * - third party login info
     * - all the login methods associated with this user.
     * - information about if the user's email is verified or not.
     *
     */
  }
}
```
</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 supertokens from "supertokens-node";

export default async function likeComment(req: SessionRequest, res: any) {
  await superTokensNextWrapper(
    async (next) => {
      await verifySession()(req, res, next);
    },
    req,
    res,
  );

  let userId = req.session!.getUserId();

  let userInfo = await supertokens.getUser(userId);

  /**
   *
   * userInfo contains the following info:
   * - emails
   * - id
   * - timeJoined
   * - tenantIds
   * - phone numbers
   * - third party login info
   * - all the login methods associated with this user.
   * - information about if the user's email is verified or not.
   *
   */
}
```

</ConditionalContent>
</ContentOption>
<ContentOption title="Nestjs" value="nestjs">
```tsx check=false reason="Requires surrounding framework application context"
import { Controller, Post, UseGuards, Request, Response } from "@nestjs/common";
import { AuthGuard } from "./auth/auth.guard";
import { Session } from "./auth/session.decorator";
import { SessionRequest } from "supertokens-node/framework/express";
import supertokens from "supertokens-node";

@Controller()
export class ExampleController {
  @Post("example")
  @UseGuards(new AuthGuard()) // For more information about this guard please read our NestJS guide.
  async postExample(
    @Request() req: SessionRequest,
    @Session() session: Session,
    @Response({ passthrough: true }) res: Response,
  ): Promise<boolean> {
    let userId = session.getUserId();

    let userInfo = await supertokens.getUser(userId);

    /**
     *
     * userInfo contains the following info:
     * - emails
     * - id
     * - timeJoined
     * - tenantIds
     * - phone numbers
     * - third party login info
     * - all the login methods associated with this user.
     * - information about if the user's email is verified or not.
     *
     */
    return true;
  }
}
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="Go" value="go">
<DependentContent group="go-frameworks" label="Go framework">
<ContentOption title="Http" value="http">
```go
import (
	"fmt"
	"net/http"

	"github.com/supertokens/supertokens-golang/recipe/session"
	"github.com/supertokens/supertokens-golang/recipe/emailpassword"
)

func main() {
	_ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		session.VerifySession(nil, getUserInfoAPI).ServeHTTP(rw, r)
	})
}

func getUserInfoAPI(w http.ResponseWriter, r *http.Request) {
	sessionContainer := session.GetSessionFromRequestContext(r.Context())

	userID := sessionContainer.GetUserID()
	// You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki
    userInfo, err := emailpassword.GetUserByID(userID)
	if err != nil {
		// TODO: Handle error
		return
	}
	fmt.Println(userInfo)
}
```
</ContentOption>
<ContentOption title="Gin" value="gin">
```go
import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/supertokens/supertokens-golang/recipe/session"
	"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
	"github.com/supertokens/supertokens-golang/recipe/emailpassword"
)

func main() {
	router := gin.New()
	router.GET("/getuserinfo", verifySession(nil), getUserInfoAPI)
}

func verifySession(options *sessmodels.VerifySessionOptions) gin.HandlerFunc {
	return func(c *gin.Context) {
		session.VerifySession(options, func(rw http.ResponseWriter, r *http.Request) {
			c.Request = c.Request.WithContext(r.Context())
			c.Next()
		})(c.Writer, c.Request)
		// we call Abort so that the next handler in the chain is not called, unless we call Next explicitly
		c.Abort()
	}
}

func getUserInfoAPI(c *gin.Context) {
	sessionContainer := session.GetSessionFromRequestContext(c.Request.Context())

	userID := sessionContainer.GetUserID()

	// You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki
    userInfo, err := emailpassword.GetUserByID(userID)
	if err != nil {
		// TODO: Handle error
		return
	}
	fmt.Println(userInfo)
	//...
}
```
</ContentOption>
<ContentOption title="Chi" value="chi">
```go
import (
	"fmt"
	"net/http"

	"github.com/go-chi/chi"
	"github.com/supertokens/supertokens-golang/recipe/session"
	"github.com/supertokens/supertokens-golang/recipe/emailpassword"
)

func main() {
	r := chi.NewRouter()
	r.Get("/getuserinfo", session.VerifySession(nil, getUserInfoAPI))
}

func getUserInfoAPI(w http.ResponseWriter, r *http.Request) {
	sessionContainer := session.GetSessionFromRequestContext(r.Context())

	userID := sessionContainer.GetUserID()
	// You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki
	userInfo, err := emailpassword.GetUserByID(userID)
	if err != nil {
		// TODO: Handle error
		return
	}
	fmt.Println(userInfo)
}
```
</ContentOption>
<ContentOption title="Mux" value="mux">
```go
import (
	"fmt"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/supertokens/supertokens-golang/recipe/session"
	"github.com/supertokens/supertokens-golang/recipe/emailpassword"
)

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/getuserinfo", session.VerifySession(nil, getUserInfoAPI)).Methods(http.MethodGet)
}

func getUserInfoAPI(w http.ResponseWriter, r *http.Request) {
	sessionContainer := session.GetSessionFromRequestContext(r.Context())

	userID := sessionContainer.GetUserID()
	// You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki
	userInfo, err := emailpassword.GetUserByID(userID)
	if err != nil {
		// TODO: Handle error
		return
	}
	fmt.Println(userInfo)
}
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-frameworks" label="Python framework">
<ContentOption title="FastAPI" value="fastapi">
```python
from fastapi import Depends, FastAPI

from supertokens_python.asyncio import get_user
from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.framework.fastapi import verify_session

app = FastAPI()

@app.post('/get_user_info_api')
async def get_user_info_api(session: SessionContainer = Depends(verify_session())):
    user_id = session.get_user_id()

    # You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki
    _ = await get_user(user_id)
```
</ContentOption>
<ContentOption title="Flask" value="flask">
```python check=false reason="Requires surrounding framework application context"
from flask import Flask, g

from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.framework.flask import verify_session
from supertokens_python.syncio import get_user

app = Flask(__name__)

@app.route('/get_user_info', methods=['GET'])
@verify_session()
def get_user_info_api():
    session: SessionContainer = g.supertokens

    user_id = session.get_user_id()

    # You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki
    _ = get_user(user_id)
```
</ContentOption>
<ContentOption title="Django" value="django">
```python check=false reason="Requires surrounding async application context"
from typing import cast

from django.http import HttpRequest

from supertokens_python.asyncio import get_user
from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.framework.django.asyncio import verify_session


@verify_session()
async def get_user_info_api(request: HttpRequest):
    session: SessionContainer = cast(SessionContainer, request.supertokens)

    user_id = session.get_user_id()

    # You can learn more about the `User` object over here https://github.com/supertokens/core-driver-interface/wiki
    _ = await get_user(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 { 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();

    let userInfo = await SuperTokens.getUser(userId);

    /**
     *
     * userInfo contains the following info:
     * - emails
     * - id
     * - timeJoined
     * - tenantIds
     * - phone numbers
     * - third party login info
     * - all the login methods associated with this user.
     * - information about if the user's email is verified or not.
     *
     */
    return NextResponse.json({});
  });
}
```

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

:::info[Tip]
The authentication session also contains the user ID and the session payload.
You can access it on [both the backend and the frontend](/additional-verification/session-verification/claim-validation#using-the-access-token-payload).

:::

#### Using the user metadata recipe

Checkout the [user metadata recipe docs](/post-authentication/user-management/user-metadata) which shows you how to save and fetch any JSON object against the user's ID. You can use this to save information like the user's name (`first_name` and `last_name`) or any other field associated with the user.


---

## Delete user


<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import { deleteUser } from "supertokens-node";

async function deleteUserForId() {
  let userId = "..."; // get the user ID
  await deleteUser(userId); // this will succeed even if the userId didn't exist.
}
```
</Tab>
<Tab title="Go" value="go">
```go
import "github.com/supertokens/supertokens-golang/supertokens"

func main() {
	userId := "..." // get the user ID somehow...
	supertokens.DeleteUser(userId) // this will succeed even if the userId didn't exist.
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.asyncio import delete_user


async def do_delete():
    user_id = "..." # get the user ID somehow...
    await delete_user(user_id) # this will succeed even if the userId didn't exist.
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.syncio import delete_user


user_id = "..." # get the user ID somehow...
delete_user(user_id) # this will succeed even if the userId didn't exist.
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

:::warning[- Calling this function permanently removes all information associated with this user, including their sessions.]
- Deletion removes the user's database sessions, but it does not immediately invalidate an already-issued stateless access
  token. Without `checkDatabase: true`, that token can continue to pass session verification until it expires. Enable an
  authoritative database check on every endpoint that must reject the deleted user immediately. After the access token
  expires, refresh fails because the database session no longer exists.
:::


---

## List users

### Newest first

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import { getUsersNewestFirst } from "supertokens-node";

async function getUsers() {
  // get the latest 100 users
  let usersResponse = await getUsersNewestFirst({
    tenantId: "public",
  });

  let users = usersResponse.users;
  let nextPaginationToken = usersResponse.nextPaginationToken;

  // get the next 200 users
  usersResponse = await getUsersNewestFirst({
    tenantId: "public",
    limit: 200,
    paginationToken: nextPaginationToken,
  });

  users = usersResponse.users;
  nextPaginationToken = usersResponse.nextPaginationToken;

  // get for specific recipes
  usersResponse = await getUsersNewestFirst({
    tenantId: "public",
    limit: 200,
    paginationToken: nextPaginationToken,
    // only get for those users who signed up with <RECIPE_NAME>
    includeRecipeIds: ["<RECIPE_ID>"],
  });

  users = usersResponse.users;
  nextPaginationToken = usersResponse.nextPaginationToken;
}
```
</Tab>
<Tab title="Go" value="go">
```go
import "github.com/supertokens/supertokens-golang/supertokens"

func main() {
	// get the latest 100 users
	result, err := supertokens.GetUsersNewestFirst("", nil, nil, nil, nil)
	if err != nil {
		// TODO: Handle error
		return
	}

	// get the next 200 users
	limit := 200
	result, err = supertokens.GetUsersNewestFirst("", result.NextPaginationToken, &limit, nil, nil)
	if err != nil {
		// TODO: Handle error
		return
	}

	// get for specific recipes
	includeRecipeIds := []string{"<RECIPE_ID>"}
	result, err = supertokens.GetUsersNewestFirst("", result.NextPaginationToken, &limit, &includeRecipeIds, nil)
	if err != nil {
		// TODO: Handle error
		return
	}
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.asyncio import get_users_newest_first


async def some_func():
	# get the latest 100 users
	users_response = await get_users_newest_first("public")

	# get the next 200 users
	users_response = await get_users_newest_first("public", 200, users_response.next_pagination_token)

	# get for specific recipes
	users_response = await get_users_newest_first(
		"public",
		200,
		users_response.next_pagination_token,
		# only get for those users who signed up with <RECIPE_NAME>
		["<RECIPE_ID>"]
	)
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.syncio import get_users_newest_first


# get the latest 100 users
users_response = get_users_newest_first("public")

# get the next 200 users
users_response = get_users_newest_first("public", 200, users_response.next_pagination_token)

# get for specific recipes
users_response = get_users_newest_first(
	"public",
	200,
	users_response.next_pagination_token,
	# only get for those users who signed up with <RECIPE_NAME>
	["<RECIPE_ID>"]
)

```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

### Oldest first

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```ts
import { getUsersOldestFirst } from "supertokens-node";

async function getUsers() {
  // get the latest 100 users
  let usersResponse = await getUsersOldestFirst({
    tenantId: "public",
  });
  let users = usersResponse.users;
  let nextPaginationToken = usersResponse.nextPaginationToken;

  // get the next oldest 200 users
  usersResponse = await getUsersOldestFirst({
    tenantId: "public",
    limit: 200,
    paginationToken: nextPaginationToken,
  });

  users = usersResponse.users;
  nextPaginationToken = usersResponse.nextPaginationToken;

  // get for specific recipes
  usersResponse = await getUsersOldestFirst({
    tenantId: "public",
    limit: 200,
    paginationToken: nextPaginationToken,
    // only get for those users who signed up with <RECIPE_NAME>
    includeRecipeIds: ["<RECIPE_ID>"],
  });

  users = usersResponse.users;
  nextPaginationToken = usersResponse.nextPaginationToken;
}
```
</Tab>
<Tab title="Go" value="go">
```go
import "github.com/supertokens/supertokens-golang/supertokens"

func main() {
	// get the oldest 100 users
	result, err := supertokens.GetUsersOldestFirst("", nil, nil, nil, nil)
	if err != nil {
		// TODO: Handle error
		return
	}

	// get the next oldest 200 users
	limit := 200
	result, err = supertokens.GetUsersOldestFirst("", result.NextPaginationToken, &limit, nil, nil)
	if err != nil {
		// TODO: Handle error
		return
	}

	// get for specific recipes
	includeRecipeIds := []string{"<RECIPE_ID>"}
	result, err = supertokens.GetUsersOldestFirst("", result.NextPaginationToken, &limit, &includeRecipeIds, nil)
	if err != nil {
		// TODO: Handle error
		return
	}
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.asyncio import get_users_oldest_first


async def some_func():
	# get the latest 100 users
	users_response = await get_users_oldest_first("public")

	# get the next 200 users
	users_response = await get_users_oldest_first("public", 200, users_response.next_pagination_token)

	# get for specific recipes
	users_response = await get_users_oldest_first(
		"public",
		200,
		users_response.next_pagination_token,
		# only get for those users who signed up with <RECIPE_NAME>
		["<RECIPE_ID>"]
	)
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.syncio import get_users_oldest_first


# get the latest 100 users
users_response = get_users_oldest_first("public")

# get the next 200 users
users_response = get_users_oldest_first("public", 200, users_response.next_pagination_token)

# get for specific recipes
users_response = get_users_oldest_first(
	"public",
	200,
	users_response.next_pagination_token,
	# only get for those users who signed up with <RECIPE_NAME>
	["<RECIPE_ID>"]
)

```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

<DependentContent passive group="backend-language">
<ContentOption title="Node.js" value="nodejs">
- If the `nextPaginationToken` is `undefined`, then there are no more users to loop through.
- If there are no users in your app, then `nextPaginationToken` is `undefined` and `users` is an empty array
- Each element in the `users` array is according to the output of the core API as shown in the [API documentation](https://app.swaggerhub.com/apis/supertokens/CDI/2.8.0#/Core/getUsers).
</ContentOption>
<ContentOption title="Go" value="go">
- If the `result.NextPaginationToken` is `nil`, then there are no more users to loop through.
- If there are no users in your app, then `result.NextPaginationToken` is `nil` and `result.Users` is an empty array
- Each element in the `result.Users` array is according to the output of the core API as shown in the [API documentation](https://app.swaggerhub.com/apis/supertokens/CDI/2.8.0#/Core/getUsers).
</ContentOption>
</DependentContent>

:::info[Multi Tenancy]
Notice that the `tenantId` appears as `"public"`. This means that the functions above loop through the users of the `public` `tenantId`. If you want to loop through other tenant IDs, you can pass in the tenant ID string to the function call.

This also implies that there is no way to loop through all users across all tenants in one go. If you want to do this, you must loop through each tenant one by one.
:::

---

## Count users

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```ts
import { getUserCount } from "supertokens-node";

async function getCount() {
  let count = await getUserCount();
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"fmt"

	"github.com/supertokens/supertokens-golang/supertokens"
)

func main() {
	tenantId := ""
	count, err := supertokens.GetUserCount(nil, &tenantId)
	if err != nil {
		// TODO: Handle error
		return
	}

	fmt.Println(count)
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.asyncio import get_user_count


async def some_func():
    user_count = await get_user_count()

    print(user_count) # TODO..
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.syncio import get_user_count


user_count = get_user_count()

```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

:::info[Multi Tenancy]
By default, the getUserCount function returns the number of users across all tenants. If you want to get the number of users for a specific tenant, you can pass in the tenant ID string to the function call.
:::
