# Push channels in CloudBehaviours

> Declare a push channel, listen for it in your game, and understand how delivery works.

> **Important:**
>
> This page describes an experimental feature that might change significantly before release. It's not recommended to use or rely on experimental features in production environments due to potential instability.

A public event on a CloudBehaviour becomes a push channel. When the cloud class invokes the event, Cloud Code sends a message to every player in the session (or, for a `Player`-scoped CloudBehaviour, to that player), and the generated client bindings raise a matching `UnityEvent`. Use a push channel to notify players the moment something happens, such as a turn ending, without polling.

Push channels carry notifications and payloads. To share state that a client can read at any time, use [synchronized state](/cloud-code/cloudbehaviours/synchronized-state.md) instead.

## Declare a push channel

A public event of type `Action`, `Action<T>`, `EventHandler`, or `EventHandler<T>` becomes a push channel:

```csharp title="Declaring a push channel"
[StateScope(Scope.MultiplayerSession)]
public class MatchState : CloudBehaviour
{
    public int Round;

    public event Action<string> RoundEnded;

    public void PlayTurn()
    {
        Round++;
        RoundEnded?.Invoke(Context.PlayerId);
    }
}
```

Event payloads serialize as JSON, and event payloads are limited to four parameters.

## Listen for push channel events in your game

The generated client bindings expose each push channel as a `UnityEvent`. Subscribe with `AddListener`:

```csharp title="Subscribing to a push channel"
protected virtual void OnEnable()
{
    EnableClient();
    matchStateClient.RoundEnded.AddListener(playerId => Debug.Log($"Round ended by {playerId}"));
}
```

Because the binding exposes push channels as `UnityEvent`s, you can also wire up listeners in the **Inspector** window.

## Delivery

Only connected clients receive a push message. Push channels are transient: they aren't stored or replayed for a player who connects later. Represent lasting state as [synchronized state](/cloud-code/cloudbehaviours/synchronized-state.md) instead.

Every player in the session receives an event you raise, whatever its payload. To send private data to one player, such as revealing which card a player drew, use `Push.SendPlayerMessageAsync(Context, message, messageType, playerId)` instead of an event. For shaping what a specific player sees in synchronized state, refer to [Per-player state views in CloudBehaviours](/cloud-code/cloudbehaviours/per-player-state-views.md).

## Additional resources

* [Turn-based game workflow](/cloud-code/cloudbehaviours/turn-based-game-workflow.md)
* [Synchronized state in CloudBehaviours](/cloud-code/cloudbehaviours/synchronized-state.md)
* [Per-player state views in CloudBehaviours](/cloud-code/cloudbehaviours/per-player-state-views.md)
