Rich Presence
Set a player’s current activity (e.g. “Playing Level 5”, “Browsing Shop”) and the SDK syncs it to two places:
- Live Activity dashboard — see who’s playing what right now, in real-time over WebSocket
- Steam Rich Presence — surface activity strings on the player’s Steam profile and friends list
Functions
Section titled “Functions”set_activity()
Section titled “set_activity()”QuestData.set_activity(activity: String, details: Dictionary = {})| Parameter | Type | Default | Description |
|---|---|---|---|
activity | String | required | Activity identifier (e.g. "in_level", "in_shop", "boss_fight") |
details | Dictionary | {} | Free-form context (level, character, boss, score, …) |
The activity is buffered locally and synced to the server every 5 seconds if it has changed. Setting the same activity repeatedly does nothing — only changes are pushed.
clear_activity()
Section titled “clear_activity()”QuestData.clear_activity()Marks the player as no longer in any activity. Call when returning to the title screen, on app pause, or before quit. Clears immediately without waiting for the 5s timer.
get_activity()
Section titled “get_activity()”QuestData.get_activity() -> DictionaryReturns the current activity dictionary (copy). Useful for showing the same string in your own in-game UI.
get_steam_presence_string()
Section titled “get_steam_presence_string()”QuestData.get_steam_presence_string() -> StringReturns a human-readable string suitable for Steam.setRichPresence("steam_display", ...) (with the GodotSteam addon). Built-in mappings:
| Activity | Output |
|---|---|
in_level (with level/level_name detail) | "Playing Level <X>" |
in_shop | "Browsing Shop" |
in_menu | "In Menu" |
boss_fight (with boss_name detail) | "Fighting <Boss>" |
| other | activity capitalized, underscores → spaces |
| empty | "In Menu" |
format_presence()
Section titled “format_presence()”QuestData.format_presence(template: String) -> StringCustom templating. {activity} and any {key} from the details dictionary are interpolated.
QuestData.set_activity("in_level", {"level": 5, "deaths": 3})QuestData.format_presence("Lvl {level} — died {deaths}×")# → "Lvl 5 — died 3×"Example
Section titled “Example”# When a level loadsfunc _on_level_started(level_id: int): QuestData.set_activity("in_level", { "level": level_id, "character": player.class_name, "difficulty": GameSettings.difficulty })
# Boss arenafunc _on_boss_intro(boss_id: String, boss_name: String): QuestData.set_activity("boss_fight", { "boss_id": boss_id, "boss_name": boss_name, "level": current_level })
# Title screen / menusfunc _on_returned_to_menu(): QuestData.clear_activity()
# Quit cleanupfunc _notification(what): if what == NOTIFICATION_WM_CLOSE_REQUEST: QuestData.clear_activity()Steam Integration
Section titled “Steam Integration”# Sync to Steam every time activity changesfunc _on_activity_changed(): if OS.has_feature("steam"): Steam.setRichPresence("steam_display", QuestData.get_steam_presence_string()) Steam.setRichPresence("status", QuestData.format_presence("{activity}"))You don’t need GodotSteam to use Rich Presence — set_activity() works standalone for the Live Activity dashboard. Steam is a downstream consumer.
How It Works
Section titled “How It Works”set_activity()writes to a local buffer and marks the state dirty- Every 5 seconds, the SDK checks the dirty flag and POSTs
{activity, details}to/v1/players/activityif changed clear_activity()POSTs immediately with an empty payload- The dashboard’s Live Activity page subscribes via WebSocket and renders changes in real-time
- No timer fires when the activity is unchanged — zero overhead at idle
Limits
Section titled “Limits”| Limit | Value |
|---|---|
| Sync interval | 5 seconds (only on change) |
activity length | 64 chars |
details size | 1 KB JSON |
Best Practices
Section titled “Best Practices”- Keep activity names stable —
"in_level"not"playing_level_5"(put5in details). This keeps the Live Activity dashboard countable per state. - Always clear on quit — otherwise the player looks “in_level” forever in the dashboard until the session timeout sweeps them out.
- Don’t hammer it — calling
set_activity()every frame is fine (changes are deduped) but it’s still cleaner to call it on actual transitions. - Match Steam’s display rules — Steam displays max ~64 chars and rejects rapid updates. Use the built-in mappings unless you need a specific format.