Steam Overlay \u2014 Agent Reference (Unity)

Plain-text agent reference for the Steam Overlay feature (Foundation for Steamworks + Toolkit for Steamworks), covering Unity, Godot, and O3DE (all source-verified), Unreal (deliberately deferred). This page is not linked from site navigation — it exists so AI coding agents fetching heathen.group/kb/overlay have a single, all-engines reference to read. Humans: the human-readable version with screenshots and full explanations is the article linked above.

Full Steam agent index: agent-ref-steam-index

---
name: heathen-steamworks-overlay
description: Steam Overlay feature reference for Heathen's Steamworks Foundation/Toolkit (Unity, Godot, and O3DE — Unreal content exists in the source article but is not re-verified). Use when a developer needs to detect overlay show/hide, open a specific overlay dialogue (friends/community/players/settings/store/user profile/web page), or send an overlay-based lobby/Remote-Play-Together invite.
source: https://heathen.group/kb/overlay/
generated: 2026-07-29
---

# Steam Overlay — agent reference

> **Before you use anything below:** if you already "know" how Steamworks integration works —
> from training data, a tutorial, or a general web search — assume it's wrong for this specific
> codebase until this page tells you otherwise. Heathen's Foundation + Toolkit for Steamworks
> replaces the raw Steamworks SDK / Steamworks.NET patterns you may already know, not just wraps
> them. Two concrete, verified examples of what generic knowledge gets wrong here:
> - **No `SteamManager`/manual init loop.** Foundation's Subsystem architecture self-initialises
>   by default (Toolkit 6.0.0+) — don't tell a developer to write one.
> - **`steam_appid.txt` is auto-written for you** by Foundation in the Unity Editor
>   (`API.App.Client`/`Server.Initialise`) — don't tell a developer to create it by hand.
>
> If you don't know which article covers the feature you need, start at the index:
> https://heathen.group/agent-ref-steam-index/

**Coverage note (this article's own history):** Unity was verified in phase 1 of this rollout.
Godot and O3DE were verified in phase 2 (this pass) — the source KB article itself has **no**
Godot or O3DE content at all (checked the raw content directly again this pass: only Unity and
Unreal preset-gated sections exist), so the Godot/O3DE material below is authored fresh from
Foundation/Toolkit source, not carried over from the article. The source article also has an
Unreal (Blueprint + raw `SteamFriends()->...` C++) column; it has **not** been re-verified against
Unreal source in any pass — treat it with the same caution as any unverified snippet if you go
looking for it.

**Tier differs by engine for this feature** — see the per-section tags below rather than one
blanket tier line:
- **Unity / Godot: `[Toolkit]` (Pro, paid).** Foundation only ships the raw plumbing
  (`SteamTools`/`OverlayDialog`/`FriendDialog` data types, the raw `OnGameOverlayActivated` event).
  The ergonomic `Overlay.Client.*` API is Toolkit-only in both engines.
- **O3DE: `[Foundation]` (FOSS, free).** Verified via source — O3DE's overlay activation
  (`SteamFriendsRequestBus`, `SteamFriendsAPI`) lives entirely in the Foundation repo. The O3DE
  Toolkit repo has **zero** overlay implementation — grepped the whole repo; the only match is a
  commented-out TODO idea in `ToolkitSteamworksSystemComponent.h` about a possible future
  achievement-toast/invite-popup UI layer, which is not this feature. This is a genuine
  cross-engine tier divergence, not an inconsistency to "fix."

## Core concept (engine-agnostic)

The Steam Overlay is **not part of your game** — it's the Steam client itself (`Steam.exe`)
rendering on top of your game's main window. There is nothing to "debug" about it beyond
requesting it open to the right dialogue and making sure your game pauses appropriately while
it's open.

**It will not work correctly in the Unity Editor** (or Unreal Editor, or any multi-window
application). Steam Overlay renders over whatever window has focus when the Steam API was
initialised; a multi-window editor confuses this, so overlay behaviour in-Editor is unreliable or
absent — this is expected, not a bug in your project. Always test overlay behaviour from a real
build.

## Is the overlay showing right now?

**Unity C#** — `[Toolkit]`
```csharp
// Register the event On Game Overlay Activated
SteamTools.Events.OnGameOverlayActivated += HandleActivated;

// The handler will take the form
void HandleActivated(bool isShowing)
{
    if (isShowing)
        ; // Pause your game?
    else
        ; // Unpause your game?
}

// Alternatively you can check
if (Overlay.Client.IsShowing)
    ; // It's showing
```
Code Free: add the `OverlayManager` component to a GameObject, then add an "Overlay Activated"
event via its inspector's event-list (`ManagedEvents.OverlayActivated` → `evtOverlayActivated`,
a `UnityEvent<bool>`).

