---
source_url: https://www.pubnub.com/docs/sdks/unreal/api-reference/presence
title: Presence API for Unreal SDK
updated_at: 2026-06-18T11:29:02.496Z
sdk_name: PubNub Unreal SDK
sdk_version: 2.0.5
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Presence API for Unreal SDK

PubNub Unreal SDK, use the latest version: 2.0.5

Presence lets you track who is online or offline and store custom state information. Presence shows:

* When a user has joined or left a channel
* How many users are subscribed to a particular channel (occupancy)
* Which channels a user or device is subscribed to
* Presence state associated with these users

Learn more about our Presence feature in the [Presence overview](https://www.pubnub.com/docs/general/presence/overview).

##### Usage in Blueprints and C++

You can use PubNub's functionality via Blueprints or directly in C++ code.

* In Blueprints, the SDK is managed by a subsystem. Start by calling the Pubnub Subsystem node, then use Create Pubnub Client to create a UPubnubClient instance.
* In a C++ project, you have to add a dependency to PubnubLibrary: In your IDE, navigate to Source/_{YourProject}_/_{YourProject}_.Build.cs and add a dependency to PubnubLibrary. PrivateDependencyModuleNames.AddRange(new string[] { "PubnubLibrary" });, Compile the code and run the project.
* In C++, start by getting the UPubnubSubsystem (a Game Instance Subsystem), then create a UPubnubClient with your configuration. #include "Kismet/GameplayStatics.h"#include "PubnubSubsystem.h"#include "PubnubClient.h" UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(this);UPubnubSubsystem* PubnubSubsystem = GameInstance->GetSubsystem<UPubnubSubsystem>(); FPubnubConfig Config;Config.PublishKey = "pub-c-...";Config.SubscribeKey = "sub-c-...";Config.UserId = "my-user-id"; UPubnubClient* PubnubClient = PubnubSubsystem->CreatePubnubClient(Config); PubnubClient allows you to call PubNub SDK functions, for example: PubnubClient->PublishMessageAsync("my-channel", "Hello!", OnPublishMessageResponseDelegate); The SDK supports multiple UPubnubClient instances within the same game for different contexts such as different users or keysets. For more information, refer to Configuration.

:::note Asynchronous and synchronous method execution
Most PubNub Unreal SDK methods are available in both asynchronous and synchronous variants.
* Asynchronous methods (Async suffix) return void and take an optional delegate parameter that fires when the operation completes. 1PubnubClient->ListUsersFromChannelAsync("my-channel", OnListUsersFromChannelResponseDelegate); You can also use native callbacks that accept lambdas instead of dynamic delegates. Native callback types have the Native suffix (for example, FOnPubnubListUsersFromChannelResponseNative).
* Synchronous methods (no suffix) block the main game thread until the operation completes and return a result struct directly. 1FPubnubListUsersFromChannelResult Result = PubnubClient->ListUsersFromChannel("my-channel");
:::

## List users from channel

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

This method returns information about the current state of a channel, including a list of unique user IDs (universally unique identifiers, UUIDs) currently subscribed to the channel and the total occupancy count of the channel.

:::note Cache
This method has a 3-second response cache time.
:::

:::warning Breaking change
The `ListUsersFromChannel` method now returns a maximum of 1,000 occupants per channel. Previously, it returned all occupants regardless of count. If you have channels with more than 1,000 occupants, you must use pagination (`Limit` and `Offset` parameters in `FPubnubListUsersFromChannelSettings`) to retrieve the complete list.
:::

You can call `ListUsersFromChannel()` on a [Channel entity](#list-users-channel-entity) (which already knows its channel) or directly on the [PubNub client](#list-users-pubnub-client) by passing the channel name explicitly.

### Channel entity

##### Available in entities

This method is available to use with the `Channel` entity. For more information, refer to [Channel](https://www.pubnub.com/docs/sdks/unreal/entities/channel).

#### Method(s)

To list users from a channel, you must first create a [Channel entity](https://www.pubnub.com/docs/sdks/unreal/entities/channel) where you provide the name of the channel you want to get presence information from.

```cpp
UPubnubChannelEntity* ChannelEntity = PubnubSubsystem->CreateChannelEntity("my-channel");

ChannelEntity->ListUsersFromChannel(
    FOnListUsersFromChannelResponse ListUsersFromChannelResponse,
    FPubnubListUsersFromChannelSettings ListUsersFromChannelSettings = FPubnubListUsersFromChannelSettings()
);
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| ListUsersFromChannelResponse | FOnListUsersFromChannelResponse | Yes |  | The delegate for the operation's result. You can also use a native callback of the type [FOnListUsersFromChannelResponseNative](#fonlistusersfromchannelresponsenative) to handle the result using a lambda. |
| ListUsersFromChannelSettings | FPubnubListUsersFromChannelSettings | Optional |  | A struct defining the method's configuration. |

##### FPubnubListUsersFromChannelSettings

| Parameter | Description |
| --- | --- |
| `ChannelGroups`Type: `FString` | Comma-delimited list of channel group names. Not used if empty. Wildcards are not supported. |
| `DisableUserID`Type: bool | Whether to disable including the user IDs of the connected clients in the response. Default is `true`. |
| `State`Type: bool | Whether to including the state of the connected clients in the response. Default is `false`. |
| `Limit`Type: `int` | Maximum number of occupants to return per channel. Valid range: `1`-`1000`. Default is `1000`. |
| `Offset`Type: `int` | Zero-based starting index for pagination. Returns occupants starting from this position. Use with `Limit` to paginate through large occupant lists. Default is `0`. |

#### Sample code

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

###### C++

##### Actor.h

```cpp
#include "PubnubClient.h"
#include "Entities/PubnubChannelEntity.h"
#include "Entities/PubnubSubscription.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|ChannelEntity")
void ListUsersFromChannelSample();

UFUNCTION()
void OnListUsersFromChannelResponse_Simple(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data);
```

##### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChannelEntity with name of your Actor class
void ASample_ChannelEntity::ListUsersFromChannelSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Create a channel entity for the channel you want to list users from
	FString ChannelName = TEXT("guild-channel");
	UPubnubChannelEntity* ChannelEntity = PubnubClient->CreateChannelEntity(ChannelName);

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_ChannelEntity with name of your Actor class
	FOnPubnubListUsersFromChannelResponse OnListUsersFromChannelResponse;
	OnListUsersFromChannelResponse.BindDynamic(this, &ASample_ChannelEntity::OnListUsersFromChannelResponse_Simple);

	// List users from the channel using the channel entity
	ChannelEntity->ListUsersFromChannelAsync(OnListUsersFromChannelResponse);
}

// ACTION REQUIRED: Replace ASample_ChannelEntity with name of your Actor class
void ASample_ChannelEntity::OnListUsersFromChannelResponse_Simple(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to list users from channel. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Users successfully listed from channel. Occupancy: %d"), Data.Occupancy);
	}
}
```

#### Returns

This function is void, but the delegate returns the [FOnListUsersFromChannelResponse](#fonlistusersfromchannelresponse) struct.

##### FOnListUsersFromChannelResponse

| Field | Type | Description |
| --- | --- | --- |
| `Result` | [FPubnubOperationResult](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `Data` | [FPubnubListUsersFromChannelWrapper](#fpubnublistusersfromchannelwrapper) | A struct containing the result of the operation. |

##### FPubnubListUsersFromChannelWrapper

| Field | Type | Description |
| --- | --- | --- |
| `Occupancy` | `int` | The number of users in a given channel. |
| `UsersState` | `TMap<FString, FString>` | A map of user IDs and their respective [state](#user-state). |

##### FOnListUsersFromChannelResponseNative

| Field | Type | Description |
| --- | --- | --- |
| `Result` | [const FPubnubOperationResult&](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `Data` | [const FPubnubListUsersFromChannelWrapper&](#fpubnublistusersfromchannelwrapper) | A struct containing the result of the operation. |

#### Other examples

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

##### Return occupancy only

You can return only the `occupancy` information for a single channel by specifying the channel and setting `DisableUserID` to `false`:

###### Actor.h

```cpp
#include "PubnubClient.h"
#include "Entities/PubnubChannelEntity.h"
#include "Entities/PubnubSubscription.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|ChannelEntity")
void ListUsersFromChannelWithSettingsSample();

UFUNCTION()
void OnListUsersFromChannelResponse_WithSettings(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data);
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChannelEntity with name of your Actor class
void ASample_ChannelEntity::ListUsersFromChannelWithSettingsSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Create a channel entity for the channel you want to list users from
	FString ChannelName = TEXT("guild-channel");
	UPubnubChannelEntity* ChannelEntity = PubnubClient->CreateChannelEntity(ChannelName);

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_ChannelEntity with name of your Actor class
	FOnPubnubListUsersFromChannelResponse OnListUsersFromChannelResponse;
	OnListUsersFromChannelResponse.BindDynamic(this, &ASample_ChannelEntity::OnListUsersFromChannelResponse_WithSettings);

	// Create additional settings
	FPubnubListUsersFromChannelSettings Settings;
	Settings.State = true;
	Settings.DisableUserID = false;

	// List users from the channel with settings using the channel entity
	ChannelEntity->ListUsersFromChannelAsync(OnListUsersFromChannelResponse, Settings);
}

// ACTION REQUIRED: Replace ASample_ChannelEntity with name of your Actor class
void ASample_ChannelEntity::OnListUsersFromChannelResponse_WithSettings(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to list users from channel. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Users successfully listed from channel. Total occupancy: %d"), Data.Occupancy);
		// List all users with theirs states
		for (auto const& [UserID, UserState] : Data.UsersState)
		{
			UE_LOG(LogTemp, Log, TEXT("UserID: %s, User State: %s"), *UserID, *UserState);
		}
	}
}
```

##### Use lambda

You can use a lambda function to handle the response:

###### Actor.h

```cpp
#include "PubnubClient.h"
#include "Entities/PubnubChannelEntity.h"
#include "Entities/PubnubSubscription.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|ChannelEntity")
void ListUsersFromChannelWithLambdaSample();
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChannelEntity with name of your Actor class
void ASample_ChannelEntity::ListUsersFromChannelWithLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Create a channel entity for the channel you want to list users from
	FString ChannelName = TEXT("guild-channel");
	UPubnubChannelEntity* ChannelEntity = PubnubClient->CreateChannelEntity(ChannelName);

	// Bind lambda to response delegate
	FOnPubnubListUsersFromChannelResponseNative OnListUsersFromChannelResponse;
	OnListUsersFromChannelResponse.BindLambda([](const FPubnubOperationResult& Result, const FPubnubListUsersFromChannelWrapper& Data)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to list users from channel. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Users successfully listed from channel. Occupancy: %d"), Data.Occupancy);
		}
	});
	
	// List users from the channel using the channel entity
	ChannelEntity->ListUsersFromChannelAsync(OnListUsersFromChannelResponse);
}
```

### PubNub client

#### Method(s)

```cpp
PubnubClient->ListUsersFromChannelAsync(
    FString Channel,
    FOnPubnubListUsersFromChannelResponse ListUsersFromChannelResponse,
    FPubnubListUsersFromChannelSettings ListUsersFromChannelSettings = FPubnubListUsersFromChannelSettings()
);
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `FString` | The channel to get the presence details of. |
| `ListUsersFromChannelResponse` *Type: [FOnPubnubListUsersFromChannelResponse](#fonpubnublistusersfromchannelresponse) | The delegate for the operation's result. You can also use a native callback of the type [FOnPubnubListUsersFromChannelResponseNative](#fonpubnublistusersfromchannelresponsenative) to handle the result using a lambda. |
| `ListUsersFromChannelSettings`Type: [FPubnubListUsersFromChannelSettings](#fpubnublistusersfromchannelsettings) | A struct defining the method's configuration. |

#### Sample code

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

###### C++

##### Actor.h

```cpp
#include "PubnubClient.h"

// blueprint.w-qs5s7j
UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Presence")
void ListUsersFromChannelSample();

UFUNCTION()
void OnListUsersFromChannelResponse_Simple(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data);
```

##### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::ListUsersFromChannelSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
	FOnPubnubListUsersFromChannelResponse OnListUsersFromChannelResponse;
	OnListUsersFromChannelResponse.BindDynamic(this, &ASample_Presence::OnListUsersFromChannelResponse_Simple);

	//List users from a channel
	FString Channel = TEXT("guild-channel");
	PubnubClient->ListUsersFromChannelAsync(Channel, OnListUsersFromChannelResponse);
}

// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::OnListUsersFromChannelResponse_Simple(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to list users from channel. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Users successfully listed from channel. Occupancy: %d"), Data.Occupancy);
	}
}
```

###### Blueprint

#### Returns

This method is void. The delegate returns the following struct:

##### FOnPubnubListUsersFromChannelResponse

| Field | Type | Description |
| --- | --- | --- |
| `Result` | [FPubnubOperationResult](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `Data` | [FPubnubListUsersFromChannelWrapper](#fpubnublistusersfromchannelwrapper) | A struct containing occupancy and user state information for the channel. |

##### FOnPubnubListUsersFromChannelResponseNative

| Field | Type | Description |
| --- | --- | --- |
| `Result` | [const FPubnubOperationResult&](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `Data` | [const FPubnubListUsersFromChannelWrapper&](#fpubnublistusersfromchannelwrapper) | A struct containing occupancy and user state information for the channel. |

#### Other examples

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

##### Return occupancy only

You can return only the `occupancy` information for a single channel by specifying the channel and setting `DisableUserID` to `false`:

###### C++

###### Actor.h

```cpp
#include "PubnubClient.h"

// blueprint._b89ktgr
UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Presence")
void ListUsersFromChannelWithSettingsSample();

UFUNCTION()
void OnListUsersFromChannelResponse_WithSettings(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data);
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::ListUsersFromChannelWithSettingsSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
	FOnPubnubListUsersFromChannelResponse OnListUsersFromChannelResponse;
	OnListUsersFromChannelResponse.BindDynamic(this, &ASample_Presence::OnListUsersFromChannelResponse_WithSettings);

	// Create additional settings
	FPubnubListUsersFromChannelSettings Settings;
	Settings.State = true;
	Settings.DisableUserID = false;

	//List users from a channel
	FString Channel = TEXT("guild-channel");
	PubnubClient->ListUsersFromChannelAsync(Channel, OnListUsersFromChannelResponse, Settings);
}

// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::OnListUsersFromChannelResponse_WithSettings(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to list users from channel. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Users successfully listed from channel. Total occupancy: %d"), Data.Occupancy);
		//List all users with theirs states
		for (auto const& [UserID, UserState] : Data.UsersState)
		{
			UE_LOG(LogTemp, Log, TEXT("UserID: %s, User State: %s"), *UserID, *UserState);
		}
	}
}
```

###### Blueprint

##### Use lambda

You can use a lambda function to handle the response:

###### Actor.h

```cpp
#include "PubnubClient.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Presence")
void ListUsersFromChannelWithLambdaSample();
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::ListUsersFromChannelWithLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind lambda to response delegate
	FOnPubnubListUsersFromChannelResponseNative OnListUsersFromChannelResponse;
	OnListUsersFromChannelResponse.BindLambda([](const FPubnubOperationResult& Result, const FPubnubListUsersFromChannelWrapper& Data)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to list users from channel. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Users successfully listed from channel. Occupancy: %d"), Data.Occupancy);
		}
	});
	
	//List users from a channel
	FString Channel = TEXT("guild-channel");
	PubnubClient->ListUsersFromChannelAsync(Channel, OnListUsersFromChannelResponse);
}
```

## List user subscribed channels

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

This method returns the list of channels a user ID is subscribed to.

:::note Timeout events
If the app restarts (or the page refreshes) within the heartbeat window, no timeout event is generated.
:::

### Method(s)

```cpp
PubnubClient->ListUserSubscribedChannelsAsync(
    FString UserID,
    FOnPubnubListUsersSubscribedChannelsResponse ListUserSubscribedChannelsResponse
);
```

| Parameter | Description |
| --- | --- |
| `UserID` *Type: `FString` | The User ID to get the subscribed channels of. |
| `ListUserSubscribedChannelsResponse` *Type: [FOnPubnubListUsersSubscribedChannelsResponse](#fonpubnublistuserssubscribedchannelsresponse) | The delegate for the operation's result. You can also use a native callback of the type [FOnPubnubListUsersSubscribedChannelsResponseNative](#fonpubnublistuserssubscribedchannelsresponsenative) to handle the result using a lambda. |

### Sample code

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

You simply need to define the user ID and the `callback` function to be used to send the data to as in the example below.

###### C++

#### Actor.h

```cpp
#include "PubnubClient.h"

// blueprint.lvjys815
UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Presence")
void ListUserSubscribedChannelsSample();

UFUNCTION()
void OnListUserSubscribedChannelsResponse(FPubnubOperationResult Result, const TArray<FString>& Channels);
	
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::ListUserSubscribedChannelsSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	FString UserID = TEXT("Player_001");
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
	FOnPubnubListUsersSubscribedChannelsResponse OnListUsersSubscribedChannelsResponse;
	OnListUsersSubscribedChannelsResponse.BindDynamic(this, &ASample_Presence::OnListUserSubscribedChannelsResponse);

	//List channels the user is subscribed to
	PubnubClient->ListUserSubscribedChannelsAsync(UserID, OnListUsersSubscribedChannelsResponse);
}

// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::OnListUserSubscribedChannelsResponse(FPubnubOperationResult Result, const TArray<FString>& Channels)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to list user subscribed channels. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Successfully listed user subscribed channels:"));
		//List all channels
		for (const FString& Channel : Channels)
		{
			UE_LOG(LogTemp, Log, TEXT("- %s"), *Channel);
		}
	}
}
```

###### Blueprint

### Returns

This method is void. The delegate returns the following struct:

#### FOnPubnubListUsersSubscribedChannelsResponse

| Field | Type | Description |
| --- | --- | --- |
| `Result` | [FPubnubOperationResult](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `Channels` | `const TArray<FString>&` | An array of channel names the user is subscribed to. |

#### FOnPubnubListUsersSubscribedChannelsResponseNative

| Field | Type | Description |
| --- | --- | --- |
| `Result` | [const FPubnubOperationResult&](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `Channels` | `const TArray<FString>&` | An array of channel names the user is subscribed to. |

### Other examples

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

#### Use lambda

You can use a lambda function to handle the response:

#### Actor.h

```cpp
#include "PubnubClient.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Presence")
void ListUserSubscribedChannelsWithLambdaSample();
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::ListUserSubscribedChannelsWithLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	FString UserID = TEXT("Player_001");
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind lambda to response delegate
	FOnPubnubListUsersSubscribedChannelsResponseNative OnListUsersSubscribedChannelsResponse;
	OnListUsersSubscribedChannelsResponse.BindLambda([](const FPubnubOperationResult& Result, const TArray<FString>& Channels)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to list user subscribed channels. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Successfully listed user subscribed channels:"));
			//List all channels
			for (const FString& Channel : Channels)
			{
				UE_LOG(LogTemp, Log, TEXT("- %s"), *Channel);
			}
		}
	});
	
	//List channels the user is subscribed to
	PubnubClient->ListUserSubscribedChannelsAsync(UserID, OnListUsersSubscribedChannelsResponse);
}
```

## User state

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

The Presence API is used to set/get key/value pairs specific to a subscriber User ID.

### Method(s)

#### Set state

```cpp
PubnubClient->SetStateAsync(
    FString Channel,
    FString StateJson,
    FOnPubnubSetStateResponse OnSetStateResponse,
    FPubnubSetStateSettings SetStateSettings = FPubnubSetStateSettings()
);
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `FString` | The channel to set the presence state on. |
| `StateJson` *Type: `FString` | JSON object with the state to set. |
| `OnSetStateResponse`Type: [FOnPubnubSetStateResponse](#fonpubnubsetstateresponse) | The delegate for the operation's result. You can also use a native callback of the type [FOnPubnubSetStateResponseNative](#fonpubnubsetstateresponsenative) to handle the result using a lambda. |
| `SetStateSettings`Type: [FPubnubSetStateSettings](#fpubnubsetstatesettings) | Struct defining the method's configuration. |

#### FPubnubSetStateSettings

| Parameter | Description |
| --- | --- |
| `ChannelGroups`Type: `FString` | Comma-delimited list of channel group names. Not used if empty. |
| `UserID`Type: `FString` | The User ID of the user for which to set state for. If `NULL`, the current PubNub context User ID is used. |
| `HeartBeat`Type: bool | Whether to set the state and make a heartbeat call at the same time via the `/heartbeat` endpoint. |

#### Get state

```cpp
PubnubClient->GetStateAsync(
    FString Channel,
    FString ChannelGroup,
    FString UserID,
    FOnPubnubGetStateResponse OnGetStateResponse
);
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `FString` | The channel to get the presence state of. |
| `ChannelGroup` *Type: `FString` | The channel group to get the presence state of. |
| `UserID` *Type: `FString` | The User ID to get the presence state of. |
| `OnGetStateResponse` *Type: [FOnPubnubGetStateResponse](#fonpubnubgetstateresponse) | The delegate for the operation's result. You can also use a native callback of the type [FOnPubnubGetStateResponseNative](#fonpubnubgetstateresponsenative) to handle the result using a lambda. |

### Sample code

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

###### C++

#### Actor.h

```cpp
#include "PubnubClient.h"

// blueprint.n0gg8yqg
UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Presence")
void SetStateSample();
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::SetStateSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	//Set state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString StateJson = R"({"health": 100, "status": "active"})";
	PubnubClient->SetStateAsync(Channel, StateJson);
}
```

###### Blueprint

#### Get State

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

###### C++

#### Actor.h

```cpp
#include "PubnubClient.h"

// blueprint.msg62_si
UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Presence")
void GetStateSample();

UFUNCTION()
void OnGetStateResponse_Simple(FPubnubOperationResult Result, FString StateResponse);
	
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::GetStateSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	FString UserID = TEXT("Player_001");
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
	FOnPubnubGetStateResponse OnGetStateResponse;
	OnGetStateResponse.BindDynamic(this, &ASample_Presence::OnGetStateResponse_Simple);

	//Get state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString ChannelGroup = TEXT("");
	PubnubClient->GetStateAsync(Channel, ChannelGroup, UserID, OnGetStateResponse);
}

// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::OnGetStateResponse_Simple(FPubnubOperationResult Result, FString StateResponse)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to get state. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Successfully got state: %s"), *StateResponse);
	}
}
```

###### Blueprint

### Returns

The `SetStateAsync` method is void. The delegate returns the following struct:

#### FOnPubnubSetStateResponse

| Field | Type | Description |
| --- | --- | --- |
| `Result` | [FPubnubOperationResult](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |

#### FOnPubnubSetStateResponseNative

| Field | Type | Description |
| --- | --- | --- |
| `Result` | [const FPubnubOperationResult&](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |

The `GetStateAsync` method is void. The delegate returns the following struct:

#### FOnPubnubGetStateResponse

| Field | Type | Description |
| --- | --- | --- |
| `Result` | [FPubnubOperationResult](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `StateResponse` | `FString` | The state of the user as a JSON string. |

#### FOnPubnubGetStateResponseNative

| Field | Type | Description |
| --- | --- | --- |
| `Result` | [const FPubnubOperationResult&](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `StateResponse` | `FString` | The state of the user as a JSON string. |

### Other examples

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

#### Set state with result struct

You can use the result struct to handle the response:

##### C++

#### Actor.h

```cpp
#include "PubnubClient.h"

// blueprint.8l84j8-9
UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Presence")
void SetStateWithResultSample();

UFUNCTION()
void OnSetStateResponse(FPubnubOperationResult Result);
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::SetStateWithResultSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
	FOnPubnubSetStateResponse OnSetStateResponse;
	OnSetStateResponse.BindDynamic(this, &ASample_Presence::OnSetStateResponse);

	//Set state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString StateJson = R"({"health": 100, "status": "active"})";
	PubnubClient->SetStateAsync(Channel, StateJson, OnSetStateResponse);
}

// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::OnSetStateResponse(FPubnubOperationResult Result)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to set state. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Successfully set state."));
	}
}
```

##### Blueprint

#### Set state for a channel group

You can set the state for a channel group by specifying the channel group name:

##### C++

#### Actor.h

```cpp
#include "PubnubClient.h"

// blueprint.js86cm8b
UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Presence")
void SetStateWithSettingsSample();
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::SetStateWithSettingsSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	//Set state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString StateJson = R"({"health": 100, "status": "active"})";

	// Create additional settings
	FPubnubSetStateSettings Settings;
	Settings.ChannelGroup = TEXT("all-presence-channels");
	Settings.UserID = TEXT("Player_005");
	
	PubnubClient->SetStateAsync(Channel, StateJson, Settings);
}
```

##### Blueprint

#### Set state with lambda

You can use a lambda function to handle the response:

#### Actor.h

```cpp
#include "PubnubClient.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Presence")
void SetStateWithResultLambdaSample();
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::SetStateWithResultLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind lambda to response delegate
	FOnPubnubSetStateResponseNative OnSetStateResponse;
	OnSetStateResponse.BindLambda([](const FPubnubOperationResult& Result)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to set state. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Successfully set state."));
		}
	});
	
	//Set state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString StateJson = R"({"health": 100, "status": "active"})";
	PubnubClient->SetStateAsync(Channel, StateJson, OnSetStateResponse);
}
```

#### Get state from channel group

You can get the state from a channel group by specifying the channel group name:

#### Actor.h

```cpp
#include "PubnubClient.h"

```

#### Actor.cpp

```cpp
// Copyright 2026 PubNub Inc. All Rights Reserved.

#include "Samples/Sample_Presence.h"
#include "Kismet/GameplayStatics.h"
#include "Engine/GameInstance.h"
#include "PubnubSubsystem.h"

/**
 * NOTE: Each sample is designed to be fully self-contained and portable. 
 * You can copy-paste any individual sample into a new project, and it should compile and run without errors 
 * — as long as you also include the necessary `#include` statements.
 *
 * The samples assume that in Pubnub SDK settings sections in ProjectSettings following fields are set:
 * PublishKey and SubscribeKey have correct keys, InitializeAutomatically is true.
 */

// NOTE: Comments marked with `ACTION REQUIRED` indicate lines you must change/adjust.

//Internal function, don't copy it with the samples
void ASample_Presence::RunSamples()
{
	Super::RunSamples();
	ListUsersFromChannelSample();
	ListUsersFromChannelWithSettingsSample();
	ListUsersFromChannelWithLambdaSample();
	ListUserSubscribedChannelsSample();
	ListUserSubscribedChannelsWithLambdaSample();
	SetStateSample();
	SetStateWithSettingsSample();
	SetStateWithResultSample();
	SetStateWithResultLambdaSample();
	GetStateSample();
	GetStateWithLambdaSample();
}
//Internal function, don't copy it with the samples
ASample_Presence::ASample_Presence()
{
	SamplesName = "Presence";
}

/* SAMPLE FUNCTIONS */

// snippet.list_users_from_channel
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::ListUsersFromChannelSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
	FOnPubnubListUsersFromChannelResponse OnListUsersFromChannelResponse;
	OnListUsersFromChannelResponse.BindDynamic(this, &ASample_Presence::OnListUsersFromChannelResponse_Simple);

	//List users from a channel
	FString Channel = TEXT("guild-channel");
	PubnubClient->ListUsersFromChannelAsync(Channel, OnListUsersFromChannelResponse);
}

// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::OnListUsersFromChannelResponse_Simple(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to list users from channel. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Users successfully listed from channel. Occupancy: %d"), Data.Occupancy);
	}
}

// snippet.list_users_from_channel_with_settings
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::ListUsersFromChannelWithSettingsSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
	FOnPubnubListUsersFromChannelResponse OnListUsersFromChannelResponse;
	OnListUsersFromChannelResponse.BindDynamic(this, &ASample_Presence::OnListUsersFromChannelResponse_WithSettings);

	// Create additional settings
	FPubnubListUsersFromChannelSettings Settings;
	Settings.State = true;
	Settings.DisableUserID = false;

	//List users from a channel
	FString Channel = TEXT("guild-channel");
	PubnubClient->ListUsersFromChannelAsync(Channel, OnListUsersFromChannelResponse, Settings);
}

// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::OnListUsersFromChannelResponse_WithSettings(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to list users from channel. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Users successfully listed from channel. Total occupancy: %d"), Data.Occupancy);
		//List all users with theirs states
		for (auto const& [UserID, UserState] : Data.UsersState)
		{
			UE_LOG(LogTemp, Log, TEXT("UserID: %s, User State: %s"), *UserID, *UserState);
		}
	}
}

// snippet.list_users_from_channel_with_lambda
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::ListUsersFromChannelWithLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind lambda to response delegate
	FOnPubnubListUsersFromChannelResponseNative OnListUsersFromChannelResponse;
	OnListUsersFromChannelResponse.BindLambda([](const FPubnubOperationResult& Result, const FPubnubListUsersFromChannelWrapper& Data)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to list users from channel. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Users successfully listed from channel. Occupancy: %d"), Data.Occupancy);
		}
	});
	
	//List users from a channel
	FString Channel = TEXT("guild-channel");
	PubnubClient->ListUsersFromChannelAsync(Channel, OnListUsersFromChannelResponse);
}

// snippet.list_user_subscribed_channels
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::ListUserSubscribedChannelsSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	FString UserID = TEXT("Player_001");
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
	FOnPubnubListUsersSubscribedChannelsResponse OnListUsersSubscribedChannelsResponse;
	OnListUsersSubscribedChannelsResponse.BindDynamic(this, &ASample_Presence::OnListUserSubscribedChannelsResponse);

	//List channels the user is subscribed to
	PubnubClient->ListUserSubscribedChannelsAsync(UserID, OnListUsersSubscribedChannelsResponse);
}

// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::OnListUserSubscribedChannelsResponse(FPubnubOperationResult Result, const TArray<FString>& Channels)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to list user subscribed channels. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Successfully listed user subscribed channels:"));
		//List all channels
		for (const FString& Channel : Channels)
		{
			UE_LOG(LogTemp, Log, TEXT("- %s"), *Channel);
		}
	}
}

// snippet.list_user_subscribed_channels_with_lambda
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::ListUserSubscribedChannelsWithLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	FString UserID = TEXT("Player_001");
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind lambda to response delegate
	FOnPubnubListUsersSubscribedChannelsResponseNative OnListUsersSubscribedChannelsResponse;
	OnListUsersSubscribedChannelsResponse.BindLambda([](const FPubnubOperationResult& Result, const TArray<FString>& Channels)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to list user subscribed channels. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Successfully listed user subscribed channels:"));
			//List all channels
			for (const FString& Channel : Channels)
			{
				UE_LOG(LogTemp, Log, TEXT("- %s"), *Channel);
			}
		}
	});
	
	//List channels the user is subscribed to
	PubnubClient->ListUserSubscribedChannelsAsync(UserID, OnListUsersSubscribedChannelsResponse);
}

// snippet.set_state
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::SetStateSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	//Set state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString StateJson = R"({"health": 100, "status": "active"})";
	PubnubClient->SetStateAsync(Channel, StateJson);
}

// snippet.set_state_with_settings
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::SetStateWithSettingsSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	//Set state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString StateJson = R"({"health": 100, "status": "active"})";

	// Create additional settings
	FPubnubSetStateSettings Settings;
	Settings.ChannelGroup = TEXT("all-presence-channels");
	Settings.UserID = TEXT("Player_005");
	
	PubnubClient->SetStateAsync(Channel, StateJson, Settings);
}

// snippet.set_state_with_result
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::SetStateWithResultSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
	FOnPubnubSetStateResponse OnSetStateResponse;
	OnSetStateResponse.BindDynamic(this, &ASample_Presence::OnSetStateResponse);

	//Set state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString StateJson = R"({"health": 100, "status": "active"})";
	PubnubClient->SetStateAsync(Channel, StateJson, OnSetStateResponse);
}

// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::OnSetStateResponse(FPubnubOperationResult Result)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to set state. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Successfully set state."));
	}
}

// snippet.set_state_with_result_lambda
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::SetStateWithResultLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind lambda to response delegate
	FOnPubnubSetStateResponseNative OnSetStateResponse;
	OnSetStateResponse.BindLambda([](const FPubnubOperationResult& Result)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to set state. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Successfully set state."));
		}
	});
	
	//Set state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString StateJson = R"({"health": 100, "status": "active"})";
	PubnubClient->SetStateAsync(Channel, StateJson, OnSetStateResponse);
}

