Unreal Chat SDK 1.0.0 migration guide

The 1.0.0 release of the Unreal Chat SDK rebuilds the SDK on top of the PubNub Unreal Engine Core SDK (PubnubLibrary) and removes the dependency on the bundled C++ Chat SDK (cpp-chat.dll). The API surface is rearchitected: all network-calling methods now return structured result types, every method gains an asynchronous variant, and real-time listeners use entity-owned delegate properties instead of callback parameters.

This guide is for developers who use Unreal Chat SDK 0.x.x in existing applications.

If your application uses 0.x.x, it will not compile against 1.0.0 without changes. This guide summarizes the differences between the versions and shows how to migrate to Unreal Chat SDK 1.0.0.

Most notable changes include:

  • New dependency: Unreal Chat SDK 0.x.x was a self-contained plugin. Version 1.0.0 requires the PubNub Unreal Engine Core SDK (PubnubLibrary) as a separate plugin installed alongside the Chat SDK.
  • Type renames: Most classes and structs gained a Chat infix (UPubnubUser → UPubnubChatUser, FPubnubMessageAction → FPubnubChatMessageAction, and others).
  • Result structs: Every method now returns a typed result struct wrapping FPubnubChatOperationResult (with Error and ErrorMessage fields) alongside the domain data. No more raw pointer returns or silent nullptr on failure.
  • Sync/Async split: Every network method is available in both a synchronous blocking variant and an Async variant that takes a delegate callback.
  • Entity-first delegates: Real-time listeners use multicast delegate properties on entity objects. Bind delegates before calling the streaming method; stop with an explicit StopStreaming*() call.
  • Multiple chat instances: The subsystem now supports multiple simultaneous chat sessions keyed by UserID.
  • Synced objects: Entity objects (channels, users, memberships, messages) are now synchronized by ID. All variables that reference the same entity ID share the latest locally known data — updating one updates all.

Differences between 0.x.x and 1.0.0​

See the major differences between the versions:

Feature/Method0.x.x1.0.0
Core dependencySelf-contained plugin (no additional dependency)Requires PubNub Unreal Engine Core SDK plugin (PubnubLibrary)
Method return typesRaw pointer or voidTyped result struct (e.g. FPubnubChatUserResult) containing FPubnubChatOperationResult
Async methodsNot available*Async suffix variants added for every network method
Real-time streamingStream*(Callback) returns UPubnubCallbackStop*Stream*() (no callback); bind OnUpdated/OnXxx delegate; stop with StopStreaming*()
Join behaviorJoin() also calls Connect() internallyJoin() and Connect() are separate — call both to receive messages after joining
Read receiptsStreamReadReceipts() returns a list of UserIDs (limited to 100 members)Split into FetchReadReceipts() (paginated snapshot with timetokens) and StreamReadReceipts() (per-user real-time updates)
Soft/hard deleteDeleteMessage() and DeleteMessageHard()Delete(bool Soft = false)
Forward parameterMessage->Forward(FString ChannelID)Message->Forward(UPubnubChatChannel* Channel)
GetUsers / GetChannels parameter order(Filter, Sort, Limit, Page)(Limit, Filter, Sort, Page) — Sort type changed to FPubnubGetAllSort
SetRestrictions on ChatChat->SetRestrictions(FString UserID, FString ChannelID, FPubnubRestriction)Chat->SetRestrictions(FPubnubChatRestriction) — UserID and ChannelID now inside the struct
Subsystem InitChat returnUPubnubChat*FPubnubChatInitChatResult containing .Chat and error info
Subsystem GetChat / DestroyChatNo argumentsRequire FString UserID argument
Multiple chat instancesNot supportedSupported — keyed by UserID
MessageDraft change listenerAddChangeListener() / AddChangeListenerWithSuggestions()Bind OnMessageDraftUpdated / OnMessageDraftUpdatedWithSuggestions delegate properties
Object identityIndependent snapshots. Two variables with the same entity ID can hold different data simultaneouslySynchronized by ID. All references to the same entity ID share the latest locally known data.

Join and Connect​

Important change

This change affects any code that calls Join() and then listens for messages. Update it before releasing to users.

In 0.x.x, calling Join() on a channel also subscribed to receive messages on that channel automatically. In 1.0.0, Join() creates the membership server-side but does not subscribe. Call Connect() separately after Join() to start receiving messages.