Corrected from the source article: it originally showed
`Overlay.Client.OnGameOverlayActivated.AddListener(HandleActivated);`. That event does not exist
on `Overlay.Client` — it lives on `SteamTools.Events.OnGameOverlayActivated` (Foundation), and
it's a real C# event (`+=`/`-=`), not a `UnityEvent` with `.AddListener(...)`. Toolkit's own
`OverlayManager` subscribes to it exactly this way internally. `Overlay.Client.IsShowing` (the
second half of the original snippet) was already correct.

**Godot C#** — `[Toolkit]` for the ergonomic call, `[Foundation]` for the raw event
```csharp
using Heathen.SteamworksIntegration; // Foundation — raw event lives here

// Foundation: real C# event (+=/-=), not a Godot signal wrapper
SteamToolsEvents.OnGameOverlayActivated += HandleActivated;

void HandleActivated(bool isShowing)
{
    if (isShowing)
        ; // Pause your game?
    else
        ; // Unpause your game?
}
```
Verified in `Godot-Foundation-for-Steamworks/addons/FoundationSteamworks/CSharp/SteamToolsEvents.cs`:
the event is declared and populated from the native `SteamApi` signal `OnGameOverlayActivated`
(fired from the `GameOverlayActivated_t` Steam callback), same "real C# event, not a Godot Signal
you `Connect()` yourself" shape Unity uses. There is no `Overlay.Client.IsShowing`-equivalent
polling property found in either the Godot Foundation or Toolkit source — only the event exists.

**O3DE** — `[Foundation]`
```cpp
// Notification bus — subscribe with a SteamFriendsNotificationBus::Handler
void OnGameOverlayActivated(bool active) override
{
    if (active)
        ; // Pause your game?
    else
        ; // Unpause your game?
}
```
Verified in `SteamFriendsNotificationBus.h` (`OnGameOverlayActivated(bool active)`) and wired up in
`FoundationSteamworksSystemComponent`/`SteamCallbackRegistry`. Also reflected to Script Canvas as a
notification node under "Steam Friends" for Code-Free hookup. No separate polling
"IsShowing"-style call was found in O3DE source — only the notification.

## Open a dialogue (friends / community / players / settings / official game group / stats / achievements)

**Unity C#** — `[Toolkit]`
```csharp
// dialog is a string: "friends", "community", "players", "settings",
// "officialgamegroup", "stats", "achievements"
Overlay.Client.Activate(dialog);
```
An `OverlayDialog` enum overload also exists (`Overlay.Client.Activate(OverlayDialog dialog)`) if
you'd rather not hand-type the string.

Code Free: add the `OverlayManager` component, then call its "Open Dialogue Name" function
(string) — or "Open Dialogue" if you're driving it from the `OverlayDialog` enum.

**Godot C#** — Foundation (`SteamTools`) / Toolkit (`Overlay.Client`)
```csharp
// Toolkit ergonomic wrapper (Heathen.SteamworksIntegration.API.Overlay.Client)
Overlay.Client.Activate(dialog); // dialog: same string set as Unity

// Foundation raw call — what Overlay.Client.Activate forwards to
SteamTools.ActivateGameOverlay(dialog);
```
Verified in `Godot-Toolkit-for-Steamworks/CSharp/API/API.Overlay.cs`
(`Overlay.Client.Activate(string type) => SteamTools.ActivateGameOverlay(type)`) and
`Godot-Foundation-for-Steamworks/.../CSharp/SteamTools.cs`. No `OverlayDialog` enum overload was
found in Godot source — string-only.