// snippet.get_state
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::GetStateSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	FString UserID = TEXT("Player_001");
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
	FOnPubnubGetStateResponse OnGetStateResponse;
	OnGetStateResponse.BindDynamic(this, &ASample_Presence::OnGetStateResponse_Simple);

	//Get state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString ChannelGroup = TEXT("");
	PubnubClient->GetStateAsync(Channel, ChannelGroup, UserID, OnGetStateResponse);
}

// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::OnGetStateResponse_Simple(FPubnubOperationResult Result, FString StateResponse)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to get state. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Successfully got state: %s"), *StateResponse);
	}
}

// snippet.get_state_with_lambda
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::GetStateWithLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	FString UserID = TEXT("Player_001");
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind lambda to response delegate
	FOnPubnubGetStateResponseNative OnGetStateResponse;
	OnGetStateResponse.BindLambda([](const FPubnubOperationResult& Result, FString StateResponse)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to get state. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Successfully got state: %s"), *StateResponse);
		}
	});
	
	//Get state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString ChannelGroup = TEXT("");
	PubnubClient->GetStateAsync(Channel, ChannelGroup, UserID, OnGetStateResponse);
}

// snippet.end

UPubnubClient* ASample_Presence::GetPubnubClient()
{
	UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(this);
	UPubnubSubsystem* PubnubSubsystem = GameInstance->GetSubsystem<UPubnubSubsystem>();
	
	//Get default PubnubClient - created automatically if PluginSettings are set to do so
	UPubnubClient* PubnubClient = PubnubSubsystem->GetPubnubClient(0);
	
	PubnubClient->SetUserID(TEXT("player_001"));
	return PubnubClient;
}
```

#### Get state from channel group with lambda

You can use a lambda function to handle the response:

#### Actor.h

```cpp
#include "PubnubClient.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Presence")
void GetStateWithLambdaSample();
	
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_Presence with name of your Actor class
void ASample_Presence::GetStateWithLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	FString UserID = TEXT("Player_001");
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind lambda to response delegate
	FOnPubnubGetStateResponseNative OnGetStateResponse;
	OnGetStateResponse.BindLambda([](const FPubnubOperationResult& Result, FString StateResponse)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to get state. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Successfully got state: %s"), *StateResponse);
		}
	});
	
	//Get state for the user on a channel
	FString Channel = TEXT("presence-channel");
	FString ChannelGroup = TEXT("");
	PubnubClient->GetStateAsync(Channel, ChannelGroup, UserID, OnGetStateResponse);
}
```

## Complete example

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

###### C++

#### ASample_PresenceFull.h

```cpp
// Copyright 2026 PubNub Inc. All Rights Reserved.

