Overview
IoTPulse gives Unreal Engine 4.27 and 5.8 games a managed realtime message bus without running servers: lobby chat, live events, presence, spectator feeds, remote configuration and companion apps all become MQTT topics on AWS IoT Core. Messages, connection events and results always arrive on the game thread.
- Connect: MQTT 5 over a secure WebSocket (port 443), the handshake signed with AWS Signature V4 using the player's credentials.
- Connect With Certificate: X.509 client certificate (mutual TLS) for kiosks and other fixed devices.
- Publish, Subscribe with
+/#wildcards, QoS 0 and 1, retained messages, last will, MQTT 5 request / response (response topic, correlation data) and user properties. - Automatic reconnect with exponential back-off; subscriptions are renewed when the broker lost the session.
- Device shadows over HTTPS: Get Shadow, Update Shadow (reported or desired state, optimistic locking), Delete Shadow; realtime shadow updates over MQTT with Make Shadow Topic.
- Publish (HTTPS) for one-off messages without a connection.
- Amazon Cognito identity pools for guests and signed-in players; static keys and the default AWS chain for development and servers.
Requirements
| Requirement | Details |
|---|---|
| Unreal Engine | 4.27 and 5.8 |
| Platforms | Win64, Linux and Android |
| Modules | IoTPulse (Runtime), IoTPulseSdk (prebuilt AWS SDK for C++ 1.11.916 and the AWS Common Runtime in Source/ThirdParty) |
| Dependencies | No other plugins. On Linux and Android TLS trusts the root certificates of the engine's SSL module; HTTPS uses the engine's libcurl and OpenSSL. |
| AWS | An AWS account with AWS IoT Core and a Cognito identity pool. Messages, connection minutes and shadow operations are billed by AWS. |
Installation
- Install IoTPulse from Fab into your engine, or copy the
IoTPulsefolder into your project'sPluginsfolder. - Enable IoTPulse in Edit > Plugins and restart the editor.
- Open Project Settings > Plugins > IoTPulse and set Region, Identity Pool Id and IoT Data Endpoint.
- C++ only: add
PublicDependencyModuleNames.Add("IoTPulse");to yourBuild.cs.
Setting up AWS
- Find your account's IoT data endpoint: AWS IoT console > Settings > Device data endpoint, or
aws iot describe-endpoint --endpoint-type iot:Data-ATS. It looks likea1b2c3d4e5f6g7-ats.iot.us-east-1.amazonaws.com; paste it into IoT Data Endpoint. - In Amazon Cognito create an identity pool. Enable guest access if players may connect before signing in, and add your identity providers (for example a Cognito user pool).
- Edit the IAM role the pool gives to players (authenticated and/or guest). The example lets each player connect only with their own identity id as client id, use topics under
mygame/and the shadows of things namedmygame-*:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:Connect",
"Resource": "arn:aws:iot:us-east-1:123456789012:client/${cognito-identity.amazonaws.com:sub}"
},
{
"Effect": "Allow",
"Action": ["iot:Publish", "iot:Receive"],
"Resource": [
"arn:aws:iot:us-east-1:123456789012:topic/mygame/*",
"arn:aws:iot:us-east-1:123456789012:topic/$aws/things/mygame-*/shadow/*"
]
},
{
"Effect": "Allow",
"Action": "iot:Subscribe",
"Resource": [
"arn:aws:iot:us-east-1:123456789012:topicfilter/mygame/*",
"arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/mygame-*/shadow/*"
]
},
{
"Effect": "Allow",
"Action": ["iot:GetThingShadow", "iot:UpdateThingShadow", "iot:DeleteThingShadow"],
"Resource": "arn:aws:iot:us-east-1:123456789012:thing/mygame-*"
}
]
}
Connect leaves the client id empty by default, which makes it the player's identity id - exactly what ${cognito-identity.amazonaws.com:sub} expands to. The same variable keeps per-player topics private, for example topic/mygame/players/${cognito-identity.amazonaws.com:sub}/*. Publish uses topic/ resources, Subscribe uses topicfilter/ resources (the filter exactly as written, wildcards included), Receive is checked for every delivered message.
aws iot attach-policy --policy-name MyGamePlayers --target us-east-1:01234567-89ab-.... AttachPolicy is an administrator operation: run it from your backend (for example a Lambda function called once after sign-up, using Get Identity Id), never grant iot:AttachPolicy to the player role. Guest (unauthenticated) identities only need the IAM role.DefaultGame.ini and in packaged games. Use them only for development and dedicated servers; players should always use the identity pool. Shipping builds refuse settings keys unless Allow Static Keys In Shipping is enabled.Certificates (Connect With Certificate)
For kiosks and venue machines register the device as a thing in AWS IoT, create a certificate, attach an IoT policy to it and copy the certificate and private key (PEM) to the device. The client id is usually the thing name. Never put a device key into a game that players download.
Quick start
Lobby chat
- On Begin Play call Connect (defaults are fine). From On Connected store Connection in a variable.
- Bind On Message of the connection to a custom event and call Subscribe with
mygame/lobby/42/chat. - To send, call Publish on the connection: Topic
mygame/lobby/42/chat, Payload{"from":"Ana","text":"gg"}. - In the On Message event read Message > Payload (and Topic to tell channels apart; Topic Matches Filter helps with wildcards).
- On End Play call Disconnect.
Presence with a last will
Set Options > Will Topic to mygame/presence/<player>, Will Payload to {"online":false} and Will Retain on, then publish {"online":true} with Retain after connecting. If the game crashes or loses the network, AWS IoT Core publishes the will for you; a normal Disconnect does not.
Latent nodes
All latent nodes run in the background, can be stopped with Cancel on their return value and fire exactly one final pin on the game thread.
| Node | Inputs | Outputs | Description |
|---|---|---|---|
| Connect | Options, Endpoint | On Connected / On Failure (Connection, Error) | MQTT 5 over a secure WebSocket, signed with the plugin's credentials. Fails on the first refused attempt (wrong endpoint, policy, credentials); after that the connection reconnects by itself. |
| Connect With Certificate | Certificate File, Private Key File, Options, Endpoint | On Connected / On Failure (Connection, Error) | Mutual TLS with an X.509 device certificate. Files are PEM; relative paths start at the project folder and packaged (non-asset) files are found too. The PEM text itself is accepted as well. |
| Publish And Wait | Connection, Topic, Payload, Payload Bytes, QoS (default QoS 1), Retain | On Success / On Failure (Error) | Publishes and waits for the broker's acknowledgement. On Failure covers "not authorized" (reason code 135), a stopped connection and the Ack Timeout. |
| Get Shadow | Thing Name, Shadow Name | On Success / On Not Found / On Failure (Shadow, Error) | Reads a device shadow over HTTPS. Empty Shadow Name = the classic shadow. |
| Update Shadow | Thing Name, Shadow Name, Document, Section, Expected Version | On Success / On Failure (Shadow, Error) | Merges Document into state.reported (default) or state.desired, or sends a full document. Expected Version > 0 fails with ConflictException if somebody else changed the shadow first. |
| Delete Shadow | Thing Name, Shadow Name | On Success / On Failure (Error) | Deletes a device shadow. |
| Publish (HTTPS) | Topic, Payload, QoS, Retain | On Success / On Failure (Error) | One message over HTTPS, no connection needed - for occasional events such as a match result. |
| Resolve Identity | Force Refresh | On Success / On Failure (Identity Id, Error) | Fetches the Cognito identity and temporary credentials now, for example right after login, so Connect is fast and errors show up early. |
Connection object
UIoTPulseConnection is returned by Connect. While it runs, the game instance keeps it alive; it is closed automatically when the game instance shuts down (end of Play In Editor, quitting). One object = one connection: after it stopped, call Connect again.
| Member | Kind | Description |
|---|---|---|
| Publish | Callable | Topic, Payload (UTF-8 text), QoS, Retain; advanced: Payload Bytes (binary, used when not empty), Response Topic, Correlation Data. Returns false if the message could not be queued. While reconnecting QoS 1 messages wait, QoS 0 messages are dropped. |
| Subscribe | Callable | Topic filter with + (one level) and # (the rest), QoS. The answer arrives on On Subscribed; the filter is renewed after reconnects. |
| Unsubscribe | Callable | Stops a subscription. |
| Disconnect | Callable | Sends DISCONNECT (the last will is not published) and stops reconnecting; On Stopped follows. |
| Is Connected | Pure | True while the connection is up (false during a reconnect). |
| Get Client Id | Pure | The MQTT client id in use. |
| On Message | Event | Message: Topic, Payload, Payload Bytes, QoS, Retain, Response Topic, Correlation Data, Content Type, User Properties. |
| On Connection Lost | Event | The connection dropped (network, credentials expired, another client with the same id). It reconnects unless Auto Reconnect is off. |
| On Reconnected | Event | Connected again; Session Present tells whether the broker kept the session. |
| On Stopped | Event | The connection stopped for good (Disconnect, or a drop with Auto Reconnect off). |
| On Subscribed | Event | Topic Filter, Success, Granted QoS, Error - the broker's answer to Subscribe. A refused filter (not authorized) is not renewed. |
Functions
| Node | Description |
|---|---|
| Set Region | Switches the AWS region for every following connection and request. |
| Set Credential Mode | Overrides the credential mode from the settings at runtime. |
| Set Login Token | Signs the player in to the identity pool with a provider token (Cognito user pool, Google, Apple, Facebook, OpenID). Connect again afterwards to use the new identity. |
| Clear Login Tokens | Forgets all login tokens and the cached identity; the player becomes a guest. |
| Set Static Credentials | Uses the given keys from now on (Static Keys mode), for example temporary keys handed out by your backend. |
| Get Identity Id | The player's Cognito identity id (the default client id); empty until credentials were resolved once. |
| Make User Pool Provider Name | Builds the login key of a Cognito user pool: cognito-idp.<region>.amazonaws.com/<pool id>. |
| Is Configured | Returns false and a reason when the endpoint or credentials are not set. |
| Make Topic | Joins levels with "/": ["mygame", "lobby", "42"] becomes mygame/lobby/42. |
| Make Shadow Topic | The reserved MQTT topic of a shadow, for example $aws/things/mygame-lobby42/shadow/name/state/update/delta. |
| Topic Matches Filter | True if a topic matches a filter with + and # wildcards (MQTT rules, case-sensitive). |
| Cancel | On a latent node's return value: none of its pins fire any more. |
| Is Finished | On a latent node's return value: true after it finished or was cancelled. |
Device shadows
A shadow is a small JSON document that AWS IoT Core stores per thing: state.reported (what is), state.desired (what should be) and state.delta (the difference). Games use them for lobby state, server status boards, persistent room settings or companion-app controls.
- Create a thing (for example
mygame-lobby42) in the AWS IoT console, or let your backend create one per room. - Update Shadow with Document
{"players":3,"map":"dunes"}writes state.reported. Set a field tonullto remove it; Documentnullclears the section. - Get Shadow returns the whole document plus Reported, Desired and Delta as JSON strings, and the Version for optimistic locking.
- Realtime: Subscribe to Make Shadow Topic with Topic = update/documents (every change) or update/delta (desired changes for a device).
Credentials
| Mode | Use for | How |
|---|---|---|
| Cognito Identity Pool | Game clients | Guests get unauthenticated credentials; after Set Login Token the player gets the authenticated role. Credentials refresh automatically before they expire, also for reconnects. |
| Static Keys | Development, dedicated servers, keys from your backend | Settings keys or Set Static Credentials (with an optional session token). |
| Default Credential Chain | Servers and tools | Environment variables, the ~/.aws profile, ECS and EC2 instance roles. |
| Certificate | Kiosks, fixed devices | Connect With Certificate; no AWS credentials involved. |
C++ API
// Build.cs: PublicDependencyModuleNames.Add("IoTPulse");
#include "IoTPulseAsyncActions.h"
#include "IoTPulseConnection.h"
UIoTPulseConnectAction* Action = UIoTPulseConnectAction::Connect(this, FIoTPulseConnectOptions(), FString());
Action->OnConnected.AddDynamic(this, &AMyActor::HandleConnected); // (UIoTPulseConnection*, const FIoTPulseError&)
Action->Activate();
void AMyActor::HandleConnected(UIoTPulseConnection* Connection, const FIoTPulseError& Error)
{
Mqtt = Connection; // UPROPERTY() UIoTPulseConnection* Mqtt;
Mqtt->OnMessage.AddDynamic(this, &AMyActor::HandleMessage);
Mqtt->Subscribe(TEXT("mygame/lobby/42/chat"));
Mqtt->PublishWithCallback(TEXT("mygame/lobby/42/chat"), TEXT("{\"text\":\"hi\"}"), EIoTPulseQoS::AtLeastOnce,
false, TArray<uint8>(), FString(), FString(),
[](bool bOk, const FIoTPulseError& Result) { /* game thread */ });
}
Every latent node class (UIoTPulseGetShadowAction, ...) can be created through its static factory function; bind the delegates, then call Activate().
Types
| Type | Kind | Members |
|---|---|---|
| FIoTPulseConnectOptions | Struct | Client Id, Keep Alive Seconds, Clean Start, Session Expiry Seconds, Will Topic, Will Payload, Will QoS, Will Retain |
| FIoTPulseMessage | Struct | Topic, Payload, Payload Bytes, QoS, Retain, Response Topic, Correlation Data, Content Type, User Properties |
| FIoTPulseShadow | Struct | Thing Name, Shadow Name, Json, Reported, Desired, Delta, Version, Timestamp |
| FIoTPulseError | Struct | Code, Message, Http Status (or MQTT reason code), Retryable |
| EIoTPulseQoS | Enum | Default (Project Settings), QoS 0 (At Most Once), QoS 1 (At Least Once) |
| EIoTPulseShadowSection | Enum | Reported State, Desired State, Full Document |
| EIoTPulseShadowTopic | Enum | update, update/accepted, update/rejected, update/delta, update/documents, get, get/accepted, get/rejected, delete, delete/accepted, delete/rejected |
| EIoTPulseCredentialMode | Enum | Cognito Identity Pool, Static Keys, Default Credential Chain |
| UIoTPulseConnection | Class | See Connection object |
Settings
Project Settings > Plugins > IoTPulse (saved to DefaultGame.ini). HTTPS requests use changes at once, MQTT connections with the next Connect.
| Setting | Default | Description |
|---|---|---|
| Region | us-east-1 | Region of your IoT endpoint and identity pool. |
| Credential Mode | Cognito Identity Pool | Cognito Identity Pool, Static Keys or Default Credential Chain. |
| Identity Pool Id | (empty) | For example us-east-1:01234567-89ab-cdef-0123-456789abcdef. |
| Allow Guest Access | On | Unauthenticated identities before Set Login Token. The pool must allow guest access too. |
| Access Key Id / Secret Access Key | (empty) | Static Keys mode. Saved in DefaultGame.ini - development and servers only. |
| Allow Static Keys In Shipping | Off | Static keys from the settings are refused in Shipping builds unless enabled (dedicated servers). |
| IoT Data Endpoint | (empty) | Your account's endpoint, for example a1b2c3d4e5f6g7-ats.iot.us-east-1.amazonaws.com. Used for MQTT and HTTPS. |
| Keep Alive Seconds | 60 | MQTT keep-alive when Connect leaves it at 0 (AWS IoT Core accepts 30 - 1200). |
| Auto Reconnect | On | Reconnect after a drop. Off: a drop stops the connection. |
| Min / Max Reconnect Delay Ms | 1000 / 60000 | Exponential back-off with jitter between reconnect attempts. |
| Default QoS | QoS 0 | Used when a node's QoS is Default. |
| Ack Timeout Seconds | 30 | Wait for the acknowledgement of a QoS 1 publish, subscribe or unsubscribe. |
| Request Timeout Ms / Connect Timeout Ms | 30000 / 5000 | HTTPS request limit; network connect limit (HTTPS and MQTT). |
| Max Retries | 3 | Automatic HTTPS retries with exponential back-off for throttling and transient errors. |
| Worker Threads | 4 | Background threads for HTTPS requests and connection setup. |
| Verify SSL | On | HTTPS certificate checks. Only disable for a local emulator. |
| Log Sdk Warnings | On | Forwards SDK and runtime warnings to LogIoTPulse. |
Troubleshooting
| Error code | Cause and fix |
|---|---|
NotConfigured | Set the IoT Data Endpoint and the Identity Pool Id in Project Settings > Plugins > IoTPulse, or switch the credential mode. |
AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE | AWS refused the signed WebSocket handshake (HTTP 403): the role lacks iot:Connect for this client id, the region does not match the endpoint, or (signed-in players) no IoT policy is attached to the identity. |
NotAuthorized (135) | The broker refused a connect, subscribe or publish: check iot:Connect / iot:Subscribe (topicfilter) / iot:Publish (topic) / iot:Receive resources and the attached IoT policy. |
Refused (142, session taken over) | Another connection uses the same client id - every device of a player needs its own id (for example identity id + a suffix, allowed with client/${cognito-identity.amazonaws.com:sub}*). |
NotAuthorizedException | Guest access is off on the identity pool, or a login token expired. Enable guest access or call Set Login Token with a fresh token. |
ResourceNotFoundException | Get Shadow: the thing has no such shadow yet (On Not Found). Elsewhere: wrong thing name or endpoint. |
ConflictException | Update Shadow with Expected Version: the shadow changed in between. Read it again and retry. |
CertificateError | Connect With Certificate could not read the certificate or key file (path relative to the project folder, PEM format). |
Unavailable | The SDK library could not be loaded or the engine is shutting down. Check the Output Log for LogIoTPulse errors. |
Credits
© 2026 Alpha XP — alphaxp.net · Support: support@alphaxp.net. Includes the AWS SDK for C++ and the AWS Common Runtime (Apache License 2.0). Built for Unreal Engine 4.27 and 5.8.