Trend-Jacking / News Commentary May 25, 2026

Construct 3 Custom itch.io Domain CORS vs Subdomain Hosting - 2026 H2 Trend Playbook

2026 H2 Construct 3 trend playbook—itch.io custom domain CORS vs subdomain hosting decision tree, origin map, cors_hosting_decision_receipt_v1.json, and wasm smoke gates.

By GamineAI Team

Construct 3 Custom itch.io Domain CORS vs Subdomain Hosting - 2026 H2 Trend Playbook

Pixel-art hero for Construct 3 custom itch.io domain CORS versus subdomain hosting 2026 H2 trend playbook

Marketing bought a custom domain for the itch page. The Construct 3 HTML5 export loads on yourgame.itch.io—then shows a blank canvas on play.yourstudio.com with CORS errors for data.wasm and the worker script. Local preview works. Discord says “itch is broken.” Engineering says “we only changed DNS.”

July 2026 HTML5-first teams run itch + GX.games + Steam receipts in parallel (triple-channel help). Custom domains look professional for fest press kits—but Construct wasm and Web Workers expect same-origin asset fetches unless you control Cross-Origin headers end to end. This Trend-Jacking / News Commentary playbook is the hosting policy decision tree—not a second post-upload MIME article (CDN octet-stream) and not the planned evening subdomain smoke tutorial (step-by-step first proof).

Non-repetition note: Godot WASM memory ceiling owns runtime memory—not CORS origins. Planned help Construct CORS custom domain fix owns traceback-first fixes; this URL owns subdomain vs custom strategy + receipt.

Pair with BUILD_RECEIPT, Wednesday demo smoke, playtest isolation, and 14-free GX multi-channel tools.

Why this matters now (2026 H2)

  1. Custom itch domains — Studios point CNAME at itch for brand URLs without reading wasm origin rules.
  2. Construct 3 HTML5 velocity — Roguelite and narrative teams ship browser demos before NW.js Steam builds (Construct save migration).
  3. Multi-channel facilitators — Playtest links must match build_label per channel—wrong host breaks receipt rows.
  4. MIME vs CORS confusion — Teams fix application/wasm MIME and still fail because origin differs on custom domain.
  5. Fest October traffic — Press opens custom URLs first; subdomain proof skipped until production is on fire.

Direct answer: Prove on *`.itch.iosubdomain first**, filecors_origin_map_v1.json`, then choose custom domain only with a documented header plan—or keep marketing landing on custom and game iframe on subdomain.

The failure mode in one paragraph

Naive pattern: Export Construct HTML5 → upload to itch → enable custom domain → share https://play.brand.com in press kit. Page HTML loads from itch infrastructure but wasm/worker URLs resolve to a host that does not send Access-Control-Allow-Origin for your page origin. Browser blocks fetch; canvas stays black. Team re-uploads zip five times; MIME receipts pass; CORS still fails.

What breaks: Not Construct export quality—hosting topology. Subdomain hosting keeps game assets same-origin relative to itch’s game runner; arbitrary custom domains split origins unless configured.

Two hosting models (beginners)

Model URL shape Who sets CORS? Construct wasm typical result
itch subdomain studio.itch.io/game itch (bundled) Works when MIME OK
Custom domain play.brand.com You + itch limits Often breaks without header plan

Beginner rule: Ship fest demos on subdomain until cors_hosting_decision_receipt_v1.json approves custom.

Three origins (working developers)

Origin A: HTML shell (page URL bar)
Origin B: Game assets (wasm, data, workers, media)
Origin C: Optional API (analytics, saves)

Pass condition for Construct HTML5: A and B must be compatible for fetch + WebAssembly.instantiateStreaming. itch subdomain mode usually collapses A≈B; custom domain mode often splits them.

Symptom matrix (route correctly)

Console / Network Likely lane Read next
CORS policy blocked wasm This playbook C1–C6
instantiateStreaming MIME error CDN MIME itch MIME help
COOP / COEP isolated Cross-origin isolation Compare CORP headers
Works incognito on itch.io only Origin split Subdomain proof
Blank after Steam switch Wrong channel build Store-demo mismatch
Godot only broken Engine export Godot MIME help

Gates C1–C6 (hosting decision pass)