// snippet.full_presence_example
// blueprint.z1nf7p3w
#pragma once

#include "PubnubClient.h"

#include "GameFramework/Actor.h"
#include "CoreMinimal.h"
#include "Sample_PresenceFull.generated.h"

// ACTION REQUIRED: Replace PUBNUBLIBRARYTESTS_API with your project's module API macro (usually ProjectName_API)
UCLASS()
class PUBNUBLIBRARYTESTS_API ASample_PresenceFull : public AActor
{
	GENERATED_BODY()

protected:
	virtual void BeginPlay() override;

public:

	UFUNCTION(BlueprintCallable, Category = "Pubnub|FullExamples|Presence")
	void RunPresenceFullExample();

	UFUNCTION()
	void OnSetStateResponse(FPubnubOperationResult Result);

	UFUNCTION()
	void OnListUsersFromChannelResponse(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data);

	UFUNCTION()
	void OnGetStateResponse(FPubnubOperationResult Result, FString StateResponse);
	
private:
	UPROPERTY()
	UPubnubClient* PubnubClient = nullptr;
};

// snippet.end
```

#### ASample_PresenceFull.cpp

```cpp
// Copyright 2026 PubNub Inc. All Rights Reserved.

// snippet.full_presence_example

#include "Samples/Sample_PresenceFull.h"
#include "Kismet/GameplayStatics.h"
#include "Engine/GameInstance.h"
#include "PubnubSubsystem.h"
#include "PubnubClient.h"

