---
title: Per-player state views in CloudBehaviours
product: Cloud Code
version: 3.0.0
latest_version: 3.0.0
status: This page documents version 3.0.0. The latest version is 3.0.0.
canonical: https://docs.unity.com/en-us/cloud-code/3.0.0/cloudbehaviours/per-player-state-views
latest_url: https://docs.unity.com/en-us/cloud-code/3.0.0/cloudbehaviours/per-player-state-views.md
last_updated: 2026-10-23
generated_at: 2026-11-04T18:04:34.832Z
locale: en-us
---

# Per-player state views in CloudBehaviours

> Define a tailored, per-player subset of your CloudBehaviour's state, such as each player's own hand in a card game.

> **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 CloudBehaviour holds the full state of your game, such as every player's hand in a card game. You usually don't want to send all of the state to every player. A `[SyncView]` method defines the tailored view that each player receives. Cloud Code builds each player's view and keeps it up to date automatically.

> **Important:**
>
> A `[SyncView]` method controls which data each player receives. It doesn't restrict who can call your endpoints or change state. For access control, refer to [Multiplayer game security in CloudBehaviours](./secure-multiplayer-game-logic.md).

## Define a per-player view

Mark a method `[SyncView("name")]`. Cloud Code calls the method once per recipient, with that player's ID, and sends the return value as part of that player's state. The Unity Editor also generates a client property named `name` with the method's return type.

The following example defines a per-player view of a card hand:

```csharp title="A per-player view of a card hand"
[StateScope(Scope.MultiplayerSession)]
public class CardGame : CloudBehaviour
{
    // Store every hand. This field persists and stays in the cloud.
    [CloudCodeSerializeProperty]
    private Dictionary<string, List<Card>> _hands = new();

    [SyncView("Hand")]
    internal List<Card> ProjectHand(string playerId) =>
        _hands.TryGetValue(playerId, out var hand) ? hand : new List<Card>();
}
```

The client bindings expose `public List<Card> Hand { get; private set; }`, which holds only that player's cards. The unfiltered dictionary never leaves the cloud.

## Requirements

A `[SyncView]` method has the following requirements:

* The method takes a single `string` parameter, the viewer's player ID, and returns the value that player receives. The method can't return `void`. The return type becomes the type of the generated client property. For example, `List<Card> ProjectHand(string playerId)` generates `List<Card> Hand` on the client.
* The method is synchronous and non-generic.
* The method is `public` or `internal`. A private `[SyncView]` method fails the build with `CCSG142`. A `[SyncView]` method never becomes an RPC, even when it's public.

The build doesn't check the following, but follow them so the view behaves as players expect:

* Name the view after what the method returns, not after the method. For example, use `[SyncView("Hand")]`, not `[SyncView("ProjectHand")]`. The view name becomes the name of the property in the client bindings.
* Don't change state in the method. The method runs once per recipient on every synchronization, so any state change repeats for every player.

## Hide values from other players

Represent a hidden value as empty or absent, not as a stand-in value such as `0`. Otherwise, a player can't tell a hidden value from a real one.

The following example shows a sealed-bid auction, where each player receives only their own bid. A bid of `0` is valid, so a `0` in place of another player's bid looks like a real bid. Leave the other players' bids out instead:

```csharp title="Hiding values by leaving them out"
[StateScope(Scope.MultiplayerSession)]
public class AuctionGame : CloudBehaviour
{
    // Store every sealed bid in the cloud only.
    [CloudCodeSerializeProperty]
    private Dictionary<string, int> _bids = new();

    // Leave out other players' bids instead of setting them to 0.
    [SyncView("Bids")]
    internal Dictionary<string, int> ProjectBids(string playerId) =>
        _bids.Where(bid => bid.Key == playerId)
             .ToDictionary(bid => bid.Key, bid => bid.Value);
}
```

## Send player-specific data to one player

A per-player view applies to synchronized state only. An event always pushes to everyone in the scope. To send player-specific data to one player, use `Push.SendPlayerMessageAsync` instead of an event. Refer to [Push channels in CloudBehaviours](./push-channels.md).

## Additional resources

* [Turn-based game workflow](./turn-based-game-workflow.md)
* [Synchronized state in CloudBehaviours](./synchronized-state.md)
* [Multiplayer game security in CloudBehaviours](./secure-multiplayer-game-logic.md)