Gate Name Pass criterion
C1 Subdomain smoke Game playable on *.itch.io with wasm_mime_receipt GREEN
C2 Origin map cors_origin_map_v1.json lists page + asset hosts
C3 Custom domain need Written reason custom URL required (press, SSL brand, etc.)
C4 Header plan OR defer CORP/COEP doc or decision to stay subdomain-only
C5 DevTools proof No CORS errors on chosen production URL
C6 Receipt cors_hosting_decision_receipt_v1.json committed

C5 blocks public fest links when RED.

Decision tree (ASCII)

Start: Construct HTML5 fest demo ready?
  |
  +-- No --> Finish export; stop (not a hosting problem)
  |
  +-- Yes --> C1: Playable on studio.itch.io/game ?
        |
        +-- No --> Fix MIME/zip first (itch MIME help)
        |
        +-- Yes --> Need custom domain in press kit?
              |
              +-- No --> SHIP subdomain (done)
              |
              +-- Yes --> Can you set ACAO/CORP on asset host?
                    |
                    +-- No --> SPLIT: landing=custom, PLAY link=subdomain
                    |
                    +-- Yes --> Implement header plan + C4/C5 + custom

Split pattern (recommended): https://brand.com/fest-2026 marketing page embeds or links https://studio.itch.io/your-demo—players never fetch wasm from a mismatched origin.

cors_origin_map_v1.json

{
  "schema": "cors_origin_map_v1",
  "project": "roguelite-demo-2026",
  "updated": "2026-05-25",
  "lanes": [
    {
      "lane_id": "itch_subdomain",
      "page_origin": "https://studio.itch.io",
      "asset_origin": "https://studio.itch.io",
      "same_origin": true,
      "construct_export": "html5-zip-rc3",
      "status": "production"
    },
    {
      "lane_id": "custom_press",
      "page_origin": "https://play.brand.com",
      "asset_origin": "https://cdn.itch.io",
      "same_origin": false,
      "header_plan": "defer-wasm-to-subdomain",
      "status": "marketing-only"
    }
  ],
  "wasm_files": ["data.wasm", "workermain.js"],
  "notes": "Do not promote custom until C5 pass"
}

Store under release-evidence/html5/cors/.

cors_hosting_decision_receipt_v1.json

{
  "schema": "cors_hosting_decision_receipt_v1",
  "build_id": "html5-nextfest-2026-rc6",
  "chosen_production_host": "itch_subdomain",
  "custom_domain_enabled": true,
  "custom_domain_serves_wasm": false,
  "gates": {
    "C1_subdomain_smoke": "pass",
    "C2_origin_map": "pass",
    "C3_custom_need_documented": "pass",
    "C4_header_plan_or_defer": "pass",
    "C5_devtools_no_cors": "pass",
    "C6_receipt": "pass"
  },
  "paired_receipts": [
    "release-evidence/html5/wasm_mime_receipt_v1.json",
    "release-evidence/build/build_receipt_v1.json"
  ],
  "facilitator_url_canonical": "https://studio.itch.io/your-demo",
  "promotion_allowed": true
}

Wire html5_host: verified into BUILD_RECEIPT and Thursday row review.

DevTools proof protocol (15 minutes)

  1. Open production URL → F12 → Console — screenshot CORS lines.
  2. Network → filter wasm — note Request URL host vs page host.
  3. If hosts differ, expect CORS unless headers green in Headers tab.
  4. Repeat Firefox + Chrome (facilitator matrix minimum).
  5. Archive devtools_cors_proof.md with pass/fail per browser.

curl sketch (supplement, not substitute)

curl -I "https://studio.itch.io/your-demo/data.wasm"
# Expect Content-Type: application/wasm (see MIME help)

curl -I "https://play.brand.com/" 
# Page may 200 while wasm on another host still CORS-fails in browser

Browsers enforce CORS stricter than curl—never close a ticket on curl alone.

Construct 3 export notes

Setting / artifact Fest recommendation
Export type HTML5 zip to itch
Minify scripts On (smaller wasm fetch)
Worker mode Note worker script names in origin map
Remote scripts Avoid third-party origins during CORS debug
NW.js Steam Separate lane—do not mix proofs

Outbound: Construct 3 manual — HTML5 export.

Header vocabulary (when you control CDN)

Header Role
Access-Control-Allow-Origin Must include page origin or * (careful with credentials)
Cross-Origin-Resource-Policy cross-origin vs same-origin on wasm
Cross-Origin-Embedder-Policy Isolation features—test before enabling blindly
Cross-Origin-Opener-Policy Popup/worker interactions