void ASample_PresenceFull::BeginPlay()
{
	Super::BeginPlay();

	//Run the example on BeginPlay
	RunPresenceFullExample();
}

void ASample_PresenceFull::RunPresenceFullExample()
{
	//Get PubnubSubsystem from GameInstance
	UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(this);
	UPubnubSubsystem* PubnubSubsystem = GameInstance->GetSubsystem<UPubnubSubsystem>();
	
	//Create Pubnub Client using Pubnub Subsystem
	FPubnubConfig Config;
	Config.PublishKey = TEXT("demo");   //replace with your Publish Key from Admin Portal
	Config.SubscribeKey = TEXT("demo"); //replace with your Subscribe Key from Admin Portal
	Config.UserID = TEXT("Player_001");
	PubnubClient = PubnubSubsystem->CreatePubnubClient(Config);

	UE_LOG(LogTemp, Log, TEXT("Presence example: Pubnub Client is created"));
	
	//Subscribe to a channel with presence events enabled.
	FPubnubSubscribeSettings SubscribeSettings;
	SubscribeSettings.ReceivePresenceEvents = true;
	FString Channel = TEXT("presence-channel-full");
	PubnubClient->SubscribeToChannelAsync(Channel, SubscribeSettings);

	// NOTE: Subscribing to a group or channel may take a few seconds to complete.
	// This sleep is used to simulate the waiting period in an actual application.
	FPlatformProcess::Sleep(3);
	UE_LOG(LogTemp, Log, TEXT("Presence example: subscribed to channel: %s"), *Channel);

	//Set the user's state on the channel.
	FOnPubnubSetStateResponse OnSetStateResponse;
	OnSetStateResponse.BindDynamic(this, &ASample_PresenceFull::OnSetStateResponse);
	FString StateJson = R"({"health": 100, "status": "ready"})";
	PubnubClient->SetStateAsync(Channel, StateJson, OnSetStateResponse);

	//List the users on the channel.
	FOnPubnubListUsersFromChannelResponse OnListUsersFromChannelResponse;
	OnListUsersFromChannelResponse.BindDynamic(this, &ASample_PresenceFull::OnListUsersFromChannelResponse);
	PubnubClient->ListUsersFromChannelAsync(Channel, OnListUsersFromChannelResponse);

	//Get the state for our user.
	FString UserID = TEXT("Player_001");
	FOnPubnubGetStateResponse OnGetStateResponse;
	OnGetStateResponse.BindDynamic(this, &ASample_PresenceFull::OnGetStateResponse);
	PubnubClient->GetStateAsync(Channel, "", UserID, OnGetStateResponse);
}

