SignalBus Blueprint Usage
Review draft. This source page has not completed website editorial and release-specific verification.
SignalBus Blueprint nodes provide a simple way for Blueprints to publish and receive local messages without storing direct references to every other Actor or system.
Blueprints use the same runtime SignalBus subsystems as C++.
SignalBus does not create:
- A separate Blueprint-only bus
- A global message registry
- Automatic Actor discovery
- Automatic server-to-client messaging
- Automatic replication
Basic Concept
Section titled “Basic Concept”The normal flow is:
Publisher Blueprint -> SignalBus -> Listener Component -> Blueprint eventExample:
Enemy Blueprint -> publishes Combat.EnemyDefeated -> Quest Blueprint reacts -> UI Blueprint reacts -> Audio Blueprint reactsThe Enemy Blueprint does not need direct references to the Quest, UI, or Audio Blueprints.
Quick Start
Section titled “Quick Start”A basic Blueprint setup has four parts:
- Create a payload struct.
- Add a
SignalBus Listener Componentto the receiving Actor. - Subscribe using the same Message ID and payload struct.
- Publish using the matching scope, Message ID, and payload struct.
All three routing values must match:
ScopeMessage IDExact payload struct typeIf any one of those differs, the subscriber does not receive the message.
1. Create a Payload Struct
Section titled “1. Create a Payload Struct”SignalBus payloads must be reflected Unreal structs.
Create a Blueprint Structure such as:
ST_HealthChangedExample fields:
Old Health: FloatNew Health: FloatInstigator Name: NameA typical payload should contain only the information needed to describe the event.
Good payload:
ST_DoorOpened- Door ID- Instigator- Open DirectionAvoid very large payloads containing full inventories, large arrays, save-game data, or entire object state.
SignalBus works best with small event descriptions.
2. Create a Message ID
Section titled “2. Create a Message ID”Use:
Make SignalBus Message IdProvide a stable Name.
Example:
Combat.HealthChangedOther examples:
Combat.DamageAppliedQuest.ObjectiveCompletedUI.NotificationRequestedWorld.DoorOpenedSave.CompletedTravel.StartedNone is invalid.
Message IDs do not need to be registered in a central list, but spelling must match exactly between publishers and subscribers.
Recommended naming style:
Category.EventNameExamples:
Combat.PlayerDiedInventory.ItemAddedObjective.ProgressChangedFrontend.ScreenChangedAvoid vague names such as:
UpdateEventChangedMessage1Clear names make diagnostics and the Broadcast Graph easier to understand.
3. Add a Listener Component
Section titled “3. Add a Listener Component”Add:
SignalBus Listener Componentto the Actor that should receive messages.
Typical listener Actors include:
- HUD controllers
- UI coordinators
- Quest managers
- Audio managers
- Gameplay Actors
- Actor Components
- World managers
- Session managers
The Listener Component owns the subscriptions created through it.
When the Actor ends play, the component can automatically unsubscribe those handles.
Leave:
Auto Unsubscribe On End Playenabled unless you have a specific reason to manage cleanup manually.
4. Subscribe to a Message
Section titled “4. Subscribe to a Message”Use one of these nodes:
Subscribe Signal WorldSubscribe Signal Game InstanceChoose the scope based on where the message belongs.
World subscription
Section titled “World subscription”Use World scope for messages tied to the current map, match, or gameplay World.
Examples:
Combat.DamageAppliedEnemy.SpawnedDoor.OpenedObjective.ProgressChangedProjectile.ImpactGame Instance subscription
Section titled “Game Instance subscription”Use Game Instance scope for local session-level messages that may survive map travel.
Examples:
Profile.LoadedSave.CompletedLogin.StatusChangedMatchmaking.SearchStartedTravel.StartedTravel.CompletedPayload Type Sample
Section titled “Payload Type Sample”The subscription node includes:
Payload Type SampleConnect a value of the exact payload struct you expect.
Example:
Subscribe Signal WorldMessage ID: Combat.HealthChangedPayload Type Sample: ST_HealthChangedThe sample is used only to identify the expected struct type.
The values inside the sample are not used for filtering.
SignalBus matches exact struct identity.
This means:
ST_HealthChangeddoes not match:
ST_HealthChangedExtendedeven when the two structs contain similar fields.
5. Receive the Message
Section titled “5. Receive the Message”Override or implement:
On SignalBus Message ReceivedThe callback provides:
Message IDPayloadScopeSubscription HandleThe callback runs only for subscriptions created by that Listener Component.
Blueprint callbacks receive an owned payload copy so the data remains safe during Blueprint execution.
The callback is not a second message and does not create duplicate routing.
6. Extract the Payload
Section titled “6. Extract the Payload”Use:
Get SignalBus Payload AsConnect the output to the exact struct type used for the subscription.
Example:
On SignalBus Message Received -> Get SignalBus Payload As ST_HealthChanged -> Branch on Success -> update health barExtraction succeeds only when the stored payload type exactly matches the requested output struct.
Always check the success result before using the extracted value.
Recommended flow:
Get SignalBus Payload As -> Success? True -> use payload False -> log or ignoreA failed extraction usually means:
- The wrong struct type was requested
- The subscription was configured with a different payload type
- The same Message ID is being used with multiple payload structs
Publishing Messages
Section titled “Publishing Messages”Use one of these explicit nodes:
Publish Signal Immediate WorldPublish Signal Queued WorldPublish Signal Immediate Game InstancePublish Signal Queued Game InstanceThe payload pin accepts only reflected USTRUCT values.
You cannot publish these directly as top-level payloads:
IntegerFloatBooleanStringObject referenceArraySetMapWrap them inside a Blueprint Structure.
Example:
Instead of publishing a Float directly:
New Health: 75.0create:
ST_HealthChanged- New Health: 75.0Immediate Publish
Section titled “Immediate Publish”Immediate publish is synchronous.
The subscriber callback runs before the publish node finishes.
Expected order:
Before PublishOn SignalBus Message ReceivedAfter PublishExample scenario:
Player takes damage -> publish Combat.HealthChanged immediately -> health UI updates -> damage audio reacts -> execution returns to the publisherUse Immediate when local listeners must react during the current execution flow.
Good uses:
- Updating local UI immediately
- Notifying gameplay systems of a completed state change
- Synchronous local coordination
- Events where callback order matters
Be careful with heavy work inside immediate subscribers because it delays the publisher.
Queued Publish
Section titled “Queued Publish”Queued publish is deferred.
The payload is copied into the subsystem queue and the publish node returns before subscribers run.
Expected order:
Before QueueAfter QueueOn SignalBus Message ReceivedExample scenario:
Inventory system queues Inventory.Refreshed -> current function finishes -> later queue pass delivers the message -> UI and audio reactUse Queued when:
- The publisher should finish first
- Work can happen later
- You want to avoid deep immediate callback chains
- You want FIFO deferred delivery
Queued messages are delivered in order within their owning subsystem.
Queued delivery is not a timer. It does not mean “deliver in five seconds.” It means “deliver during a later SignalBus queue-processing pass.”
Publisher Pin
Section titled “Publisher Pin”Publish nodes may include an optional:
Publisherpin.
This pin is used for diagnostics and graph identity only.
It does not affect routing.
A subscriber is not selected based on the Publisher object.
SignalBus does not strongly retain the Publisher.
Example:
Publisher: SelfThis helps the Inspector show which object produced the message.
Example Scenario 1: Door Opened
Section titled “Example Scenario 1: Door Opened”Payload
Section titled “Payload”ST_DoorOpened- Door Name- InstigatorPublisher
Section titled “Publisher”Door Blueprint:
Open Door -> Make ST_DoorOpened -> Publish Signal Immediate World Message ID: World.DoorOpened Publisher: SelfSubscriber
Section titled “Subscriber”Quest Manager Blueprint:
Begin Play -> Subscribe Signal World Message ID: World.DoorOpened Payload Type Sample: ST_DoorOpenedCallback:
On SignalBus Message Received -> Get SignalBus Payload As ST_DoorOpened -> check Door Name -> update questWhy World scope?
The door belongs to the current gameplay World.
Example Scenario 2: Save Completed
Section titled “Example Scenario 2: Save Completed”Payload
Section titled “Payload”ST_SaveCompleted- Slot Name- Success- Error MessagePublisher
Section titled “Publisher”Save Manager Blueprint:
Save operation finishes -> Publish Signal Immediate Game Instance Message ID: Save.CompletedSubscriber
Section titled “Subscriber”Frontend UI Blueprint:
Subscribe Signal Game Instance Message ID: Save.Completed Payload Type Sample: ST_SaveCompletedCallback:
Get SignalBus Payload As ST_SaveCompleted -> Success? True -> show saved notification False -> show errorWhy Game Instance scope?
Save status belongs to the local session and may remain relevant across map travel.
Example Scenario 3: Replicated Health Change
Section titled “Example Scenario 3: Replicated Health Change”SignalBus does not replicate messages.
For multiplayer, use Unreal networking first.
Server:
Server changes Health -> Health replicatesClient:
OnRep_Health -> Publish Signal Immediate World Message ID: Combat.HealthChangedLocal client listeners:
HUDAudioCamera effectsAccessibility feedbackSignalBus handles local reactions after replication arrives.
Do not expect a server SignalBus publish to automatically reach client subscribers.
Example Scenario 4: Travel Started
Section titled “Example Scenario 4: Travel Started”Use the Game Instance bus.
Publisher:
Before opening a new map -> Publish Signal Immediate Game Instance Message ID: Travel.StartedSubscribers:
Loading screenSession managerSave coordinatorFrontend flowThe Game Instance bus can survive while the old World is destroyed.
Do not queue a World message and expect it to survive into the next map.
Scope Isolation
Section titled “Scope Isolation”World and Game Instance are separate buses.
This will not deliver:
Publisher:Publish Signal Immediate WorldMessage ID: Save.Completed
Subscriber:Subscribe Signal Game InstanceMessage ID: Save.CompletedThe Message ID may match, but the scope does not.
Likewise, each PIE client, server World, and Game Instance owns a separate SignalBus context.
SignalBus does not share messages between network peers.
Exact Payload Matching
Section titled “Exact Payload Matching”SignalBus does not convert payload types.
These do not match:
Subscriber expects ST_DamageAppliedPublisher sends ST_DamageApplied_ExtendedThese also do not match:
Subscriber expects ST_HealthChangedPublisher sends ST_HealthUpdatedeven if the fields are identical.
Use one clearly defined struct for each message contract.
A good rule is:
One Message IDOne expected payload structTechnically, the same Message ID can be used with multiple payload types, but doing so makes debugging and Blueprint extraction more confusing.
Subscription Handles
Section titled “Subscription Handles”Subscribe nodes return a subscription handle.
Store the handle when you need manual control.
Use it to:
- Unsubscribe one specific subscription
- Check which callback registration is being removed
- Manage temporary listening states
Example:
Begin Listening -> Subscribe Signal World -> store handle
Stop Listening -> Unsubscribe using stored handleDo not invent or modify handles manually.
A handle is valid only for the subsystem and subscription that created it.
Unsubscribing
Section titled “Unsubscribing”Most Actor-based listeners should rely on:
Auto Unsubscribe On End PlayManual unsubscribe is useful when:
- A temporary mode ends
- A UI panel closes
- A listener should stop reacting before Actor destruction
- The same component owns multiple subscriptions
If the component provides Unsubscribe All, it removes only handles created by that component.
It does not clear other subscribers from the bus.
Repeated unsubscribe should be treated as a no-op or failed removal, not as a new action.
Common Pitfalls
Section titled “Common Pitfalls”1. Wrong scope
Section titled “1. Wrong scope”Publisher:
Publish Signal WorldSubscriber:
Subscribe Signal Game InstanceResult:
No deliveryFix: use the same scope.
2. Message ID typo
Section titled “2. Message ID typo”Publisher:
Combat.HealthChangedSubscriber:
Combat.HealthChangeResult:
No deliveryFix: use the exact same Name.
3. Wrong payload struct
Section titled “3. Wrong payload struct”Publisher sends:
ST_HealthChangedSubscriber expects:
ST_DamageAppliedResult:
No deliveryFix: use the exact same reflected struct.
4. Forgetting to subscribe
Section titled “4. Forgetting to subscribe”Adding a Listener Component alone does not create a subscription.
You must call:
Subscribe Signal Worldor:
Subscribe Signal Game Instance5. Subscribing repeatedly
Section titled “5. Subscribing repeatedly”Calling Subscribe every Tick or every time a widget refreshes creates duplicate subscriptions.
Result:
One publish -> callback runs multiple timesSubscribe once during an appropriate lifecycle event, such as:
Begin PlayOn InitializedOn ActivatedUnsubscribe when that listening period ends.
6. Publishing every Tick
Section titled “6. Publishing every Tick”Publishing every frame can create:
- High callback volume
- Large diagnostic history
- Warning activity
- Queue backlog
- Editor slowdown
Publish only when meaningful state changes.
Bad:
Tick -> Publish HealthChanged every frameBetter:
Health value actually changes -> Publish HealthChanged once7. Using queued delivery as a timer
Section titled “7. Using queued delivery as a timer”Queued does not mean delayed by a specific number of seconds.
Use Unreal timers for scheduled behavior.
Set Timer -> timer expires -> publish SignalBus message8. Expecting old messages after subscribing
Section titled “8. Expecting old messages after subscribing”SignalBus does not replay history.
Message publishedSubscriber registers laterThe new subscriber does not receive the old message.
Read current state first, then subscribe for future changes.
9. Assuming SignalBus replicates
Section titled “9. Assuming SignalBus replicates”A client-local publish does not reach the server.
A server-local publish does not reach clients.
Use:
- Server RPCs
- Client RPCs
- NetMulticast RPCs
- Replicated properties
Then publish locally after the network event arrives.
10. Large Blueprint payloads
Section titled “10. Large Blueprint payloads”Blueprint listeners copy payloads for safety.
Large arrays, maps, strings, and nested structs increase copy cost.
Prefer compact payloads containing:
- IDs
- Names
- Small numeric values
- Small state summaries
- Weak or soft identity information where appropriate
Let subscribers query large durable state from its owning system.
11. Heavy immediate callbacks
Section titled “11. Heavy immediate callbacks”Immediate callbacks run before the publisher continues.
A slow subscriber delays every immediate publisher using that message.
Use queued delivery when work does not need to complete immediately.
12. Assuming Publisher affects routing
Section titled “12. Assuming Publisher affects routing”The optional Publisher object is diagnostic context only.
Subscribers do not filter automatically by Publisher.
If filtering is required, include an identifier in the payload and check it in the subscriber.
Example:
ST_DoorOpened- Door IDSubscriber:
if Door ID == Expected Door -> reactRecommended Blueprint Lifecycle
Section titled “Recommended Blueprint Lifecycle”Actor listener
Section titled “Actor listener”Begin Play -> Subscribe
End Play -> automatic unsubscribeTemporary UI listener
Section titled “Temporary UI listener”Widget Activated -> Subscribe -> store handle
Widget Deactivated -> UnsubscribePersistent session listener
Section titled “Persistent session listener”Game Instance-managed object initializes -> Subscribe Signal Game Instance
Object shuts down -> UnsubscribeAvoid subscribing in construction scripts.
Construction scripts may run in editor contexts and multiple times.
Diagnostics and Debugging
Section titled “Diagnostics and Debugging”Blueprint publishes and subscriptions appear in the same runtime diagnostics used by C++.
Use the SignalBus Runtime Inspector to review:
- Active subscriptions
- Message history
- World and Game Instance contexts
- Queued messages
- Payload snapshots
- Warning entries
- Publisher and subscriber identities
- Broadcast Graph topology
Useful checks when a message is not received:
- Is the subscriber active?
- Do scopes match?
- Do Message IDs match exactly?
- Do payload structs match exactly?
- Is the correct PIE context selected?
- Was the message Immediate or Queued?
- Was the listener destroyed or unsubscribed?
- Did queued processing occur?
- Was queue capacity exceeded?
- Did
Get SignalBus Payload Assucceed?
Payload inspection captures the routed payload once. It does not create a separate snapshot for every Blueprint subscriber.
Blueprint Performance Guidance
Section titled “Blueprint Performance Guidance”Prefer:
- Small payload structs
- Event-based publishing
- One subscription per intended listener
- Queued delivery for non-urgent work
- Immediate delivery only when synchronous behavior is required
- Stable Message IDs
- Automatic cleanup
Avoid:
- Publishing every Tick
- Very large containers
- Deep nested payload structs
- Repeated duplicate subscription
- Long-running immediate callbacks
- Using SignalBus as bulk storage
- Using SignalBus instead of replication
Final Checklist
Section titled “Final Checklist”For every Blueprint message flow, confirm:
Publisher scope matches subscriber scopeMessage ID matches exactlyPayload struct matches exactlyListener Component existsSubscribe node has executedPayload extraction checks SuccessSubscription is cleaned upImmediate or Queued mode is intentionalNetwork behavior is handled separatelyThe simplest reliable pattern is:
Create a small payload structUse one stable Message IDSubscribe oncePublish only when something changesExtract the exact payload typeLet the Listener Component clean up