# Status

**URL:** https://heroiclabs.com/docs/nakama/concepts/status/
**Summary:** Nakama users can set a status message when they connect and update it while they're online. The status is set for each connection, and is erased when the user disconnects. Users can follow each other to be notified of status changes. This is ideal to know when their friends are online and what they're up to.
**Keywords:** set status, appear offline, receive status updates, follow users, unfollow users
**Categories:** nakama, status, concepts

---


# Status

Nakama users can set a status message when they connect and update it while they're online.

Users can follow each other to be notified of status changes. This is ideal to know when their friends are online and what they're up to.

The status is set for each connection, and is erased when the user disconnects. If the user is connected from multiple devices each one is allowed to have a different status.

## Set a status

By default users have no status when they first connect, and will not appear online to their followers. To appear online the user must set a status.

A status can be as simple as a text message from the user to their followers or it can be a structured JSON string with complex information such as the [real-time multiplayer match ID](../multiplayer/relayed/) the user is currently in - so their friends can jump in and join them!

{{< code type="client" >}}
```javascript
socket.updateStatus("Hello everyone!");
```
{{< / code >}}

{{< code type="client" >}}
```csharp
await socket.UpdateStatusAsync("Hello everyone!");
```
{{< / code >}}

{{< code type="client" >}}
```swift
try await socket.updateStatus(status: "Hello everyone!")
```
{{< / code >}}

{{< code type="client" >}}
```dart
await socket.updateStatus('Hello everyone!');
```
{{< / code >}}

{{< code type="client" >}}
```cpp
rtClient->updateStatus("Hello everyone!");
```
{{< / code >}}

{{< code type="client" >}}
```java
socket.updateStatus("Hello everyone!").get();
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var update : NakamaAsyncResult = yield(socket.update_status_async(JSON.print({"status": "happy"})), "completed")
if update.is_exception():
    print("An error occurred: %s" % update)
    return
print("Status updated")
```
{{< / code >}}

{{< code type="client" framework="godot4" >}}
```gdscript
var update : NakamaAsyncResult = await socket.update_status_async(JSON.stringify({"status": "happy"}))
if update.is_exception():
    print("An error occurred: %s" % update)
    return
print("Status updated")
```
{{< / code >}}

{{< code type="client" framework="defold" >}}
```lua
socket.status_update(socket, "Hello everyone!")
```
{{< / code >}}

{{< missing type="client" lang="bash" />}}
{{< missing type="client" lang="shell" />}}

The status can be set and updated as often as needed with this operation.

## Appear offline

If the user needs to appear offline or "invisible" they can do so by erasing their status. Their followers will receive the same status update as they would if the user disconnects.

{{< code type="client" >}}
```javascript
socket.updateStatus();
```
{{< / code >}}

{{< code type="client" >}}
```csharp
await socket.UpdateStatusAsync(null);
```
{{< / code >}}

{{< code type="client" >}}
```swift
try await socket.updateStatus(status: "")
```
{{< / code >}}

{{< code type="client" >}}
```dart
await socket.updateStatus('');
```
{{< / code >}}

{{< code type="client" >}}
```cpp
rtClient->updateStatus("");
```
{{< / code >}}

{{< code type="client" >}}
```java
socket.updateStatus(null).get();
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var leave : NakamaAsyncResult = yield(socket.update_status_async(""), "completed")
if leave.is_exception():
    print("An error occurred: %s" % leave)
    return
print("Status updated")
```
{{< / code >}}

{{< code type="client" framework="godot4" >}}
```gdscript
var leave : NakamaAsyncResult = await socket.update_status_async("")
if leave.is_exception():
    print("An error occurred: %s" % leave)
    return
print("Status updated")
```
{{< / code >}}

{{< code type="client" framework="defold" >}}
```lua
socket.status_update("")
```
{{< / code >}}

{{< missing type="client" lang="bash" />}}
{{< missing type="client" lang="shell" />}}

## Receive status updates