void ASample_PresenceFull::OnSetStateResponse(FPubnubOperationResult Result)
{
	if (!Result.Error)
	{
		UE_LOG(LogTemp, Log, TEXT("Presence example: state successfully set."));
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("Presence example: failed to set state. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
}

void ASample_PresenceFull::OnListUsersFromChannelResponse(FPubnubOperationResult Result, FPubnubListUsersFromChannelWrapper Data)
{
	if (!Result.Error)
	{
		UE_LOG(LogTemp, Log, TEXT("Presence example: successfully listed users. Occupancy: %d"), Data.Occupancy);
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("Presence example: failed to list users. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
}

void ASample_PresenceFull::OnGetStateResponse(FPubnubOperationResult Result, FString StateResponse)
{
	if (!Result.Error)
	{
		UE_LOG(LogTemp, Log, TEXT("Presence example: successfully got state: %s"), *StateResponse);
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("Presence example: failed to get state. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
}

// snippet.end
```

###### Blueprint

## Deprecated methods

### List users from channel (deprecated)

:::warning Deprecated
This method is deprecated and will be removed in a future version. Use `PubnubClient->ListUsersFromChannel()` or `PubnubClient->ListUsersFromChannelAsync()` instead.
:::

```cpp
PubnubSubsystem->ListUsersFromChannel(
    FString Channel,
    FOnListUsersFromChannelResponse ListUsersFromChannelResponse,
    FPubnubListUsersFromChannelSettings ListUsersFromChannelSettings = FPubnubListUsersFromChannelSettings()
);
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `FString` | The channel to get the presence details of. |
| `ListUsersFromChannelResponse` *Type: `FOnListUsersFromChannelResponse` | The delegate for the operation's result. |
| `ListUsersFromChannelSettings`Type: `FPubnubListUsersFromChannelSettings` | A struct defining the method's configuration. |

### List user subscribed channels (deprecated)

:::warning Deprecated
This method is deprecated and will be removed in a future version. Use `PubnubClient->ListUserSubscribedChannels()` or `PubnubClient->ListUserSubscribedChannelsAsync()` instead.
:::

```cpp
PubnubSubsystem->ListUserSubscribedChannels(
    FString UserID,
    FOnListUsersSubscribedChannelsResponse ListUserSubscribedChannelsResponse
);
```

| Parameter | Description |
| --- | --- |
| `UserID` *Type: `FString` | The User ID to get the subscribed channels of. |
| `ListUserSubscribedChannelsResponse` *Type: `FOnListUsersSubscribedChannelsResponse` | The delegate for the operation's result. |

### Set state (deprecated)

:::warning Deprecated
This method is deprecated and will be removed in a future version. Use `PubnubClient->SetState()` or `PubnubClient->SetStateAsync()` instead.
:::

```cpp
PubnubSubsystem->SetState(
    FString Channel,
    FString StateJson,
    FOnSetStateResponse OnSetStateResponse,
    FPubnubSetStateSettings SetStateSettings = FPubnubSetStateSettings()
);
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `FString` | The channel to set the presence state on. |
| `StateJson` *Type: `FString` | JSON object with the state to set. |
| `OnSetStateResponse`Type: `FOnSetStateResponse` | The delegate for the operation's result. |
| `SetStateSettings`Type: `FPubnubSetStateSettings` | Struct defining the method's configuration. |

### Get state (deprecated)

:::warning Deprecated
This method is deprecated and will be removed in a future version. Use `PubnubClient->GetState()` or `PubnubClient->GetStateAsync()` instead.
:::

```cpp
PubnubSubsystem->GetState(
    FString Channel,
    FString ChannelGroup,
    FString UserID,
    FOnGetStateResponse OnGetStateResponse
);
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `FString` | The channel to get the presence state of. |
| `ChannelGroup` *Type: `FString` | The channel group to get the presence state of. |
| `UserID` *Type: `FString` | The User ID to get the presence state of. |
| `OnGetStateResponse` *Type: `FOnGetStateResponse` | The delegate for the operation's result. |

## Terms in this document

* **Access Manager** - A cryptographic, token-based permission administrator that allows you to regulate clients' access to PubNub resources, such as channels, channel groups, and user IDs.
* **Action** - The type of activity (procedure) to execute when a condition is satisfied (for example, sending a message).
* **Billing alert notification** - A means of informing a user that a billing alert has been triggered. Before notifications can happen, a billing alert must be triggered first.
* **Business Object** - A container for data fields and metrics that defines aggregations and data sources.
* **Channel** - A pathway for sending and receiving messages between devices, created automatically when you first use it, that can handle any number of users and messages for different communication needs, like 1-1 text chats, group conversations, and other data streaming.
* **Channel pattern** - A way to group and analyze channel data to track performance metrics like message counts and user engagement over time with PubNub Insights.
* **Condition** - A requirement that must be satisfied or evaluated to true for an action to be executed. Input in a decision table.
* **Cryptor** - An implementation of a specific cryptographic algorithm used for data encryption/decryption that adheres to a standard interface.
* **Dashboard** - A collection of widgets (charts) that give an overview of the metrics one is evaluating.
* **Data fields** - Data you want Illuminate to track. These can be quantitative (measures), like "Number" or "Timestamp" or qualitative (dimensions) values, like "String" that can be used to categorize and segment data. Data fields can be aggregated and calculated.
* **Decision** - A collection (or decision table) of conditions and actions. When conditions are satisfied, the corresponding actions are triggered as per defined rules.
* **End Customer** - A customer of a PubNub partner. End customers do not have direct access to the Admin Portal. Instead, they interact with PubNub products—such as Illuminate—through the partner’s portal, where PubNub services are embedded. They can create PubNub objects only within this partner-provided environment.
* **Entity** - A subscribable object within a PubNub SDK that allows you to perform context-specific operations.
* **Listener** - A function or objectthat reacts to events or messages, like new chat messages or connection updates, letting your app respond in real-time.
* **Mapped/Unmapped** - Whether the data source for a data field has been defined or the action has been configured.
* **MCP Server** - A Model Context Protocol server that coordinates communication and synchronization between AI agents, clients, or services, such as Cursor IDE and Windsurf.
* **Message** - A unit of data transmitted between clients or between a client and a server in PubNub, containing information such as text, binary data, or structured data formats like JSON. Messages are sent over channels and can be tracked for delivery and read status.
* **Metric** - What exactly is evaluated using measures and dimensions (collectively called data fields), as well as aggregation functions.
* **Module** - A Functions v1 container that groups related functions for configuration and deployment on an app’s keysets.
* **Origin** - The subdomain used to establish a connection to the PubNub network that allows your application's traffic to appear like it's coming from your own domain.
* **Package** - A Functions v2 container that groups Functions, tracks Revisions, and is deployed to keysets.
* **Partner** - A PubNub customer who resells PubNub products, such as Illuminate, to their own customers. Partners have access to the Admin Portal, enabling them to create and manage PubNub objects for themselves or on behalf of their end customers.
* **Publish Key** - A unique identifier that allows your application to send messages to PubNub channels. It's part of your app's credentials and should be kept secure.
* **PubNub** - PubNub is a real-time messaging platform that provides APIs and SDKs for building scalable applications. It handles the complex infrastructure of real-time communication, including: Message delivery and persistence, Presence detection, Access control, Push notifications, File sharing, Serverless processing with Functions and Events & Actions, Analytics and monitoring with BizOps Workspace, AI-powered insights with Illuminate.
* **Push token** - A device identifier issued by a push provider (APNs or FCM) used to register a device for receiving mobile push notifications.
* **Rule** - A definition (row in a decision table) stating which action should be triggered for which condition.
* **Service Integration** - A machine identity that represents a program or service consuming the Admin API, scoped to your account and authenticated using expirable API keys with configurable permissions.
* **Signal** - A non-persistent message limited to 64 bytes designed for high-volume usecases where the the most recent data is relevant, like GPS location updates.
* **Subscribe Key** - A unique identifier that allows your application to receive messages from PubNub channels. It's part of your app's credentials and should be kept secure.
* **Timetoken** - A unique identifier for each message that represents the number of 100-nanosecond intervals since January 1, 1970, for example, 16200000000000000.
* **Trigger details** - A set of predefined criteria for a given billing alert. When met, billing alert notifications are generated.
* **User** - An individual or entity that interacts with a system, application, or service. In PubNub, a user typically refers to someone who sends or receives messages through the platform, identified by a unique user ID or username.
* **User ID** - UTF-8 encoded, unique string of up to 92 characters used to identify a single client (end user, device, or server) that connects to PubNub.
* **Vibe Coding** - A way to build applications in an intuitive, relaxed, and improvisational manner, using AI tools and natural language descriptions.