1// Join implicitly started message delivery
2FPubnubChatOperationResult Result = Channel->Join();
3
4// Messages arrived via the channel delegate

Dependency​

Unreal Chat SDK 0.x.x was a self-contained plugin. Version 1.0.0 depends on the PubNub Unreal Engine Core SDK (PubnubLibrary). If you installed from FAB, the PubNub Gaming SDK already includes both plugins. No additional downloads are needed.

To install the Core SDK from GitHub:

  1. Download the PubNub Unreal Engine Core SDK and place it in your project's Plugins folder alongside the Chat SDK plugin.
  2. Delete the Intermediate and Binaries folders from your project.
  3. Rebuild the project.

No changes to your .Build.cs file are required.

Type renames​

Rename all entity class references. The Chat infix was added to distinguish Chat SDK types from the underlying UE Core SDK types.

Old typeNew type
UPubnubUserUPubnubChatUser
UPubnubChannelUPubnubChatChannel
UPubnubMessageUPubnubChatMessage
UPubnubMembershipUPubnubChatMembership
UPubnubThreadChannelUPubnubChatThreadChannel
UPubnubAccessManagerUPubnubChatAccessManager
FPubnubMessageActionFPubnubChatMessageAction
FPubnubRestrictionFPubnubChatRestriction
FPubnubEventFPubnubChatEvent
FPubnubSendTextParamsFPubnubChatSendTextParams
FPubnubCreatedChannelWrapperFPubnubChatCreateGroupConversationResult / FPubnubChatCreateDirectConversationResult
FPubnubChannelsResponseWrapperFPubnubChatGetChannelsResult
FPubnubUsersResponseWrapperFPubnubChatGetUsersResult
FPubnubEventsHistoryWrapperFPubnubChatEventsResult

Also rename the CustomDataJson field to Custom on FPubnubChatChannelData, FPubnubChatUserData, and FPubnubChatMembershipData:

1FPubnubChatChannelData Data;
2Data.CustomDataJson = TEXT("{\"color\":\"blue\"}");

Update enum value names. All enum values now use PascalCase after the prefix:

Old valueNew value
PCET_TYPINGPCET_Typing
PCET_CUSTOMPCET_Custom
PCS_ConnectedPCCS_ConnectionOnline
PMAT_ReactionPCMAT_Reaction
PMAT_EditedPCMAT_Edited
PMAT_DeletedPCMAT_Deleted

Result structs​

Every method that previously returned a raw pointer or void now returns a typed result struct. The struct always contains a Result field of type FPubnubChatOperationResult with Error (bool) and ErrorMessage (FString). Check Error before accessing the payload.

1UPubnubUser* User = Chat->CreateUser("user_alice", Data);
2if (!User)
3{
4 // error only visible in logs
5}

Methods that previously returned void now return FPubnubChatOperationResult:

1Channel->SendText(TEXT("Hello"));
2// no way to know if it succeeded

Sync and Async methods​

Every network method is now available in two variants. Use the synchronous form when you need the result immediately; use the Async form to avoid blocking the game thread.

1// Blocks until complete. Returns result struct directly.
2FPubnubChatUserResult Result = Chat->GetUser("user_alice");
3if (!Result.Result.Error)
4{
5 UPubnubChatUser* User = Result.User;
6}

Multiple chat instances​

The subsystem now supports multiple simultaneous chat sessions, one per UserID. Update all InitChat, GetChat, and DestroyChat calls.

1UPubnubChat* Chat = PubnubChatSubsystem->InitChat("pub-key", "sub-key", "Player_001");
2
3UPubnubChat* Chat = PubnubChatSubsystem->GetChat();
4
5PubnubChatSubsystem->DestroyChat();

Synced and mutable objects​

In 0.x.x, entity objects (channels, users, memberships, messages) were independent snapshots. Two variables that pointed to the same entity ID could hold different data at the same time. Calling Update() on one returned a new object with the updated data, leaving any other variable unchanged.

In 1.0.0, every entity object is synchronized by ID. All variables that hold a reference to the same entity ID share the latest locally known data. Calling Update() on any of them updates the underlying shared state, so every other reference reflects the change immediately.

1// Channel and Channel2 are independent snapshots
2UPubnubChannel* Channel = Chat->CreatePublicConversation(ChannelID, ChannelData1);
3UPubnubChannel* Channel2 = Chat->GetChannel(ChannelID);
4
5Channel2 = Channel2->Update(ChannelData2);
6// Channel still holds ChannelData1; Channel2 holds ChannelData2

