GX.games HTML5 Upload Receipt build_id Disagrees With Steam Depot build_label - How to Fix
Problem: Your GX.games HTML5 upload returns a receipt JSON with build_id": "gx-2026-05-20-a" (or similar), but the Steam fest install title screen shows fest-demo-2026-05-24-rc2. Support tickets reference one string; your BUILD_RECEIPT row references another—and QA cannot tie a GX browser crash to the NW.js Steam build players actually downloaded.
Who is affected now: HTML5-first micro-studios running GX.games + Steam in parallel per the H2 2026 HTML5 second storefront analysis. You fixed itch MIME and Steam depot names, but GX uploader cache and manual version bumps still let channels diverge during fest week. This is cross-channel label drift, not playtest binary on fest depot (same Steam surface, wrong exe).
Fastest safe fix: Pick one build_label string in repo root VERSION (or CI env) → inject into HTML5 export, GX upload metadata, and Steam NW.js / desktop build → upload both channels from the same git SHA → diff gx_html5_upload_receipt_v1.json vs build_label_smoke_receipt_v1.json → block fest visibility / GX publish when strings differ → confirm in-game overlay on both clients.
Direct answer
GX.games and Steam are separate CDNs—they do not share a manifest. If you bump Steam’s build_label after promotion but skip GX re-upload (or GX serves a cached HTML5 bundle), receipts and player-visible labels will disagree. Treat build_label as a release artifact property generated once per commit, not per storefront form field.
Why this issue spikes in 2026
- Dual-surface HTML5 studios — GX for discovery, Steam for wishlist/fest—two upload rituals, one tired producer.
- GX cache behavior — Old
index.html/ wasm can remain live after you thought you shipped. - Different ID field names — GX API returns
build_id; Steam docs saybuild_label; teams map them mentally and drift. - Separate defines —
STEAM_RELEASEvsGX_BUILDmacros diverge when only one export preset updates. - Wednesday smoke — BUILD_RECEIPT columns now expect per-channel upload proof, not Steam-only.
Symptoms and search phrases
- GX developer console receipt
build_id≠ Steam title-screenbuild_label. - Player on GX reports bug; your Steam crash log filter finds no matches.
- BUILD_RECEIPT has Steam upload row only—GX row missing or stale date.
- Fest week hotfix: Steam promoted; GX still serves last week’s wasm.
playtest_scope_map_v1.jsonlistsgx_publicrow but nobody re-uploaded GX after fest tag.- Support spreadsheet has two “version” columns that stopped matching in May.
- CI green on Steam job; GX upload job skipped or used
latestartifact from wrong branch.
Root causes (check in order)
- Manual bump on one channel only — Steam
rc3, GX stillrc2. - GX CDN / project cache — upload succeeded; live game old.
- Steam depot promoted later — GX uploaded from earlier commit.
- Different scripting defines — HTML5 export preset not reading same
VERSIONfile. - Separate CI workflows — no shared “release tag” input.
- Receipt records wrong field — logged GX project id instead of build_id from response body.
- No in-game readout on HTML5 — mismatch found via Discord, not smoke.
Beginner path (first 45 minutes)
Prerequisites: GX.games project access, Steam fest build installed (not editor), one VERSION file in repo (create if missing).
- Open live GX.games game URL → pause/menu → note on-screen
build_label(add if missing—Step 2). - Install Steam fest demo → note title-screen label (photo).
- Download last GX upload receipt from CI artifact or
release-evidence/gx/. - Compare three strings: GX overlay, Steam overlay, receipt
build_id/build_label. - If any differ → pause GX publish and Steam fest visibility until one commit rebuilds both.
Common mistake: Trusting GX dashboard “last updated” timestamp without opening the live URL in a private window.
Fastest safe fix path
Step 1 — Single build_label source of truth
Create repo-root VERSION (plain text, one line):
fest-demo-2026-05-24-rc2
Wire every export to read it:
| Stack | Injection |
|---|---|
| Construct 3 | Project property + event copies to HUD Text |
| GameMaker | #macro BUILD_LABEL include from generated header |
| Godot 4.x | Export preset env BUILD_LABEL; autoload BuildInfo |
| Phaser / custom | Webpack DefinePlugin or import.meta.env |
Rule: CI sets VERSION from git tag fest-demo-2026-05-24-rc2—humans do not edit per storefront.
Step 2 — Capture GX upload receipt correctly
After GX.games uploader / API publish, persist response body (field names vary by integration—normalize in CI):
{
"schema": "gx_html5_upload_receipt_v1",
"uploaded_at_utc": "2026-05-24T21:15:00Z",
"git_sha": "a1b2c3d4",
"build_id": "fest-demo-2026-05-24-rc2",
"gx_project_id": "your-project-slug",
"live_url": "https://gx.games/games/your-game/your-build/",
"wasm_mime_ok": true,
"pass": true
}
Store at release-evidence/gx/gx_html5_upload_receipt_v1.json.
Normalize: map GX API build_id → same string as VERSION file—if API returns opaque hash, also log build_label you sent in upload metadata.
Official: GX.games documentation (verify current uploader fields in your integration version).
Step 3 — Steam side build_label_smoke_receipt
Reuse Steam fest depot build_label help receipt—add channel awareness:
{
"schema": "build_label_smoke_receipt_v1",
"channels": [
{
"channel": "steam_fest",
"expected_build_label": "fest-demo-2026-05-24-rc2",
"installed_build_label": "fest-demo-2026-05-24-rc2",
"pass": true
},
{
"channel": "gx_html5",
"expected_build_label": "fest-demo-2026-05-24-rc2",
"installed_build_label": "fest-demo-2026-05-24-rc2",
"pass": true
}
],
"cross_channel_label_collision": false,
"pass": true
}
Step 4 — CI diff gate (fail closed)
$version = Get-Content -Raw VERSION
$gx = Get-Content release-evidence/gx/gx_html5_upload_receipt_v1.json | ConvertFrom-Json
$steam = Get-Content release-evidence/steam/build_label_smoke_receipt_v1.json | ConvertFrom-Json
if ($gx.build_id -ne $version.Trim()) { throw "GX build_id mismatch VERSION" }
$fest = $steam.channels | Where-Object { $_.channel -eq "steam_fest" }
if ($fest.installed_build_label -ne $version.Trim()) { throw "Steam label mismatch VERSION" }
Run after both upload jobs on the same pipeline run (same git_sha).
Step 5 — BUILD_RECEIPT multi-channel row
Extend BUILD_RECEIPT:
| Column | Example |
|---|---|
build_label |
fest-demo-2026-05-24-rc2 |
git_sha |
a1b2c3d4 |
gx_upload_ok |
true |
steam_depot_upload_ok |
true |
channel_label_match |
true |
Attach both receipt JSON paths in upload_log array.
Step 6 — GX cache bust smoke
After upload:
- Open GX live URL in private window (no service worker from dev session).
- Hard refresh (Ctrl+F5) or append
?b=fest-demo-2026-05-24-rc2query if your loader supports cache bust. - Confirm overlay label matches
VERSION. - If stale → re-upload; check GX project “replace build” vs new slot; verify wasm path updated.
Pair with itch.io WASM MIME boot hang when browser loads wrong wasm—not label drift but common on same HTML5 artifact.
Working dev path — playtest_scope_map channel rows
Add explicit channel surfaces:
{
"surfaces": [
{
"surface_id": "gx_public",
"channel": "gx_html5",
"build_label": "fest-demo-2026-05-24-rc2",
"demo_scope": "fest_hour_one"
},
{
"surface_id": "fest_public",
"channel": "steam",
"build_label": "fest-demo-2026-05-24-rc2",
"demo_scope": "fest_hour_one"
}
]
}
| Check | Pass |
|---|---|
Same build_label on both rows when scope matches |
Yes |
Different demo_scope → labels may differ intentionally |
Documented |
git_sha in both receipts equal |
Yes |
GX wasm_mime_ok |
true for Godot/Construct exports |
See playtest isolation playbook for surface tagging—GX public is fest_public or dedicated gx_public per your policy, not playtest.
Verification checklist
- [ ]
VERSIONfile matches GX receiptbuild_id/build_label - [ ]
VERSIONmatches Steam installed overlay - [ ] GX live URL overlay matches after private-window load
- [ ]
gx_html5_upload_receipt_v1.jsonpass: true - [ ]
build_label_smoke_receipt_v1.jsonall channelspass: true - [ ] BUILD_RECEIPT
channel_label_match: true - [ ] Both uploads from same
git_sha - [ ] Wednesday smoke diff includes GX + Steam columns
Prevention
- One pipeline, two upload jobs—sequential, same artifact folder.
- Never bump Steam only during fest week without GX job.
- Photo/screenshot gate: GX overlay + Steam overlay in CI artifacts.
- Document GX cache bust step in facilitator README (sibling to playtest VOD README).
- GameMaker export sanity + HTML5 analysis as onboarding reading.
Troubleshooting
| Symptom | Fix |
|---|---|
| GX receipt OK, live game old | Cache—private window + re-upload; verify wasm URL changed |
| Steam correct, GX wrong | Re-run GX job from fest tag commit |
| Labels match, behavior differs | Different defines—grep STEAM / GX macros; not this article’s label-only drift |
Opaque GX build_id hash |
Store your build_label in upload metadata + receipt |
| Only Steam in BUILD_RECEIPT | Add GX row; block promotion without it |
| Playtest label on GX | Wrong export preset—see Steam playtest on fest depot |
FAQ
Is GX build_id the same as Steam BuildID?
No. Steam BuildID is SteamPipe internal. Your team-owned string is build_label (human-readable). Map GX API fields into that string for support triage.
Can we use different labels if demos differ?
Yes—if demo_scope differs, labels should differ and playtest_scope_map must document it. Do not silently diverge when scope is meant to match.
Do we need GX if we only ship Steam?
No—skip GX receipt columns. This help applies when both channels are live.
Construct-only on GX, GameMaker on Steam?
Still use one build_label per release intent if QA correlates bugs across channels; note engine in receipt notes field.
Related links
- BUILD_RECEIPT channel_label_match False With itch as Third Channel
- 14 Free GX.games and Multi-Channel HTML5 build_label Receipt Tools (2026)
- Steam Depot Promoted Playtest build_label on Fest Demo
- Steam Playtest Build Exposes Dev Console on Fest Demo
- 2026 H2 HTML5-First Studios Adding Android Second Storefront
- Your First GameMaker Steam Demo Export Sanity Check
- 12 Free GameMaker Studio 2 Steam Demo Export Save Sanity Resources
- 18 Free Steamworks PC Distribution Resources
- Wednesday Demo Build Smoke Ritual
- Your First BUILD_RECEIPT JSON and Upload Log
- itch.io HTML5 Godot WASM MIME Boot Hang
- Official: GX.games Docs, Steamworks — Builds
One build_label per release commit—GX receipts and Steam depots are two upload buttons, not two version truths.