Skip to content

Blueprint Custom Events as RPCs

A replicated Custom Event is not "calling a function on another computer." It is sending a one-way network message through a replicated actor or actor component, then letting the receiving machine run that event locally.

The one-minute version

  • In Blueprint, an RPC is usually a Custom Event whose Details panel Replicates setting is changed to Run on Server, Run on Owning Client, or Multicast.
  • The actor must be a replicated actor. For component RPCs, the owning actor must replicate and the component must be set up for networking too.
  • RPCs are one-way. They do not return a value across the network. Send inputs with the event, then send the result back through replicated state, RepNotify, or a separate client RPC.
  • A client can call Run on Server only from an actor that is owned by that client's connection. A placed door, pickup, or enemy is usually not owned by the client touching it.
  • Reliable means "keep resending until acknowledged." It does not mean "free," "instant," or "safe to call every frame."
  • Use RPCs for requests and transient events. Use replicated variables for durable state that late clients, relevancy changes, and UI can read later.

What an RPC actually is

A normal Custom Event runs where it is called. A replicated Custom Event asks Unreal's networking layer to deliver the call to a different machine, according to the event's replication mode and the actor's ownership.

At beginner altitude, the pipeline looks like this:

pseudocode of the relationship - not engine source

Blueprint calls CustomEvent_ServerFire on BP_PlayerCharacter
-> Unreal checks whether this actor/component is allowed to send that RPC
-> the call is serialized into network data for the right connection
-> the receiving machine executes CustomEvent_ServerFire in its local copy
-> the event graph after that node runs on the receiving machine

The event did not run "inside the other player's Blueprint." It ran on that machine's local copy of the replicated actor. That distinction matters because each world has its own objects, widgets, cameras, and component instances.

How a Custom Event becomes an RPC

For a Blueprint actor:

Class defaults:
-> Replicates = true

Event Graph:
-> Add Custom Event, for example ServerTryInteract
-> select the Custom Event node
-> Details panel -> Graph -> Replicates:
      Not Replicated
      Run on Server
      Run on Owning Client
      Multicast
-> optionally check Reliable
-> add input parameters the receiver needs

Then call the event like any other Blueprint event. The same node name appears in your graph; the replication setting changes where the event is allowed to execute.

Use names that say where the event is meant to run:

Prefix Example Meaning
Server ServerTryInteract(TargetActor) A client request that the server validates.
Client ClientShowHitMarker() Server tells one owning client to do local presentation.
Multicast MulticastPlayImpactFX(Location, Surface) Server tells relevant clients about a transient event.

The prefix is only a naming convention, but it saves real debugging time. A node called FireWeapon gives no clue which machine should run it.

The three Blueprint RPC modes

Mode Who should usually call it Where it executes Beginner use
Run on Server Owning client, or the server itself Server copy of that actor "I pressed Interact/Fire/Ready. Please validate and change authoritative state."
Run on Owning Client Server The client connection that owns this actor "Show this private UI/camera/audio result to that one player."
Multicast Server Server and clients for which the actor is relevant "Play a short cosmetic event for everyone currently seeing this actor."

Blueprint does not expose the newer C++ Remote RPC mode. For Blueprint beginners, the practical set is Server, Owning Client, and Multicast.

Ownership: why the Server RPC silently does nothing

The classic bug:

Client overlaps BP_Door
-> client calls BP_Door.ServerOpenDoor
-> nothing happens on the server

The door is replicated, but the door is not owned by that client. The client does not get to send Server RPCs through every actor it can see. The client can normally send Server RPCs through its own PlayerController, possessed Pawn, or another replicated actor whose Owner chain resolves to that player's connection.

Use an owned path:

Client presses Interact on owned PlayerController or Pawn
-> Run on Server: ServerTryInteract(TargetActor)
-> server validates target distance, line of sight, state, and permission
-> server calls a normal function/interface on BP_Door
-> server changes replicated door state
-> clients receive the result

That shape keeps the request on an owned actor and the authority on the server. It also avoids making every world object owned by whoever last touched it.

What counts as an owned path?

Actor Can this client's Server RPC usually go through it? Why
This client's PlayerController Yes It is the connection's control object.
This client's possessed Pawn / Character Yes It is owned through the player's controller.
Another player's pawn No That pawn belongs to a different connection.
A placed door, pickup, enemy, or objective actor Usually no World actors are normally server-owned or unowned.
A weapon/equipment actor Maybe Only if it replicates and its Owner is set to the owning player path.
A widget No Widgets are local UI and are not replicated actors.

