How to wait for server confirmed attribute change when using predicted gameplay effects?

Using UE 5.7.2-0
Context on how “Wait for Attribute Changed” and “Wait Gameplay Effect Applied to Actor” behave in my observations.

Wait for Attribute Changed: fires 3x on the predicting client, once the predicted application (infinite effect), the removal of that effect, application of the server instant effect. That’s all expected but I cannot differentiate between predictions, actual increases or decreses and server side changes at all.

Wait Gameplay Effect Applied to Actor: only fires once with the predicted effect. If it would just fire twice I could check if it was a infinite effect + some tags and could determine if it was the server. But even then this solution would only work for the local client as effects are not replicated to other players.


Possible solutions I could think off:

After “Wait Gameplay Effect Applied to Actor” triggers, wait for the active handle to be invalid, then look up the new server effect. Kinda works for duration effects but is inconsistant and I was not able to get it to work with instants.

Write my own “Wait Gameplay Effect Applied to Actor” that somehow hooks into the modify effect value, which is used when the predicted effects values or duration changes. I read through lot of the sourcecode to understand prediction, I think i got a quite good grasp on it but I’m not confident in writhing such a wait function myself if there are other options.

Use a Gameplay Cue. I didn’t find a way yet to solve my issue with Cues. It would solve that that other clients also get the information with as much context as I need.

Only Wait for (either function), on the server and then use RPCs to trigger the desired effects on the owning or all clients. Seems very flexible, I think I could implement that but feels like I’m working around GAS, maybe there is a solution I’m missing. :slight_smile:

Enabling full effect replication (I’m mixed right now), I think would be a bad desicion for my game as I have a ton of effects that only concern the predicting onwing client and the server.

Clear prediction key before such effects (disable prediction essentially). I tested that works but kinda feels like I’m working against GAS.


To answer possible questions like: “do you need those attribute changes to be predicted?”. Right now I do not not but I generally need a solution to listen to the effect modification (magnitude/duration change) so I can use the predicted effect for instant feedback and server effect for correction.

Edit: Also just having an option to only wait for the server effect in general, ignoring the prediction, would be nice. My solution for that was just checking active effects periodically on the client, doesn’t work for instants tho.

You’re running into a fundamental limitation of how prediction works in GAS—there isn’t a built-in way to “just wait for the server-confirmed attribute change” because predicted and authoritative changes intentionally go through the same pathways.

Why your current observations happen

  • Wait for Attribute Changed
    Fires multiple times because:

    1. Predicted application (client)

    2. Rollback/removal of prediction

    3. Server authoritative application

    GAS does not tag these with “this is predicted vs server,” so from the outside they look identical.

  • Wait Gameplay Effect Applied to Actor
    Only fires for predicted effects locally because:

    • Predicted effects exist only on the predicting client

    • Server-applied instant effects don’t replicate as “applied events” to other clients


The core issue

GAS does not expose a clean “this change is server-confirmed” signal at the Blueprint level.

So you need to differentiate using prediction context, not the events themselves.


Recommended solutions (from most “GAS-friendly” to workaround)

:white_check_mark: 1. Check Prediction Keys (best low-level solution)

If you go C++ (or expose it), you can inspect:

  • FGameplayEffectContextHandle

  • FPredictionKey

Key idea:

  • Predicted effects → have a valid local prediction key

  • Server effects → come with a different / no local prediction key

You can filter like:

if (Spec.GetContext().GetPredictionKey().IsLocalClientKey())
{
    // predicted
}
else
{
    // server confirmed
}

:backhand_index_pointing_right: This is the correct way internally, but not exposed in Blueprint by default.


:white_check_mark: 2. Use Gameplay Cues for “confirmed” signals (recommended for BP)

You were close here—this is actually one of the intended patterns.

  • Predicted GE → no cue (or local-only cue)

  • Server GE → triggers Gameplay Cue

Then:

  • Listen to the Gameplay Cue as your authoritative signal

  • Use predicted attribute change only for responsiveness

:check_mark: Works for:

  • Owning client

  • Other clients

  • Instants + duration effects


:white_check_mark: 3. Hybrid approach (most common in production)

Use both:

  • Attribute change delegate
    → for immediate feedback (predicted)

  • Gameplay Cue OR replicated event
    → for server confirmation / correction

This avoids fighting GAS while still giving you control.


:warning: 4. Polling / Active Handle tricks

As you noticed:

  • Works inconsistently

  • Breaks for instants

  • Not reliable

:backhand_index_pointing_right: I would avoid this entirely.


:warning: 5. Disabling prediction / clearing prediction key

This works but defeats the purpose of GAS prediction.

Only use it if:

  • The effect truly doesn’t need responsiveness

:warning: 6. Server-only + RPC

This is valid and sometimes necessary, but:

Yes, this is working around GAS.

Use it only when:

  • You need very custom behavior

  • GAS abstractions don’t fit


:key: Practical takeaway

There is no “wait for server-only attribute change” node.

Instead, structure it like this:

  • Predicted Attribute Change
    → UI feedback, responsiveness

  • Gameplay Cue (server)
    → confirmation, VFX, corrections, gameplay logic


Bonus: If you really want a BP-only filter

A hacky but usable approach:

  • Store last predicted value

  • Ignore the first change(s) within the same frame / prediction window

  • Accept the stabilized value after rollback

Still not perfect, but works for UI cases.


Final recommendation

If you want something robust and scalable:

:backhand_index_pointing_right: Use Gameplay Cues as your “server-confirmed event layer”
:backhand_index_pointing_right: Use Attribute Changed only for prediction feedback

That aligns with how GAS is designed to be used, instead of fighting it.