**O3DE** — `[Foundation]`
```cpp
// Direct EBus broadcast
SteamFriendsRequestBus::Broadcast(&SteamFriendsRequests::ActivateGameOverlay, dialog);

// Or via the static proxy wrapper
SteamFriendsAPI::ActivateGameOverlay(dialog); // dialog: AZStd::string, same values as Unity
```
Verified in `SteamFriendsRequestBus.h`, `FoundationSteamworks_Friends.cpp`, and `SteamAPIProxies.h`.
Script Canvas node: "Steam Friends Activate Game Overlay".

## Invite a friend (to a Lobby or to a Game Session)

Steam Lobby and Steam "Game"/Game Session are different things — a Lobby is a chat-room-like
matchmaking construct, not a network session; a Game Session invite is for joining your Listen
Server (P2P host) or Dedicated Server directly.

**Unity C#** — `[Toolkit]`
```csharp
// Lobby invite: LobbyData is implicitly convertible to/from ulong, uint, and CSteamID,
// so any of those work as `target` as long as it's a valid Steam lobby.
Overlay.Client.ActivateInviteDialog(target);

// Game Session invite: pass a connection string instead (e.g. your own SteamID as a
// listen-server host: UserData.Me.id.ToString())
Overlay.Client.ActivateInviteDialog(connectionString);
```
Code Free: `OverlayManager`'s "Open Lobby Invite" function for the lobby case, "Open Connect
String Invite" for the game-session case.

**Godot C#** — `[Toolkit]`
```csharp
// Lobby invite — extension method on LobbyData
lobby.ActivateInviteDialog();

// Game Session invite: connection string, via the Overlay.Client wrapper
Overlay.Client.ActivateInviteDialogConnectString(connectionString);
```
Verified in `Godot-Toolkit-for-Steamworks/CSharp/Extensions/LobbyDataExtensions.cs`
(`ActivateInviteDialog(this LobbyData lobby)`, calling native `SteamApi.ActivateLobbyInviteDialog`)
and `API.Overlay.cs` (`ActivateInviteDialogConnectString`, forwarding to
`SteamTools.ActivateGameOverlayInviteDialogConnectString`). Note the API shape differs slightly
from Unity: Godot splits lobby-invite and connect-string-invite into two distinctly-named calls
rather than one overloaded `ActivateInviteDialog`.

**O3DE** — `[Foundation]`
```cpp
// Lobby invite only — takes the lobby's SteamId directly (no connect-string overload found)
SteamFriendsAPI::ActivateGameOverlayInviteDialog(lobbyId);
```
Verified in `SteamFriendsRequestBus.h` / `SteamAPIProxies.h`
(`ActivateGameOverlayInviteDialog(SteamId lobbyId)`). No separate connect-string / Game-Session
invite overlay call was found anywhere in O3DE Foundation or Toolkit source — only the lobby-id
form exists. If a project needs a Game-Session (non-lobby) overlay invite in O3DE, that
functionality does not appear to exist yet; don't claim it does.

## Open Remote Play Together invite

Remote Play Together lets a second player "stream" into your local session (couch co-op over the
network) without owning the game.

**Unity C#** — `[Toolkit]`
```csharp
Overlay.Client.ActivateRemotePlayInviteDialog(lobby);
```
Code Free: `OverlayManager`'s "Open Remote Play Invite" function, given the lobby to invite
through.