Set Owner can matter for networking, but do not use it as a random fix. Set ownership when the actor is genuinely associated with a player's connection, such as that player's inventory item or equipped weapon. A shared door should usually stay server-owned and receive requests through the player's owned actor.

No return values: design it as a message

An RPC is asynchronous network communication. By the time the server receives a client request, validates it, changes state, and sends results back, the original Blueprint call has already continued locally. A return pin would pretend that the answer exists immediately on the caller, so Unreal does not offer one.

Use this instead:

Client:
    call ServerTryBuyItem(ItemId)
    optionally show "pending" presentation

Server RPC:
    validate money, inventory space, and item definition
    if accepted:
        change replicated Money and Inventory
    else:
        call ClientShowBuyFailed(Reason)

Clients:
    RepNotify / UI refresh reacts when replicated values arrive

The request is an RPC. The durable result is replicated state. A private error message can be a Run on Owning Client RPC.

Reliable vs unreliable

Reliable RPCs are resent until the receiver acknowledges them. They also carry ordering consequences: a backed-up reliable stream can delay later reliable traffic. This is why "Reliable" should feel like a budget, not a default.

Use Reliable for low-frequency requests or notifications that must arrive for the feature to make sense:

  • player confirms ready;
  • player presses a menu purchase button;
  • server tells the owning client that a match invite was accepted;
  • one-time ability activation request, after client-side rate limiting.

Prefer Unreliable for frequent or disposable events:

  • aim updates every tick;
  • repeated cosmetic impact pings;
  • footstep/muzzle/audio spam where the next update matters more than the old one;
  • anything called from Tick or a held input without a rate limit.

Reliable is not validation. The server still needs to check distance, cooldown, ammo, authority, item ownership, and any other gameplay rule before trusting a client request.

Patterns that work

Interacting with a door

Owned pawn/controller:
    Input Interact
    -> line trace locally for responsiveness
    -> ServerTryInteract(HitActor)

ServerTryInteract:
    validate HitActor is still interactable and close enough
    call interface Interact on HitActor

Door on server:
    set bOpen = true (RepNotify)

Clients:
    OnRep_Open plays the door timeline locally

Firing a replicated projectile

Client:
    Input Fire
    -> play local muzzle flash/camera shake if desired
    -> ServerFire(AimTransform)

ServerFire:
    validate cooldown, ammo, weapon, aim origin
    spawn replicated projectile
    decrement replicated ammo

Clients:
    receive projectile and ammo updates

Private client feedback

Server:
    player took confirmed damage
    -> reduce replicated Health
    -> ClientShowDamageIndicator(Direction)

Owning client:
    ClientShowDamageIndicator
    -> local widget/camera/audio feedback

The health belongs in replicated state. The screen indicator belongs to the owning client's local presentation.

When it fails, and what failure looks like

Most Blueprint RPC failures do not give you a dramatic crash. The event simply does not execute on the machine you expected.

Common causes:

  1. The actor does not replicate. The event is marked as an RPC, but there is no network actor path to carry it.
  2. The component path is not network-ready. The actor replicates, but the component with the event is not configured for replicated component behavior.
  3. The client does not own the actor. Server RPCs from unowned actors are dropped.
  4. You called a Client RPC from a client and expected the server to send it. Client RPCs are normally server-to-owning-client messages.
  5. You called Multicast from a client. It runs locally on that client instead of reaching everyone.
  6. The actor is not relevant to a client. Server multicast reaches relevant clients for that actor, not a guaranteed global audience forever.
  7. The event is reliable but spammed. The reliable queue can become a new problem instead of fixing packet loss.

Print from inside the event with the actor name and net mode. If the print does not appear on the expected machine, debug ownership and authority before debugging the gameplay logic inside the event.

Lookalikes - which one do I want?

Tool Use when Not for
Run on Server RPC Owning client asks the server to do authoritative work. Getting an immediate return value or bypassing validation.
Run on Owning Client RPC Server tells one player to show private local presentation. Public state everyone needs to know.
Multicast RPC Server sends a transient event to relevant clients now. Durable state, late joiners, or anything that must be reconstructable later.
Replicated variable Clients need the current value. One-time cosmetic pulses with no lasting state.
RepNotify Clients should run local presentation when a replicated value arrives. Client-to-server requests.
Blueprint Interface You need a local contract between objects in the same world. Crossing the network by itself.
Event Dispatcher One local object broadcasts to local listeners. Replicating an event to another machine.

The quick path is to make every multiplayer action a Multicast because "all players should see it." The concrete cost is that state becomes a pile of one-time events: late joiners, relevancy changes, dropped unreliable calls, and UI refreshes have nothing durable to read. Replicate the state first; use RPCs for requests or transient presentation.

Going deeper