When a user updates their status all of their followers receive an event that contains both the old status and the new one. Clients register an event handler to be called when receiving a status update.

{{< code type="client" >}}
```javascript
socket.onstatuspresence = (statuspresence) => {
    statuspresence.leaves.forEach((leave) => {
        console.log("User %o no longer has status %o", leave.user_id, leave.status);
    });
    statuspresence.joins.forEach((join) => {
        console.log("User %o now has status %o", join.user_id, join.status);
    });
};
```
{{< / code >}}

{{< code type="client" >}}
```csharp
socket.ReceivedStatusPresence += presenceEvent =>
{
    Console.WriteLine(presenceEvent);
    foreach (var joined in presenceEvent.Joins)
    {
        Console.WriteLine("User id '{0}' status joined '{1}'", joined.UserId, joined.Status);
    }
    foreach (var left in presenceEvent.Leaves)
    {
        Console.WriteLine("User id '{0}' status left '{1}'", left.UserId, left.Status);
    }
};
```
{{< / code >}}

{{< code type="client" >}}
```swift
socket.onStatusPresence = { presence in
    for join in presence.joins {
        print("User ID: \(join.userID) Username: \(join.username) Status: \(join.status)")
    }
    for leave in presence.leaves {
        print("User ID: \(leave.userID) Username: \(leave.username) Status: \(leave.status)")
    }
}
```
{{< / code >}}

{{< code type="client" >}}
```dart
socket.onStatusPresence.listen((presence) {
  for (final join in presence.joins) {
    print('User ID: ${join.userId} Username: ${join.username} Status: ${join.status}');
  }
  for (final leave in presence.leaves) {
    print('User ID: ${leave.userId} Username: ${leave.username} Status: ${leave.status}');
  }
});
```
{{< / code >}}

{{< code type="client" >}}
```cpp
rtListener->setStatusPresenceCallback([](const NStatusPresenceEvent& event)
{
    for (auto& presence : event.leaves)
    {
        std::cout << "User " << presence.username << " no longer has status " << presence.status << std::endl;
    }

    for (auto& presence : event.joins)
    {
        std::cout << "User " << presence.username << " now has status " << presence.status << std::endl;
    }
});
```
{{< / code >}}

{{< code type="client" >}}
```java
SocketListener listener = new AbstractSocketListener() {
    @Override
    public void onStatusPresence(final StatusPresenceEvent presence) {
        for (UserPresence userPresence : presence.getJoins()) {
            System.out.println("User ID: " + userPresence.getUserId() + " Username: " + userPresence.getUsername() + " Status: " + userPresence.getStatus());
        }

        for (UserPresence userPresence : presence.getLeaves()) {
            System.out.println("User ID: " + userPresence.getUserId() + " Username: " + userPresence.getUsername() + " Status: " + userPresence.getStatus());
        }
    }
};
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
func _ready():
    # First, setup the socket as explained in the authentication section.
    socket.connect("received_status_presence", self, "_on_status_presence")

func _on_status_presence(p_presence : NakamaRTAPI.StatusPresenceEvent):
    print(p_presence)
    for j in p_presence.joins:
        print("%s joined with status: %s" % [j.user_id, j.status])
    for j in p_presence.leaves:
        print("%s left with status: %s" % [j.user_id, j.status])
```
{{< / code >}}

{{< code type="client" framework="godot4" >}}
```gdscript
func _ready():
    # First, setup the socket as explained in the authentication section.
    socket.received_status_presence.connect(self._on_status_presence)

func _on_status_presence(p_presence : NakamaRTAPI.StatusPresenceEvent):
    print(p_presence)
    for j in p_presence.joins:
        print("%s joined with status: %s" % [j.user_id, j.status])
    for j in p_presence.leaves:
        print("%s left with status: %s" % [j.user_id, j.status])
```
{{< / code >}}

