---
title: RPCs 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/rpcs
latest_url: https://docs.unity.com/en-us/cloud-code/3.0.0/cloudbehaviours/rpcs.md
last_updated: 2026-10-23
generated_at: 2026-11-04T11:39:24.398Z
locale: en-us
---

# RPCs in CloudBehaviours

> Declare a remote procedure call (RPC), call it from your game, and inject services into it.

> **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 remote procedure call (RPC) is a public method on a CloudBehaviour that runs in the cloud and that your game calls through the client bindings. The Unity Editor generates a matching method in the client bindings for each RPC. The method body never runs on a player's device, so put validation, secret logic, and anything that awards or spends resources in the method body.

> **Important:**
>
> Every public method in the cloud script is a network endpoint that any client can call, including a malicious one. For guidance on restricting access to an RPC, refer to [Multiplayer game security in CloudBehaviours](./secure-multiplayer-game-logic.md).

## Write a method your game can call

The Editor generates an RPC for each public, non-static, non-generic method on the cloud class. Methods marked `[SyncView]` are the exception, because they define [per-player state views](./per-player-state-views.md) instead. The method can be synchronous or asynchronous (returning `Task` or `Task<T>`), and it can take parameters and return a value.

The following example declares three methods that your game can call, and one private method that stays in the cloud:

```csharp title="Methods your game can call"
[StateScope(Scope.MultiplayerSession)]
public class MatchState : CloudBehaviour
{
    public void EndTurn()
    {
        // Add your turn logic here.
    }

    public int SubmitScore(int score)
    {
        // Add your scoring logic here.
        return score;
    }

    public async Task<string> PlayTurn(string move)
    {
        // Add your move logic here.
        return "ok";
    }

    // Private methods stay in the cloud.
    private void ResetRound()
    {
        // Add your reset logic here.
    }
}
```

Parameters and return values serialize as JSON, so use serializable types, such as primitives, strings, and plain C# classes. Parameters marked `[CloudCodeService]` are the exception. The runtime injects these parameters, so Cloud Code never serializes them, and they don't appear on the client. Refer to [Inject services into an RPC](#inject-services-into-an-rpc).

The Editor generates a data-only copy of concrete classes, structs, and enums that you define in the cloud assembly, with only their public fields and properties. Refer to [Model types crossing the client boundary](./synchronized-state.md#model-types-crossing-the-client-boundary).

The following types cause a compile-time error instead:

* Interfaces and abstract classes, because the runtime can't tell which concrete type to deserialize a value into.
* Types that derive from a .NET type, such as a collection, or from a type injected with `[CloudCodeService]`.
* Custom collection types. Use `List<T>` or an array instead.
* Types with a public property that can be read but not assigned, such as a computed property or a property without a public setter.
* Types declared in another assembly that references the Unity Engine or the Unity Editor, because that assembly can't run in the cloud.

## Call an RPC from your game

The generated client bindings contain an awaitable method for each RPC. Every client-side call is asynchronous, even when the cloud method is synchronous, because each call goes over the network:

```csharp title="Calling RPCs through the client bindings"
public async Task PlayAsync()
{
    var result = await matchStateClient.PlayTurn("rock");
    Debug.Log(result);
}
```

Each RPC response also carries the caller's synchronized state after the method runs. The client bindings apply that state before the call returns, so a client that calls an RPC doesn't need a separate hydration. In a `MultiplayerSession` scope, the other players receive the update as a push instead, unless you [control synchronization manually](./synchronized-state.md#control-synchronization-manually).

## Inject services into an RPC

To use a service inside an RPC, add the service as a parameter marked with `[CloudCodeService]`. For example, inject the generated interface to schedule a timer or call another CloudBehaviour. The runtime injects the service, and the Editor removes the parameter from the generated client method:

```csharp title="Injecting a service into an RPC"
[StateScope(Scope.MultiplayerSession)]
public class MatchState : CloudBehaviour
{
    public async Task StartTurn([CloudCodeService] IMatchState self)
    {
        await self.OnTurnTimeout().ScheduleAsync(TimeSpan.FromSeconds(30));
    }

    [CloudCodeAccess(Access.Service)]
    public void OnTurnTimeout()
    {
        // Add your timeout logic here.
    }
}
```

The generated client `StartTurn` method has no `self` parameter.

### Register the generated interface

A generated `I{Behaviour}` interface resolves only if your module registers it. In the module's `ICloudCodeSetup`, call the generated `Add{Behaviour}Client()` extension method for each CloudBehaviour interface you inject:

```csharp title="Registering the generated interface"
using Unity.Services.CloudCode.Core;

public class ModuleSetup : ICloudCodeSetup
{
    public void Setup(ICloudCodeConfig config)
    {
        config.AddMatchStateClient();
    }
}
```

If you inject an `I{Behaviour}` interface without registering it, the build fails with a generator error that names the missing `Add{Behaviour}Client()` call.

> **Note:**
>
> Mark every injected service parameter with `[CloudCodeService]`. If an injected service or a generated `I{Behaviour}` interface parameter is missing the attribute, the build fails with `CCSG136`.

For the full timer scheduling pattern, refer to [Timers in CloudBehaviours](./timers.md). To call another CloudBehaviour's endpoint, refer to [Cross-behaviour calls in CloudBehaviours](./calling-another-behaviour.md).

## Additional resources

* [Get started with CloudBehaviours](./get-started.md)
* [Turn-based game workflow](./turn-based-game-workflow.md)
* [Access control in CloudBehaviours](./access-control.md)