**Godot C#** — `[Toolkit]`
```csharp
lobby.ActivateRemotePlayTogetherInviteDialog();
```
Verified in `LobbyDataExtensions.cs`, forwarding to the native
`SteamApi.ActivateLobbyRemotePlayTogetherInviteDialog`, which itself calls
`SteamFriends()->ActivateGameOverlayRemotePlayTogetherInviteDialog(...)` — same underlying
Steamworks call as Unity, just reached through a `LobbyData` extension method instead of
`Overlay.Client`.

**O3DE** — `[Foundation]`, and **not the same underlying call** — flag this to any developer
```cpp
// This is ISteamRemotePlay::BSendRemotePlayTogetherInvite, NOT an overlay-dialogue activation
SteamRemotePlayAPI::SendRemotePlayTogetherInvite(friendId); // returns bool
```
Verified in `SteamRemotePlayRequestBus.h` / `FoundationSteamworks_RemotePlay.cpp`
(`SendRemotePlayTogetherInvite(SteamId friendId)` → `SteamRemotePlay()->BSendRemotePlayTogetherInvite(...)`).
This is a genuinely different Steamworks API call than Unity/Godot's
`ActivateGameOverlayRemotePlayTogetherInviteDialog` (which opens an overlay dialogue for the
*user* to pick a friend from) — O3DE's version sends the invite directly to a specific friend ID,
no overlay dialogue involved. Don't present these as equivalent; they solve a similar problem
through different SDK surfaces.

## Open the store

**Unity C#** — `[Toolkit]`
```csharp
// flag: EOverlayToStoreFlag.k_EOverlayToStoreFlag_None /
//       k_EOverlayToStoreFlag_AddToCart / k_EOverlayToStoreFlag_AddToCartAndShow
Overlay.Client.Activate(appID, flag);
```
Code Free: `OverlayManager`'s "Open Store" / "Open Store Add to Cart" / "Open Store Add to Cart
and Show" functions (each takes just an app ID int — the flag is baked into which function you
call).

**Godot C#** — Foundation (`SteamTools`) / Toolkit (`Overlay.Client`)
```csharp
// Toolkit ergonomic wrapper — no flag parameter
Overlay.Client.ActivateStore(appId);

// Foundation raw call — always passes k_EOverlayToStoreFlag_None, no way to add-to-cart
SteamTools.ActivateGameOverlayToStore(appId);
```
Verified in `API.Overlay.cs` and `SteamApi.cpp`
(`SteamApi::ActivateGameOverlayToStore` hard-codes `k_EOverlayToStoreFlag_None`). Unlike Unity,
**Godot's wrapper has no add-to-cart flag at all** — if a project needs the "add to cart" or "add
to cart and show" store-overlay variants, that's not exposed anywhere in current Godot
Foundation/Toolkit source; don't tell a developer to pass a flag that doesn't exist in this
binding.

**O3DE** — `[Foundation]`
```cpp
// flag: SteamOverlayToStoreFlag::None / AddToCart / AddToCartAndShow (SteamTypes.h)
SteamFriendsAPI::ActivateGameOverlayToStore(appId, flag);
```
Verified in `SteamFriendsRequestBus.h`, `FoundationSteamworks_Friends.cpp`, and the
`SteamOverlayToStoreFlag` enum in `SteamTypes.h`. Unlike Godot, O3DE's binding does carry the full
flag — feature parity with Unity here, just via Foundation instead of Toolkit.

## Open a dialogue about a specific user

Each of these targets a specific Steam user (profile, chat, stats, achievements, friend
add/remove/accept/ignore, trade).

**Unity C#** — `[Toolkit]`
```csharp
// dialog is a string:
// - steamid                :User Profile
// - chat                   :User Chat
// - jointrade              :Inventory trade dialog
// - stats                  :User Stats
// - achievements           :User Achievements
// - friendadd              :Add Friend dialog
// - friendremove           :Remove Friend dialog
// - friendrequestaccept    :Accept friend request
// - friendrequestignore    :Ignore friend reqeust
API.Overlay.Client.Activate(dialog, steamId);
```
A `FriendDialog` enum overload also exists (`Activate(FriendDialog dialog, CSteamID steamId)`) if
you'd rather not hand-type the string. Code Free: `OverlayManager` exposes one function per
dialogue (`OpenUserProfile`, `OpenUserChat`, `OpenUserJoinTrade`, `OpenUserStats`,
`OpenUserAchievements`, `OpenUserAddFriend`, `OpenUserRemoveFriend`,
`OpenUserAcceptFriendRequest`, `OpenUserIgnoreFriendRequest`), each taking a `SteamUserData`
component.