{{< code type="client" framework="defold" >}}
```lua
socket.on_status_presence_event(function(presences)
    for i,leave in ipairs(presences.leaves) do
        print(("User %s no longer has status %s"):format(leave.user_id, leave.status))
    end
    for i,join in ipairs(presences.joins) do
        print(("User %s now has status %s"):format(join.user_id, join.status))
    end
end)
```
{{< / code >}}

{{< missing type="client" lang="bash" />}}
{{< missing type="client" lang="shell" />}}

If a user is disconnected or appears offline, they will leave their previous status but there will be no corresponding new status.

## Follow users

Users only receive status updates from those they follow. Users can follow anyone they're interested in, but it's common to follow a list of friends to see when they're online and what they're up to.

When following a set of users, the operation will immediately return the status of those that are online and have set a visible status.

Following a user is only active with the current session. When the user disconnects they automatically unfollow anyone they may have followed while connected.

{{< code type="client" >}}
```javascript
var status = await socket.followUsers(["<user id>"]);
status.presences.forEach((presence) => {
  console.log("User %o has status %o", presence.user_id, presence.status);
});
```
{{< / code >}}

{{< code type="client" >}}
```csharp
await socket.FollowUsersAsync(new[] { "<user id>" });
```
{{< / code >}}

{{< code type="client" >}}
```swift
try await socket.followUsers(userIds: ["<user id>"])
```
{{< / code >}}

{{< code type="client" >}}
```dart
var status = await socket.followUsers(['<user id>']);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto successCallback = [](const NStatus& status)
{
    for (auto& presence : status.presences)
    {
        std::cout << "User " << presence.username << " has status " << presence.status << std::endl;
    }
};

rtClient->followUsers({ "<user id>" }, successCallback);
```
{{< / code >}}

{{< code type="client" >}}
```java
socket.followUsers("<user id>").get();
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var user_ids = ["<user-id1>", "<user-id2>"]
var status : NakamaRTAPI.Status = yield(socket.follow_users_async(user_ids), "completed")
if status.is_exception():
    print("An error occurred: %s" % status)
    return
print(status)
```
{{< / code >}}

{{< code type="client" framework="godot4" >}}
```gdscript
var user_ids = ["<user-id1>", "<user-id2>"]
var status : NakamaRTAPI.Status = await socket.follow_users_async(user_ids)
if status.is_exception():
    print("An error occurred: %s" % status)
    return
print(status)
```
{{< / code >}}

{{< code type="client" framework="defold" >}}
```lua
local user_ids = { "<user id>" }
socket.status_follow(user_ids)
```
{{< / code >}}

{{< missing type="client" lang="bash" />}}
{{< missing type="client" lang="shell" />}}

## Unfollow users

Unfollowing a set of users immediately stops the user from receiving any further status updates from them.

{{< code type="client" >}}
```javascript
socket.unfollowUsers(["<user id>"]);
```
{{< / code >}}

{{< code type="client" >}}
```csharp
await socket.UnfollowUsersAsync(new[] { "<user id>" });
```
{{< / code >}}

{{< code type="client" >}}
```swift
try await socket.unfollowUsers(userIds: ["<user id>"])
```
{{< / code >}}

{{< code type="client" >}}
```dart
await socket.unfollowUsers(['<user id>']);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
rtClient->unfollowUsers({ "<user id>" });
```
{{< / code >}}

{{< code type="client" >}}
```java
socket.unfollowUsers("<user id>").get();
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var user_ids = ["<user-id1>", "<user-id2>"]
var status : NakamaAsyncResult = yield(socket.unfollow_users_async(user_ids), "completed")
if status.is_exception():
    print("An error occurred: %s" % status)
    return
print(status)
```
{{< / code >}}

{{< code type="client" framework="godot4" >}}
```gdscript
var user_ids = ["<user-id1>", "<user-id2>"]
var status : NakamaAsyncResult = await socket.unfollow_users_async(user_ids)
if status.is_exception():
    print("An error occurred: %s" % status)
    return
print(status)
```
{{< / code >}}