Honest limit: itch custom domain pages may not let you set arbitrary headers on itch-hosted wasm—treat “full custom” as marketing shell, not wasm host, unless support confirms otherwise.

Multi-channel alignment

Channel Hosting note
itch subdomain Canonical wasm proof
GX.games Separate origin map row
Steam NW.js / standalone—not this playbook
itch custom Marketing only until C5

triple-channel help channel_label_match fails when facilitators distribute custom URL but receipts reference subdomain build_label.

Beginner path (producer, 60 minutes)

  1. Ask engineering for one green URL on *.itch.io.
  2. Paste that URL in press kit—not custom domain.
  3. If brand demands custom, require split pattern in writing.
  4. Collect DevTools screenshot with zero CORS errors.
  5. Sign receipt only when facilitator_url_canonical matches Discord pin.

Developer path (engineering, half day)

  1. Automate C1 with Playwright load + console listener.
  2. Block CI deploy if press JSON contains custom URL without C5 pass.
  3. Add html5_host column to BUILD_RECEIPT.
  4. Pair Wednesday smoke golden path on canonical host only.
  5. Document in facilitator README (snippet below).

Facilitator README snippet

## HTML5 playtest link
- Canonical: https://studio.itch.io/your-demo (wasm host)
- Marketing: https://play.brand.com (landing only—do not file bugs against wasm here)
- If canvas blank: check Console for CORS before re-uploading zip
- Tag issues: html5-cors vs html5-mime

