Programming & Scripting Errors

Steamworks Callbacks Not Firing in Unity Editor - Run in Background and Pump Timing Fix

Fix Steamworks callbacks that never arrive in the Unity Editor by enabling Run in Background, pumping SteamAPI_RunCallbacks every frame, fixing init order, and separating editor versus player test expectations.

By GamineAI Team

Steamworks can initialize successfully while callbacks still never reach your game. In the Unity Editor this often looks like achievements that never toast, lobby invites that never arrive, or overlay messages that never trigger handlers, even though SteamAPI_Init returned true.

This article assumes native load and steam_appid.txt are already plausible. If initialization itself fails, start with Steamworks Init Failed in Unity Editor. If unlocks fail in packaged builds specifically, pair this guide with Steam Achievements Not Unlocking in Unity Build.

Problem summary

Typical symptoms

  • You register callbacks (Steamworks.NET, Facepunch.Steamworks, or raw SteamAPI_RegisterCallback) and never see handlers fire in Play Mode.
  • The Steam client is running, Init succeeds, remote actions happen on another account, but your local session stays silent.
  • Behavior improves when you alt-tab back into the Editor or click the Game view.

When it shows up

  • After integrating Steamworks and focusing tests on standalone builds, while Editor testing is an afterthought.
  • When SteamAPI_RunCallbacks is only called from FixedUpdate or from a slow coroutine.
  • When Run In Background is disabled and the Editor loses focus during multiplayer or remote tests.

Impact

  • False negatives in Editor QA, so bugs slip to builds or live.
  • Teams rewrite networking or UI code when the real issue is pump timing.

Why this happens

Steam’s API is pull-driven for many notifications. If your process does not call SteamAPI_RunCallbacks regularly, pending work queues up and your delegates never run.

Common root causes in Unity:

  1. Callbacks not pumped every frame
    RunCallbacks is missing, behind a try that swallows errors, or only runs when certain scenes load.

  2. Editor focus freezes the player loop
    With Run In Background off, switching to Visual Studio, Slack, or a browser pauses Play Mode. Callbacks stop pumping even though Steam is still generating events.

  3. Init order
    Callback objects are created before SteamAPI_Init, or are destroyed during domain reload while Steam still references stale handles.

  4. Wrapper-specific expectations
    Some wrappers batch work and still require periodic RunCallbacks or their own Update hook. Skipping that hook looks like “Steam is broken”.

Fix steps (do them in order)

Step 1 - Enable Run In Background

In Unity: Edit → Project Settings → Player → Resolution and Presentation → Run In Background. Enable it for the configuration you use in Play Mode (PC, Mac, Linux standalone settings still affect Editor behavior for this flag in many Unity versions).

Re-test the exact scenario where callbacks failed while you were not focused on the Game view.

Step 2 - Pump callbacks on the main thread every frame

Add a small bootstrap component that runs in Update (not only FixedUpdate):

  1. Guard with your wrapper’s “initialized” check.
  2. Call SteamAPI_RunCallbacks exactly once per frame on the main thread.
  3. Log once per session (not spammy) the first time RunCallbacks runs after init so you can confirm order in the Console.

If you use Steamworks.NET, follow its documented CallbackManager.RunCallbacks pattern in Update. If you use Facepunch.Steamworks, follow its Update hook guidance for the version you pinned. The invariant is the same: steady pump, main thread.

Step 3 - Initialize once, before registering long-lived callbacks

Order should look like:

  1. Create or verify steam_appid.txt for editor tests (see init article).
  2. Call Init and confirm success.
  3. Register callbacks and achievement/stats interfaces.
  4. Start pumping.

If you register first, some wrappers appear fine until the first remote event exposes undefined ordering.

Step 4 - Survive domain reload and re-enter Play Mode

If you use Enter Play Mode Options without domain reload, static callback holders can survive in a bad state.

Pick one policy:

  • Full domain reload for Steam-heavy scenes while iterating, or
  • Explicit Shutdown on play mode exit and re-Init on next enter, documented in your bootstrap.

Add RuntimeInitializeOnLoadMethod or EditorApplication.playModeStateChanged hooks only if you understand double-init risk. The default safe path for small teams is quit Play Mode fully between Steam config changes.

Step 5 - Confirm you are not testing impossible editor paths

Some interfaces are build-only or behave differently in Editor. When a callback never fires, verify in Steam’s partner documentation whether that interface is supported in development contexts. Link your expectations in QA docs so Editor skips do not get misfiled as code bugs.

Verification checklist

  • With Run In Background enabled, unfocus the Editor for thirty seconds while a remote friend triggers an action that should notify you. Callbacks still arrive.
  • Console shows your one-time “pump started after init” log in the correct order.
  • After ten minutes of idle gameplay, trigger another callback event. Still works (catches throttled Update removals).
  • Standalone Development build still receives callbacks (guards against Editor-only false positives).

Alternative causes to scan quickly

  • Editor vs build define symbols accidentally excluding your pump script in Editor.
  • Multiple bootstrap objects calling Init or RunCallbacks twice per frame (rare, but causes hard-to-read races).
  • Exception inside a callback stopping subsequent pumps if your wrapper disables itself on error.

Prevention tips

  • Keep a single SteamBootstrap MonoBehaviour responsible for Init, pump, and shutdown.
  • Add a lightweight Editor window debug readout showing last pump time and last callback category (no secrets).
  • Document for QA: “Editor tests require Run In Background on” next to your Steam test matrix.

FAQ

Should RunCallbacks run in LateUpdate instead of Update?
Either is acceptable if it is once per frame and main-thread. Update is the most common choice so gameplay reads Steam state before this frame’s simulation.

Does IL2CPP change Editor pumping?
Editor uses Mono; IL2CPP matters for builds. Still verify a Development build because stripping or link steps can remove a pump script if referenced only weakly.

Is a zero-length interval coroutine enough?
Prefer Update. Coroutines can be delayed by time scale, disabled objects, or scene pauses.

Related links

Bookmark this page if your team repeatedly blames “Steam delay” when the Editor simply stopped pumping while you were reading logs in another window.