On this page

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 (UPubnubUserUPubnubChatUser, FPubnubMessageActionFPubnubChatMessageAction, 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 dependency
Self-contained plugin (no additional dependency)
Requires PubNub Unreal Engine Core SDK plugin (PubnubLibrary)
Method return types
Raw pointer or void
Typed result struct (e.g. FPubnubChatUserResult) containing FPubnubChatOperationResult
Async methods
Not available
*Async suffix variants added for every network method
Real-time streaming
Stream*(Callback) returns UPubnubCallbackStop*
Stream*() (no callback); bind OnUpdated/OnXxx delegate; stop with StopStreaming*()
Join behavior
Join() also calls Connect() internally
Join() and Connect() are separate — call both to receive messages after joining
Read receipts
StreamReadReceipts() 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 delete
DeleteMessage() and DeleteMessageHard()
Delete(bool Soft = false)
Forward parameter
Message->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 Chat
Chat->SetRestrictions(FString UserID, FString ChannelID, FPubnubRestriction)
Chat->SetRestrictions(FPubnubChatRestriction)UserID and ChannelID now inside the struct
Subsystem InitChat return
UPubnubChat*
FPubnubChatInitChatResult containing .Chat and error info
Subsystem GetChat / DestroyChat
No arguments
Require FString UserID argument
Multiple chat instances
Not supported
Supported — keyed by UserID
MessageDraft change listener
AddChangeListener() / AddChangeListenerWithSuggestions()
Bind OnMessageDraftUpdated / OnMessageDraftUpdatedWithSuggestions delegate properties
Object identity
Independent snapshots. Two variables with the same entity ID can hold different data simultaneously
Synchronized 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 — no additional downloads were needed. Version 1.0.0 depends on the PubNub Unreal Engine Core SDK (PubnubLibrary).

To install the Core SDK:

  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
UPubnubUser
UPubnubChatUser
UPubnubChannel
UPubnubChatChannel
UPubnubMessage
UPubnubChatMessage
UPubnubMembership
UPubnubChatMembership
UPubnubThreadChannel
UPubnubChatThreadChannel
UPubnubAccessManager
UPubnubChatAccessManager
FPubnubMessageAction
FPubnubChatMessageAction
FPubnubRestriction
FPubnubChatRestriction
FPubnubEvent
FPubnubChatEvent
FPubnubSendTextParams
FPubnubChatSendTextParams
FPubnubCreatedChannelWrapper
FPubnubChatCreateGroupConversationResult / FPubnubChatCreateDirectConversationResult
FPubnubChannelsResponseWrapper
FPubnubChatGetChannelsResult
FPubnubUsersResponseWrapper
FPubnubChatGetUsersResult
FPubnubEventsHistoryWrapper
FPubnubChatEventsResult

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_TYPING
PCET_Typing
PCET_CUSTOM
PCET_Custom
PCS_Connected
PCCS_ConnectionOnline
PMAT_Reaction
PCMAT_Reaction
PMAT_Edited
PCMAT_Edited
PMAT_Deleted
PCMAT_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()bool
Message->IsDeleted()FPubnubChatIsDeletedResult
Message->Type()EPubnubChatMessageType
Message->GetType()FString
Message->Reactions()TArray<FPubnubMessageAction>
Message->GetReactions()FPubnubChatGetReactionsResult
Message->HasThread()bool
Message->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 status
Chat->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 / Reconnect
Chat->DisconnectSubscriptions() drops all active subscriptions; Chat->ReconnectSubscriptions(FString Timetoken) restores them, optionally catching up from a timetoken.
Rate limiter
FPubnubChatRateLimiterConfig in FPubnubChatConfig lets you configure per-channel-type send rate limits and an exponential backoff factor. See Config → RateLimiter in Initial configuration.
EmitReadReceiptEvents config
FPubnubChatConfig.EmitReadReceiptEvents (TMap<FString, bool>) controls which channel types emit read receipt signals (public, group, direct).
Global presence
StoreUserActivityTimestamps 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 callbacks
All *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. 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.

Last updated on