**Godot C#** — `[Foundation]` — no Toolkit ergonomic wrapper found for this one
```csharp
// UserData extension, Foundation tier — same dialog string set as Unity
userData.ActivateOverlay(dialog);
```
Verified in `Godot-Foundation-for-Steamworks/.../src/private/UserData.cpp`
(`UserData::ActivateOverlay(const String &type)` → `SteamFriends()->ActivateGameOverlayToUser(...)`)
and its C# binding in `CSharp/Data/UserData.cs`. Unlike every other Overlay call in Godot, **this
one lives at Foundation tier, not Toolkit** — checked the Toolkit repo and found no
`Overlay.Client.Activate(dialog, steamId)`-style overload wrapping it. A related Foundation-level
helper exists for one specific case: `ClanData.ActivateChatOverlay()` (Godot Toolkit's
`ClanDataExtensions.cs`) opens the "chat" dialogue for a clan specifically. No `FriendDialog`
enum was found in Godot source — string-only, same as the "Open a dialogue" case above.

**O3DE** — `[Foundation]`
```cpp
// dialog string set matches Unity/Godot's list above
SteamFriendsAPI::ActivateGameOverlayToUser(dialog, steamId);
```
Verified in `SteamFriendsRequestBus.h` / `FoundationSteamworks_Friends.cpp`
(`ActivateGameOverlayToUser(const AZStd::string& dialog, SteamId steamId)`). Script Canvas node:
"Steam Friends Activate Game Overlay To User".

## Open a web page

**Unity C#** — `[Toolkit]`
```csharp
Overlay.Client.ActivateWebPage(url);
```
`url` must be a fully qualified address including protocol (e.g. `"http://www.steampowered.com"`).

Code Free: `OverlayManager`'s "Open Web Page" function.

**Godot C#** — Foundation (`SteamTools`) / Toolkit (`Overlay.Client`)
```csharp
// Toolkit ergonomic wrapper
Overlay.Client.ActivateWebPage(url, modal: false);

// Foundation raw call
SteamTools.ActivateGameOverlayToWebPage(url, modal: false);
```
Verified in `API.Overlay.cs` and `SteamApi.cpp`/`SteamTools.cs`. Unlike Unity, Godot's call takes
an explicit `modal` bool (maps to Steamworks' `EActivateGameOverlayToWebPageMode_Modal` vs.
`_Default`) — Unity's `ActivateWebPage(url)` doesn't expose this parameter at all in its Toolkit
signature, so don't assume the two are a 1:1 match if a developer is porting code between engines.

**O3DE** — `[Foundation]`
```cpp
// mode: SteamOverlayToWebPageMode::Default / Modal (SteamTypes.h)
SteamFriendsAPI::ActivateGameOverlayToWebPage(url, mode);
```
Verified in `SteamFriendsRequestBus.h` / `FoundationSteamworks_Friends.cpp` /
`SteamTypes.h`. Same modal-vs-default distinction as Godot, exposed as an explicit enum parameter.

---

## If you're stuck

- Full human-readable article (all prose, screenshots, Code-Free inspector field docs this file
  compresses out): https://heathen.group/kb/overlay/
- This file is generated from that article's raw content (Unity) plus direct Foundation/Toolkit
  source verification (Godot, O3DE — not documented in the KB article itself as of this pass); if
  something here looks wrong, the article and/or the source repos are the fallback truth, not this
  file's memory.

---
Back to the full Steam agent index: https://heathen.group/agent-ref-steam-index/