This applies to all entity types: channels, users, memberships, and messages. This is the default in 1.0.0. However, review any code that intentionally holds multiple pointers to the same entity ID and relies on them being independent. That pattern no longer works.

Entity-first delegates​

Real-time listeners no longer accept a callback parameter. Bind to the entity's delegate property before calling the streaming method. Call the matching StopStreaming*() method to unsubscribe.

1FOnPubnubMessageStreamUpdateReceived Callback;
2Callback.BindDynamic(this, &AMyActor::OnMessageUpdated);
3UPubnubCallbackStop* Stop = Message->StreamUpdates(Callback);
4
5// Stop:
6Stop->Stop();

The same pattern applies to all streaming methods across all entities (Channel->StreamPresence(), Channel->StreamTyping(), User->StreamMentions(), Membership->StreamUpdates(), etc.).

Read receipts​

The read receipts API was reworked to scale beyond 100 channel members and to separate snapshot fetching from real-time streaming.

In 0.x.x, StreamReadReceipts() returned a list of UserIDs representing members who had read the message. This worked only for channels with 100 or fewer members.

In 1.0.0:

  • FetchReadReceipts() returns a paginated snapshot of the last-read timetoken for each member. Use this for initial load or on-demand checks.
  • StreamReadReceipts() delivers real-time updates per user via the channel's OnReadReceiptReceived delegate. Each update contains a single user's read position, not a full member list.
1// Returns TArray<FString> UserIDs — limited to 100 members
2UPubnubCallbackStop* Stop = Channel->StreamReadReceipts(OnReadReceiptsDelegate);

Delete message​

The separate soft-delete and hard-delete methods are unified into a single Delete(bool Soft) method.

1// Soft delete
2UPubnubMessage* SoftDeleted = Message->DeleteMessage();
3
4// Hard delete
5bool bSuccess = Message->DeleteMessageHard();

Message accessors​

Several Message accessors were renamed for consistency with the Get* / Is* / Has* naming convention.

OldNew
Message->Text()Message->GetCurrentText()
Message->GetTimetoken()Message->GetMessageTimetoken()
Message->Deleted() → boolMessage->IsDeleted() → FPubnubChatIsDeletedResult
Message->Type() → EPubnubChatMessageTypeMessage->GetType() → FString
Message->Reactions() → TArray<FPubnubMessageAction>Message->GetReactions() → FPubnubChatGetReactionsResult
Message->HasThread() → boolMessage->HasThread() → FPubnubChatHasThreadResult
1FString Text = Message->Text();
2FString Timetoken = Message->GetTimetoken();
3bool bDeleted = Message->Deleted();

Forward message​

Forward now takes a UPubnubChatChannel* object instead of a string channel ID.

1Message->Forward(TEXT("target-channel-id"));

GetUsers and GetChannels parameter order​

The parameter order for GetUsers() and GetChannels() changed. Limit is now the first parameter. The Sort parameter type also changed from FString to a typed struct.

1// GetUsers(Filter, Sort, Limit, Page)
2Chat->GetUsers(TEXT(""), TEXT("name:asc"), 25, FPubnubPage());
3
4// GetChannels(Filter, Sort, Limit, Page)
5Chat->GetChannels(TEXT(""), TEXT("id:asc"), 25, FPubnubPage());

SetRestrictions on Chat​

Chat->SetRestrictions() now accepts a single FPubnubChatRestriction struct that includes UserID and ChannelID directly, replacing the three separate parameters.

1FPubnubRestriction Restriction;
2Restriction.Ban = true;
3Restriction.Reason = TEXT("Spam");
4Chat->SetRestrictions(TEXT("user_123"), TEXT("support"), Restriction);

MessageDraft​

MessageDraft was rewritten as a native Unreal implementation. Key changes:

  • Change listeners replaced by delegate properties.
  • Message elements are now plain structs instead of UObjects.
  • New AppendText() method for easily appending plain text to the end of a draft.
  • Draft mutations are now validated internally — the SDK prevents operations that would corrupt existing mentions or links (for example, inserting text in the middle of a mention offset range).