Relationship to upcoming tutorial (#9 backlog)

Topic This trend playbook Planned subdomain evening tutorial
Strategy Primary Assumes strategy chosen
cors_smoke_receipt_v1.json Referenced Hands-on steps
Decision tree Full Brief recap
curl MIME Points to help May include ffprobe-style checks

Ship strategy first so tutorial does not debug CORS on a host you should never use.

Troubleshooting table

Observation First action
Custom blank, subdomain OK Stop wasm on custom; use split
CORS + MIME error Fix MIME on subdomain first
Intermittent blank CDN cache—MIME help
GX works, itch custom fails Separate origin maps
Worker failed Include worker URL in C2 map
After DNS change only Re-run C5—origins changed

Fest week calendar

Day Action
Mon C1 subdomain smoke + MIME receipt
Tue Draft origin map + decision tree sign-off
Wed Demo smoke on canonical host
Thu Row review html5_host column
Fri Freeze facilitator URL in Discord

Engine comparison (HTML5 lanes)

Engine Custom domain CORS risk
Construct 3 High (wasm + worker)
Godot 4.5 Web High — see Godot wasm blog
Phaser Medium (script tags)
Unity WebGL High + COOP complexity

Multi-engine studios still file one cors_origin_map_v1.json per demo SKU.

COOP / COEP / CORP (when isolation appears)

Some teams enable cross-origin isolation for threads or shared buffers—then every asset host must cooperate:

Header Symptom when wrong
COEP: require-corp Wasm blocked unless CORP present
CORP: same-origin on wasm Custom page cannot load asset
COOP: same-origin Popups break auth flows

Fest default: Do not enable isolation on itch HTML5 unless you already proved C5 on all hosts. Revisit after subdomain lane is boringly stable.

DNS and custom domain checklist (producer)

Step Owner Pass
CNAME points to itch per docs Producer DNS propagates
SSL cert valid Browser padlock Green
Custom URL loads itch page shell Manual 200 OK
Game canvas plays Engineering C5
Press PDF updated Marketing Canonical URL only

Common trap: DNS correct, SSL green, canvas still black—players blame “SSL” when CORS is the real fault. Train support to ask for Console screenshot first.

Case vignettes (synthesized patterns)

Vignette A — Press kit custom, wasm on subdomain

Studio linked play.brand.com in October kit. Wasm fetched from cdn.itch.io without ACAO for play.brand.com. Fix: Press kit → studio.itch.io/demo; custom domain landing paragraph only. Time to green: 90 minutes (no re-export).

Vignette B — MIME fixed, CORS ignored

Team passed wasm_mime_receipt after CDN MIME help on subdomain, then enabled custom same day without C5. Fix: Disabled wasm on custom; kept MIME discipline on subdomain. Lesson: order gates C1 → MIME → C5.

Vignette C — Facilitator link drift

Discord pin showed custom URL; BUILD_RECEIPT facilitator_url_canonical still subdomain—playtest bugs filed against wrong host. Fix: Thursday row review added html5_host diff column.

BUILD_RECEIPT row example

{
  "build_id": "html5-nextfest-2026-rc6",
  "channel": "itch_public",
  "html5_host": "itch_subdomain",
  "facilitator_url_canonical": "https://studio.itch.io/your-demo",
  "custom_domain_marketing_only": true,
  "cors_hosting_decision_receipt": "release-evidence/html5/cors/cors_hosting_decision_receipt_v1.json",
  "wasm_mime_receipt": "release-evidence/html5/wasm_mime_receipt_v1.json"
}

Align with GX receipt help so build_id matches across GX and itch proofs.

Browser matrix (minimum fest QA)

Browser Subdomain Custom (if used)
Chrome desktop Required pass C5 if promoted
Firefox desktop Required pass C5 if promoted
Safari macOS Required pass Extra scrutiny
Chrome Android Required pass Often forgotten
Safari iOS Required pass ITP quirks

Archive one screen recording per browser showing golden path load—not only static screenshots.

Press kit URL block (copy-paste)

Play the demo (canonical): https://studio.itch.io/your-demo
Brand site: https://play.brand.com (info + trailer; game runs on itch link above)
System: Modern Chrome/Firefox, WebGL enabled

Stops outlets from embedding the wrong origin in iframe articles.

Security and abuse notes

  • Do not set Access-Control-Allow-Origin: * on authenticated APIs sharing cookies with game host.
  • Treat facilitator URLs like secrets during NDA playtests—leaks cause playtest scope confusion, not security miracles.
  • Custom domains increase phishing risk—publish official URL list in Discord pinned post.

When to escalate to itch support

Escalate when:

  • Subdomain fails with GREEN MIME receipt (unlikely—file itch ticket with curl -I).
  • Custom domain required by publisher contract and split pattern rejected.
  • Headers documented but C5 still fails after 24h propagation.

Attach cors_origin_map_v1.json, devtools_cors_proof.md, and build_id—not only “CORS broken” subject lines.

Evidence folder layout

release-evidence/html5/cors/
  cors_origin_map_v1.json
  cors_hosting_decision_receipt_v1.json
  devtools_cors_proof.md
  screenshots/
    chrome_subdomain_pass.png
    chrome_custom_fail_or_pass.png
  wasm_mime_receipt_v1.json   # symlink or copy from sibling folder

Friday Block 5 should confirm the facilitator URL in Discord still matches facilitator_url_canonical—drift is a top-three October incident driver for HTML5 teams.

Post-mortem questions (after fest)

  1. Did we promote custom before C5?
  2. Did facilitators file MIME bugs when CORS was the root?
  3. Did GX and itch receipts disagree on build_id?
  4. Will tutorial #9 subdomain smoke become mandatory onboarding?

Honest answers feed the next Blog-Planner refill—Process rows stay closed; hosting depth moves into tutorials tied to receipts.

Pin the canonical itch URL in two places only: Discord welcome and BUILD_RECEIPT—third copies in Notion drafts cause October link drift.

Promotion checklist

  • [ ] cors_hosting_decision_receipt_v1.json committed
  • [ ] wasm_mime_receipt_v1.json GREEN on subdomain
  • [ ] Press kit URL equals facilitator_url_canonical
  • [ ] Custom domain does not serve wasm (unless C5 pass)
  • [ ] BUILD_RECEIPT html5_host row matches
  • [ ] Forward help linked when published

FAQ

Is custom domain always broken?
No—but default itch custom setups break Construct wasm unless you prove C5.

Can we iframe subdomain into custom?
Often yes for marketing; test embed policies and mobile Safari.

Does re-exporting Construct fix CORS?
Rarely—hosting topology is the fix.

Same zip on both URLs?
Same bytes, different origins—different browser results.

What about GX.games?
Add a lanes[] row—do not assume itch rules transfer.

Key takeaways

  1. Subdomain first — custom domain is a policy choice, not a upload toggle.
  2. CORS ≠ MIME — fix both, in that order, for Construct HTML5.
  3. cors_origin_map_v1.json documents truths engineering already knows.
  4. Split pattern saves fest week when you cannot set headers.
  5. Planned CORS help complements this strategy URL.

Related reading