Steamworks SDK 1.65 - Replace IsRunningOnSteamDeck Without Breaking Settings 2026
![]()
If you are searching steamworks sdk 1.65 after Valve's July 24, 2026 release, the useful question is not "what is in the changelog?" - the useful question is a pipeline decision: will removing IsRunningOnSteamDeck() break your graphics defaults, input paths, or QA telemetry, and can you migrate to the new hardware and Proton APIs without hard-coding the next device name into production settings?
Valve's Steamworks SDK 1.65 announcement is the authoritative release note. Godot teams should also read GodotSteam's 4.21 / SDK 1.65 post, which shipped wrapper support a few days later. An announcement is a ceiling. This tutorial is a floor test: one evening, one disposable branch, a migration matrix that separates diagnostics from functional settings, and a rollback-safe receipt.
This article turns the 1.65 list into an S1-S6 keep/hold lab. You will inventory every IsRunningOnSteamDeck call, reclassify each as diagnostic or functional, swap diagnostics to IsRunningOnSteamHardware(), move functional defaults to GetSteamHardwareDefaultConfig() (and capability checks like Big Picture / VR / Proton), decide whether to report performance settings, check Steam Input origins and wrapper readiness, and write steamworks_sdk_1_65_migration_receipt_v1.json. You will not rewrite your whole Steamworks layer tonight.
Non-repetition: this is not Your First Proton 11 Steam Deck Verify Pass, which is a one-evening Proton runtime verify. It is not Steam Machine Verified - what indies should lock, which is a cert-lane readiness guide. This URL owns one intent: migrate SDK 1.65 so device-name branches stop driving settings, without breaking what players already tuned.
| Audience | Start here | Done when |
|---|---|---|
| Beginner / solo indie | Glossary, Monday ritual, S1-S3 | Deck/Machine defaults still apply without IsRunningOnSteamDeck |
| Working developer | S1-S6, wrapper matrix, receipt | Compile + smoke on Deck and desktop; telemetry is opt-in only |
| Company / pipeline lead | CapEx four-liner + hold criteria | Named owner, rollback branch, no silent privacy surprises |
| Creator / QA | Share note + verification tools list | Discord paste replaces "SDK updated, hope it works" |
Time estimate: 90-150 minutes for one game branch. Add 30 minutes if you must bump GodotSteam / Steamworks.NET and re-smoke Editor init.
Default recommendation: keep SDK 1.65 for any title that still calls IsRunningOnSteamDeck() for graphics, UI scale, or input - the API is removed, so staying on 1.64 is a ticking compile break. Hold shipping a live depot until S4-S5 prove your functional settings still resolve on Deck hardware and under Proton, and until privacy review signs off on any new performance reporting.
What SDK 1.65 actually changed
Strip the secondary-blog paraphrases and keep Valve's functional intent.
Steam Machine, Steam Frame, and Steam Deck
- Removed
ISteamUtils::IsRunningOnSteamDeck(). Do not call it. Do not#ifdefaround it forever. - Added
ISteamUtils::IsRunningOnSteamHardware()→ returnsESteamHardwareType. Valve's guidance: use this for analytics, support, or diagnostic purposes. For functional decisions, use other SDK calls. - Added
ISteamUtils::GetSteamHardwareDefaultConfig()to help choose default video (and other) settings tuned for specific Steam hardware - and to let future hardware change those defaults without a recompile. - Added
ISteamUtils::IsRunningUnderProton()to detect the Proton compatibility layer on Linux. - Pre-existing helpers that still matter when replacing Deck checks:
IsSteamInBigPictureMode(),IsSteamRunningInVR(), and other feature-specific utils.
ISteamApps - performance reporting (opt-in data)
- Added
SetGamePerformanceSetting()andSetGameRenderResolution()so a game can report relative performance settings and resolution to Steam. That data is included with anonymous framerate data if the user has opted in to sharing it. Treat this as telemetry you choose to send - not a free always-on sensor.
ISteamUGC
- New query/rank options:
k_EUGCQuery_RankedByNumParentItemsandk_EUGCRankedByNumParentCollections(descending order by dependents / collections). Metadata max also moved (GodotSteam notes 10,000).
Steam Input
- New action origin enum values for Switch 2, Steam Controller, and Steam Frame Controller.
ISteamMatchmakingServers
ServerFriends()- friends who recently played a specific server."popularamongfriends"filter - servers friends commonly play on.
The two lines a pipeline lead must read twice: device-name checks are for diagnostics, and default configs are for settings. Mixing them is how you ship "Steam Machine looks like Deck Ultra" bugs six months from now.
The diagnostic vs functional rule (print this)
| Intent | Wrong (1.64 habit) | Right (1.65) |
|---|---|---|
| Crash report / support ticket / analytics dimension | IsRunningOnSteamDeck() |
IsRunningOnSteamHardware() → store ESteamHardwareType |
| First-run graphics preset, UI scale, FSR default, TDP-friendly quality | if (IsRunningOnSteamDeck()) ApplyDeckPreset() |
GetSteamHardwareDefaultConfig() + your tuned preset table; capability checks for Big Picture / VR / Proton when needed |
| "Are we under Proton?" (shader cache, path quirks, crash notes) | Guess from OS alone | IsRunningUnderProton() |
| "Should we show controller glyphs?" | Device name | Steam Input action origins / Big Picture / active controller |
| "Should we send graphics setting telemetry?" | Always | Only with user opt-in path; call SetGamePerformanceSetting / SetGameRenderResolution when you mean to |
If a call changes what the player sees or how the game runs, it is functional. If a call only changes what you log, it is diagnostic. Never collapse those into one bool isDeck.
Monday ritual - inventory, reclassify, smoke, decide
| Minute | Action | Evidence | Keep or hold |
|---|---|---|---|
| 0-15 | Record SDK version, wrapper version, branch name, AppID | Session header in receipt | Hold if you cannot name a rollback tag |
| 15-40 | Grep every IsRunningOnSteamDeck / Deck bool |
Inventory table (S1) | Hold ship if any functional call is unmarked |
| 40-70 | Replace diagnostics with IsRunningOnSteamHardware |
Diff + sample log line | S2 |
| 70-100 | Move settings to GetSteamHardwareDefaultConfig (+ Proton/Big Picture as needed) |
First-run presets on Deck + desktop | S3 |
| 100-120 | Decide performance reporting; wire only if privacy OK | Opt-in note | S4 |
| 120-150 | Wrapper readiness + Input origins + smoke under Proton | Matrix + S5/S6 | Adopt or hold depot |
If you only have 90 minutes, finish S1-S3. A clean settings migration without telemetry is a real ship gate.
Company CapEx four-liner
- Scope - one disposable branch upgrades to SDK 1.65 / matching wrapper; no live depot promote until S5 smoke passes.
- Cost - Steamworks SDK itself is free for partners; cost is engineer time (half day) plus any wrapper bump / CI rebuild. GodotSteam 4.21 already tracks 1.65; Unity Steamworks.NET may lag - budget a wrapper wait if bindings are missing.
- Trap - calling
SetGamePerformanceSetting/SetGameRenderResolutionwithout confirming the anonymous framerate opt-in story, or usingIsRunningOnSteamHardwareto drive graphics (device names return for future hardware you have not tuned). - Owner - one named engineer owns the inventory, the settings matrix, privacy sign-off for telemetry, and the rollback tag.
Prerequisites
- [ ] Partner Steamworks access and a non-shipping branch / AppID test build.
- [ ] Ability to grep the whole repo for
IsRunningOnSteamDeck,SteamDeck,is_deck,bSteamDeck. - [ ] At least one Steam Deck (or Deck-class) device and one desktop Windows build for comparison.
- [ ] Optional but strong: a Proton path (Deck desktop mode / SteamOS) to exercise
IsRunningUnderProton(). - [ ] Wrapper inventory: native C++ Steamworks, GodotSteam version, Steamworks.NET / Facepunch version.
- [ ] Read Valve's release note and, if on Godot, the GodotSteam 4.21 post.
Beginner glossary
IsRunningOnSteamDeck: removed API that returned a boolean for Steam Deck. Do not use it.IsRunningOnSteamHardware: returns an enum of Steam hardware types - for analytics/support/diagnostics, not for "set Ultra because Deck."GetSteamHardwareDefaultConfig: asks Steam for a default configuration hint tuned to the hardware - preferred for first-run settings, including future devices without a rebuild.IsRunningUnderProton: true when the Windows build is running under Proton on Linux.- Diagnostic vs functional: logs vs player-facing behavior. Split them.
- Anonymous framerate data: Steam's opt-in player telemetry channel; 1.65 can attach performance setting + resolution if you report them.
S1-S6 - the migration in detail
S1 - Inventory every Deck branch
Search the codebase and build scripts:
IsRunningOnSteamDeck
SteamUtils()->IsRunningOnSteamDeck
is_steam_deck
IsSteamDeck
STEAM_DECK
bRunningOnDeck
Build a table:
| File:line | Current behavior | Diagnostic or functional? | Replacement candidate |
|---|---|---|---|
GraphicsBootstrap.cpp:88 |
forces "Deck Medium" preset | functional | GetSteamHardwareDefaultConfig + preset map |
CrashReporter.cpp:40 |
adds deck=1 tag |
diagnostic | IsRunningOnSteamHardware |
InputGlyphs.cpp:12 |
swaps to Deck glyphs | functional | Steam Input origins / Big Picture |
Pass S1 when every call is classified. Unclassified calls are automatic hold.
S2 - Move diagnostics to IsRunningOnSteamHardware
For crash reports, support zips, analytics dimensions, and Discord paste for QA:
// Diagnostic only - do not drive graphics from this enum alone
ESteamHardwareType hw = SteamUtils()->IsRunningOnSteamHardware();
crash_fields["steam_hardware"] = SteamHardwareTypeToString(hw);
crash_fields["proton"] = SteamUtils()->IsRunningUnderProton() ? "1" : "0";
crash_fields["big_picture"] = SteamUtils()->IsSteamInBigPictureMode() ? "1" : "0";
Map the enum to a stable string in your code. Do not invent device names Steam has not published in your logging schema without a documented unknown bucket.
Pass S2 when a Deck build and a desktop build both emit a hardware field, and no diagnostic path still calls the removed API.
S3 - Move functional settings to default config + capabilities
Replace first-run and "force Deck preset" logic with:
- Ask
GetSteamHardwareDefaultConfig()for the Steam-provided default hint. - Map that hint to your tuned preset table (Low / Medium / High / Deck-tuned / Machine-tuned).
- Layer capability checks: Big Picture, VR, touch, and
IsRunningUnderProton()only where the capability actually changes behavior (e.g. shader cache paths, not "make it look like Deck"). - Preserve player overrides. First-run defaults must not clobber a user who already set Ultra.
Pseudocode:
if (!UserHasSavedGraphicsProfile()) {
auto cfg = SteamUtils()->GetSteamHardwareDefaultConfig();
ApplyPreset(MapSteamDefaultToOurPreset(cfg));
}
// Never: if (IsRunningOnSteamHardware() == k_ESteamHardwareType_SteamDeck) ApplyDeckUltra();
Pass S3 when:
- Fresh profile on Deck-class hardware lands on your intended preset.
- Fresh profile on desktop does not get the Deck preset.
- An existing saved profile is left alone.
- Future-hardware comment exists in the preset map: unknown configs fall back safely (usually desktop Medium), not to a hard-coded Deck Ultra.
This is the backlink magnet. Changelog blogs stop at "API added." You ship a settings contract.
S4 - Performance reporting (optional, privacy-gated)
If - and only if - your privacy policy and Steam opt-in story allow it, report current relative performance setting and render resolution via SetGamePerformanceSetting / SetGameRenderResolution when those values change. Valve attaches them to anonymous framerate data when the user has opted in.
Do:
- Call when the player changes quality or resolution, not every frame.
- Document the fields in your privacy / data note for partners.
- Gate behind the same opt-in expectation Steam already uses for framerate sharing.
Do not:
- Treat the APIs as required for Deck Verified.
- Send personally identifying data through them.
- Assume every player opted in.
Pass S4 when either (a) you deliberately skip reporting and the receipt says so, or (b) reporting is wired, rate-limited, and privacy-reviewed.
S5 - Wrapper readiness + Steam Input origins
| Stack | 1.65 readiness (as of late July 2026) | Action |
|---|---|---|
| Native C++ Steamworks | Valve shipped 1.65 | Bump SDK, fix compile breaks on removed API |
| GodotSteam | 4.21 shipped with SDK 1.65 (Server 4.10); brief delay on Win32 DLL then fixed | Upgrade plugin; re-test init and hardware calls |
| Steamworks.NET / Facepunch | Often lags Valve by days-weeks | Check bindings for new utils; stub compile guards if missing; do not ship half-bound APIs |
Also smoke Steam Input origins for Switch 2 / Steam Controller / Steam Frame Controller if your glyph or binding UI switches on origin enums. Missing origins usually show as "unknown" glyphs - catch that in QA, not after review.
If Editor init fails after a wrapper bump, isolate with Steamworks init failed - Unity Editor native plugin path.
Pass S5 when the wrapper you ship actually exposes the calls you use, and a controller-origin smoke list is checked.
S6 - Proton + hardware smoke and share note
Run a short matrix:
| Build | Check | Expected |
|---|---|---|
| Windows desktop | Fresh graphics profile | Desktop preset, not Deck |
| Steam Deck (Game Mode) | Fresh profile + Big Picture | Hardware default maps to your Deck-tuned preset |
| Same Deck under Proton path | IsRunningUnderProton true in diagnostics |
Settings still from default-config path, not from a Proton bool |
| Existing save | Launch after upgrade | Player overrides preserved |
| Crash zip | Hardware enum present | No IsRunningOnSteamDeck symbol |
For Deck verify tooling beyond this API smoke, keep 14 free Steam Deck verification tools after Proton 11 and the evening Proton 11 verify pass in the QA kit. For Machine cert language, pair with Steam Machine Verified. Broader integration bookmarks live in 18 free Steamworks and PC distribution resources.
Share note:
SDK 1.65 migration (YYYY-MM-DD)
Branch: [name] Wrapper: [native / GodotSteam x.y / SW.NET]
S1 inventory: N calls (D diagnostic / F functional)
S2 hardware enum in crash/analytics: pass/fail
S3 default-config presets Deck vs desktop: pass/fail
S4 performance reporting: skipped / privacy-OK wired
S5 wrapper + input origins: pass/fail
S6 Proton + save preserve: pass/fail
Decision: promote depot / hold
Pass S6 when the note and receipt exist with a named owner.
Migration matrix you can copy
| Old pattern | New pattern | Notes |
|---|---|---|
if (IsRunningOnSteamDeck()) quality = Medium |
GetSteamHardwareDefaultConfig() → map to Medium |
Future hardware can change without rebuild |
if (IsRunningOnSteamDeck()) log "deck" |
IsRunningOnSteamHardware() |
Diagnostic |
if (Linux) assume Proton |
IsRunningUnderProton() |
Accurate on Deck desktop vs native Linux builds |
| Glyphs from device name | Steam Input action origins | Includes new Controller / Frame / Switch 2 origins |
| Always send graphics telemetry | Opt-in + SetGamePerformanceSetting / SetGameRenderResolution |
Privacy gate |
| Hard-code Steam Machine later | Prefer default-config + unknown fallback | Do not invent a new device bool every SKU |
Who should hold the depot
- Teams with functional Deck bools still in production - compile may break the moment you bump; finish S1-S3 on a branch first.
- Unity / C# wrappers without 1.65 bindings yet - hold the feature use of new APIs; you can still remove Deck calls behind stubs if compile forces it, but do not fake
GetSteamHardwareDefaultConfig. - Anyone wiring performance reporting without privacy review - skip S4 reporting until legal/comms agrees.
- Titles mid-Deck Verified resubmit - finish the current cert packet on a known SDK, then migrate on the next packet (unless the removed API already blocks you).
Common mistakes
- Replacing
IsRunningOnSteamDeckwithIsRunningOnSteamHardware == Deckfor graphics. That recreates the device-name problem for Steam Machine / Frame / future SKUs. - Clobbering saved player settings on first boot after upgrade.
- Assuming Proton from OS alone and changing shader or path logic incorrectly.
- Shipping half-updated wrappers where headers compile but runtime symbols differ (especially after GodotSteam's Win32 DLL hiccup - re-verify your platform binaries).
- Calling performance setters every frame.
- Skipping desktop control. A Deck-only smoke cannot prove you did not break desktop defaults.
Troubleshooting order
- Compile break on
IsRunningOnSteamDeck- you still have a caller; finish S1. - Wrong preset on Deck - check default-config mapping and whether a leftover device bool still wins.
- Desktop gets Deck preset - mapping table or first-run flag is wrong; compare fresh profiles.
- Proton flag never true - confirm you are actually under Proton; native Linux builds will correctly return false.
- Wrapper missing symbols - check GodotSteam / Steamworks.NET version; pin known-good DLLs per platform.
- Editor init failed after bump - plugin path /
steam_appid.txt; see the help article linked in S5.
What teams should do next Monday
Solo indie
- Grep, classify, migrate S2-S3 on a branch.
- Smoke Deck + desktop once; promote when S6 passes.
Small studio
- One engineer owns the inventory spreadsheet.
- QA owns the S6 matrix; pipeline lead owns privacy for S4.
Company / publisher build
- Require the migration receipt in the release checklist.
- Ban new device-name conditionals in code review.
- Track wrapper versions next to SDK version in the SBOM / dependency note.
Creator / content QA
- Paste the share note into Discord after the smoke.
- Attach one screenshot of first-run presets on Deck vs desktop.
Key takeaways
- Steamworks SDK 1.65 (July 24, 2026) removes
IsRunningOnSteamDeck()- migrate before the next SDK bump forces it. - Use
IsRunningOnSteamHardware()for analytics/support/diagnostics only (Valve announcement). - Use
GetSteamHardwareDefaultConfig()for first-run and hardware-tuned defaults - including future Steam hardware without a recompile. - Use
IsRunningUnderProton()instead of guessing from OS. - Keep diagnostic vs functional calls separate - never one
bool isDeckfor both. SetGamePerformanceSetting/SetGameRenderResolutionattach to anonymous framerate data only when the user opted in - privacy-gate them.- GodotSteam 4.21 tracks SDK 1.65 (GodotSteam post); confirm your C# wrapper bindings before calling new APIs.
- New Steam Input origins (Switch 2, Steam Controller, Steam Frame Controller) need a glyph/QA pass.
- Preserve player-saved settings across the upgrade.
- Smoke Deck + desktop + Proton path before promoting a depot.
- Hold the depot if wrappers, privacy, or preset mapping are incomplete.
- A filled migration matrix + receipt is the cite-worthy artifact - not another changelog summary.
FAQ - Steamworks SDK 1.65
What happened to IsRunningOnSteamDeck in SDK 1.65?
It was removed. Valve directs developers to feature-specific methods: IsRunningOnSteamHardware for diagnostics, GetSteamHardwareDefaultConfig for settings, plus existing helpers like Big Picture and VR checks, and the new IsRunningUnderProton.
Should I use IsRunningOnSteamHardware to set graphics quality?
No. Valve documents that call for analytics, support, or diagnostic purposes. For functional defaults, use GetSteamHardwareDefaultConfig and capability-based checks so future Steam hardware can change defaults without a recompile - and so you do not bake device names into gameplay settings.
What does GetSteamHardwareDefaultConfig do?
It helps choose default game settings (video and others) tuned for specific Steam hardware, and supports changing those defaults on future Steam hardware without recompiling the game. Map its result to your own preset table and keep player overrides intact.
How do I detect Proton in SDK 1.65?
Call ISteamUtils::IsRunningUnderProton(). Do not assume every Linux session is Proton, and do not drive graphics solely from the Proton flag.
Are the new performance APIs required?
No. SetGamePerformanceSetting and SetGameRenderResolution let you report settings/resolution into Steam's anonymous framerate channel when the user has opted in. Skip them until privacy and product agree.
Does GodotSteam support SDK 1.65 yet?
Yes. GodotSteam 4.21 (and GodotSteam Server 4.10) shipped with SDK 1.65 support around July 29, 2026, after a short Windows 32-bit DLL fix from Valve. Upgrade and re-test init on each target platform.
What about Steamworks.NET?
C# wrappers often lag Valve's native SDK. Confirm bindings for the new utils before calling them in production. You can still remove dead IsRunningOnSteamDeck calls while waiting, but do not stub fake hardware-default behavior.
Will this migration help Steam Machine and Steam Frame?
Yes - that is the point. Diagnostics can report hardware type; settings should come from default-config and capabilities so Machine / Frame / future devices do not require a new hard-coded branch each time.
Related reading
- Your First Proton 11 Steam Deck Verify Pass - One Evening 2026
- Steam Machine Verified - What Indies Should Lock After Great on Machine 2026
- 14 Free Steam Deck Verification Tools After Proton 11 - 2026
- 18 Free Steamworks and PC Distribution Integration Resources 2026
- 18 Free Steam Deck Performance and Compatibility Testing Resources
- Steamworks Init Failed - Unity Editor Native Plugin Path Fix