1// Adding a change listener
2Draft->AddChangeListener(Callback);
3
4// Adding a mention target (UObject)
5UPubnubMentionTarget* Target = UPubnubMentionTarget::CreateUserMentionTarget(TEXT("user-id"));
6Draft->AddMention(5, 4, Target);
7
8// Reading elements (UObjects)
9TArray<UPubnubMessageElement*> Elements = /* delivered via callback */;
10FString Text = Elements[0]->GetText();

Sample widget​

Unreal Chat SDK 1.0.0 includes a sample UI widget (W_PubnubChatSample) in the plugin's Content folder. The widget demonstrates initialization, sending and receiving messages, presence, and moderation. Open it in the Unreal Editor to see a working reference implementation before building your own UI.

New capabilities in 1.0.0​

The following features are new in 1.0.0 and have no counterpart in 0.x.x. Consider adopting them after completing your migration.

FeatureDescription
Connection statusChat->OnConnectionStatusChanged delegate fires with EPubnubChatConnectionStatus (PCCS_ConnectionOnline, PCCS_ConnectionOffline, PCCS_ConnectionError) whenever the underlying PubNub connection changes. Refer to connection management for more details.
Disconnect / ReconnectChat->DisconnectSubscriptions() drops all active subscriptions; Chat->ReconnectSubscriptions(FString Timetoken) restores them, optionally catching up from a timetoken.
Rate limiterFPubnubChatRateLimiterConfig in FPubnubChatConfig lets you configure per-channel-type send rate limits and an exponential backoff factor. See Config → RateLimiter in Initial configuration.
EmitReadReceiptEvents configFPubnubChatConfig.EmitReadReceiptEvents (TMap<FString, bool>) controls which channel types emit read receipt signals (public, group, direct).
Global presenceStoreUserActivityTimestamps and StoreUserActivityInterval in FPubnubChatConfig track the last active time for all users. See global presence.
InitChatAsync()Non-blocking initialization via PubnubChatSubsystem->InitChatAsync(PubKey, SubKey, UserID, OnInitChatDelegate).
Native lambda callbacksAll *Async methods accept a *Native delegate variant that takes a lambda instead of a UObject delegate. For example, FOnPubnubChatOperationResponseNative.

Migration steps​

To migrate from Unreal Chat SDK 0.x.x to 1.0.0:

  1. Install the Core SDK. If you use FAB, install the PubNub Gaming SDK which includes both plugins. If you use GitHub, download the PubNub Unreal Engine Core SDK plugin and place it in your project's Plugins folder. Delete the Intermediate and Binaries folders and rebuild the project.
  2. Update every Join() call that expects to receive messages: add a Connect() call after Join() and bind the channel's message delegate before calling Connect().
  3. Rename all entity types using the type renames table. Rename CustomDataJson to Custom on data structs.
  4. Update enum value names to the new PascalCase format.
  5. Update InitChat, GetChat, and DestroyChat calls to pass a UserID argument. Extract the Chat pointer from FPubnubChatInitChatResult.
  6. Update all method return-value handling to check Result.Error before using the payload.
  7. Migrate streaming calls to the entity-first delegate pattern: bind to the entity's delegate property, call the parameterless Stream*() method, and call StopStreaming*() when done.
  8. Update read receipts usage: replace StreamReadReceipts() list-based calls with FetchReadReceipts() for snapshots and bind OnReadReceiptReceived for real-time updates.
  9. Replace DeleteMessage() and DeleteMessageHard() with Delete(bool Soft).
  10. Rename message accessors: Text() → GetCurrentText(), GetTimetoken() → GetMessageTimetoken(), Deleted() → IsDeleted(), Type() → GetType(), Reactions() → GetReactions().
  11. Update Forward() calls to pass a UPubnubChatChannel* object instead of a string ID.
  12. Swap GetUsers() and GetChannels() parameter order to (Limit, Filter, Sort, Page) and update the Sort argument type to FPubnubGetAllSort.
  13. Update Chat->SetRestrictions() to use the unified FPubnubChatRestriction struct.
  14. Migrate MessageDraft change listeners to OnMessageDraftUpdated delegate properties and update MentionTarget and MessageElement usage to the new struct types.
  15. Consider adopting *Async method variants to avoid blocking the game thread where appropriate.
  16. Review any code that holds multiple pointers to the same entity ID and relies on them being independent snapshots. In 1.0.0, all references to the same entity ID share the latest locally known data, so patterns that depended on independent copies will behave differently.

If you encounter issues during migration, contact PubNub Support.

Was this page useful?

Last updated on