DEV Community

Cover image for Publish a Unity Game on Itch.io: WebGL, ZIP & HTML5 Setup (Step-by-Step)
abdul rahman
abdul rahman

Posted on Originally published at gameunity.store on

Publish a Unity Game on Itch.io: WebGL, ZIP & HTML5 Setup (Step-by-Step)

A complete release engineering guide covering root-level ZIP packaging, WebGL decompression fallbacks, Butler CLI automation, and browser canvas optimization.

Technical Abstract: Publishing an indie game on itch.io is often treated as a simple file upload, yet hundreds of developers struggle with black loading screens, memory crashes, and 404 errors. This guide breaks down the release pipeline, based on the comprehensive architectural guide published on GameUnity: How to Publish Your Unity Game on Itch.io.


šŸ“Œ The Short Answer: How Do You Upload a Unity Game to itch.io?

Uploading a Unity game to itch.io is fairly straightforward, but the build format is where people often get tripped up:

  • In-Browser Play (WebGL): If you want players to launch your game directly in their browser without downloading third-party files, WebGL is the right choice.
  • Downloadable Play (Standalone): If you want players to install an expansive, high-fidelity experience, a ZIP containing the Windows/Mac build is simpler and avoids browser memory limits.

For a browser release, switch Unity's build platform to WebGL, build the project, and make sure index.html sits directly at the root level of your ZIP archive. If you run into deeper pipeline questions or want the complete architectural blueprint, review the complete Unity to itch.io publishing framework on GameUnity.


"The most common mistake indie developers make when publishing to itch.io is treating their build as a loose desktop folder. Itch.io is an automated server environment. If your WebGL ZIP contains a parent folder that hides index.html, the player gets a 404 or an unplayable canvas.

Build your project cleanly, verify your root directory structure before zipping, and automate your patch pipeline using Butler. That is the difference between a frustrating release and a seamless launch."

— Abdulrahman Maslmany, Lead Systems Architect


⚔ Quick Release Checklist

  • WebGL Root Invariance: index.html must sit directly in the root of the ZIP file, never inside a nested parent folder.
  • Decompression Fallback: Enable Gzip/Brotli fallback in Unity to eliminate black loading screens on itch.io.
  • Standalone Integrity: Package the .exe, UnityPlayer.dll, and *_Data folder together. Never upload the .exe alone.
  • Automated Updates: Use the Butler CLI to push binary delta patches directly from your terminal.

1. Architectural Decision: In-Browser WebGL vs. Downloadable Standalone ZIP

Selecting between an embedded in-browser experience and an offline desktop installer represents a fundamental engineering trade-off:

  • When to Choose WebGL: WebGL reduces player friction to zero. Players click a link, wait a few seconds for assets to stream, and play immediately. It is indispensable for game jams, portfolio showcases, and web demos.
  • When to Choose a Downloadable Standalone ZIP: Grants your game unconstrained access to high-performance desktop APIs (DirectX 12, Vulkan), full multi-threading, persistent disk I/O, and unrestricted system memory.
  • The Critical Testing Rule: Always test the uploaded game directly on itch.io, not just inside the Unity Editor or localhost. Browser CORS security policies, iframe sandboxing, and mobile browser WebGL memory ceilings often trigger silent failures on itch.io that never appear locally.

2. Do You Need to Upload Every File? (Correct ZIP Structure)

A frequent question when preparing a Unity build is: "Do I need to upload every single file from the build folder, and how should it be packaged?"

The short answer: Yes, you must upload all compiled files, but how you compress them makes the difference between an instant success and a broken launch.

A. The WebGL HTML5 ZIP Architecture (The Root index.html Rule)

When Unity exports a WebGL project, it creates three core components:

  1. index.html (The entry web document)
  2. Build/ (Contains .wasm, .data, and .framework.js binaries)
  3. TemplateData/ (Contains loading bars, icons, and style sheets)
āŒ The #1 Mistake: Zipping the Parent Folder

plaintext
MyGame.zip
└── WebGL_Build_Folder/       <-- WRONG! Itch.io cannot detect index.html
    ā”œā”€ā”€ index.html
    ā”œā”€ā”€ Build/
    └── TemplateData/
Result on itch.io: "There was an issue loading your game. No index.html found at root level."
code
Code
MyGame.zip
ā”œā”€ā”€ index.html                <-- PERFECT! Directly in root of ZIP
ā”œā”€ā”€ Build/
│   ā”œā”€ā”€ MyGame.data.unityweb
│   ā”œā”€ā”€ MyGame.framework.js.unityweb
│   └── MyGame.wasm.unityweb
└── TemplateData/
How to do it: Open your WebGL build folder, select all items inside (Ctrl+A or Cmd+A), right-click → Compress to ZIP.
B. The Standalone Desktop Rule (Windows / Mac)
If you are uploading a downloadable Windows game, never upload only the .exe file. A Unity executable cannot boot without its runtime dependencies. You must compress the entire folder containing:
MyGame.exe
UnityPlayer.dll (The core rendering engine library)
UnityCrashHandler64.exe
MyGame_Data/ (Contains scenes, models, and audio)
MonoBleedingEdge/ (If using Mono runtime instead of IL2CPP)
3. Unity WebGL Build Settings: WebAssembly & Decompression Fallbacks
To ensure smooth execution inside browser sandboxes without crashing:
Switch Platform: In Unity, go to File > Build Settings, select WebGL, and click Switch Platform.
Enable Decompression Fallback: Go to Project Settings > Player > Publishing Settings.
Set Compression Format to Gzip.
Crucial: Tick Decompression Fallback. Since itch.io servers do not always serve custom Content-Encoding: gzip response headers, this injects a lightweight JavaScript decompressor that prevents the dreaded black loading screen.
Tune WebGL Memory Size: Set WebGL Memory Size between 256 MB and 512 MB. Allocating above 1024 MB frequently causes Out-Of-Memory (OOM) crashes in mobile and low-RAM desktop browsers. For advanced asset footprint techniques, see the Unity mobile and WebGL performance guide on GameUnity.
4. Configuring Project Settings on itch.io
Log into your itch.io dashboard and select Create New Project.
Under Classification, select Games.
Under Kind of project, change the dropdown to HTML ("You have a ZIP or HTML file that will be played in the browser").
In the Uploads section, upload your root-level WebGL .zip file.
Once uploaded, check: "This file will be played in the browser".
Set Viewport Dimensions:
Set Manual size to 1280 px width by 720 px height (matching your Unity canvas).
Enable the Fullscreen button.
Enable Automatically start on page load.
Under Visibility & access, keep the project in Draft or Restricted to test the live build before going public.
5. Troubleshooting Guide: Fixing Common itch.io Errors
Problem 1: "No index.html found"
Fix: You zipped the folder rather than its contents. Extract the ZIP, select the files directly (index.html, Build, TemplateData), and re-zip them.
Problem 2: Stuck on Black Screen or "An error occurred running Unity content"
Fix: Enable Decompression Fallback in Unity Publishing Settings, or set Compression Format = Disabled.
Problem 3: "Out of Memory" (OOM) or JavaScript Heap Exhaustion
Fix: Lower your WebGL memory allocation in Unity to 384 MB or 512 MB, and compress textures using ASTC or Crunch.
Problem 4: Windows Build Crashes with "Failed to Load Mono"
Fix: The player launched the .exe without extracting the *_Data folder and UnityPlayer.dll. Ensure your ZIP archive packages the full directory payload.
6. Automate Your Uploads with the Butler CLI
Manually re-zipping and uploading builds on every minor patch is slow. Professional developers automate deployment using Butler, itch.io's command-line tool:
code
Bash
# 1. Authenticate Butler
butler login

# 2. Push WebGL build to your html5 channel
butler push ./Builds/WebGL yourusername/my-game:html5

# 3. Push Windows standalone build with version tagging
butler push ./Builds/Windows yourusername/my-game:windows-beta --userversion 1.0.4
Binary Delta Patching: Butler calculates binary diffs. If you only updated one script, Butler pushes a tiny 2MB patch instead of re-uploading an entire 400MB build.
7. Format Distribution Matrix
Project Format  Player Friction Hardware Overhead   Graphics API    Optimal Scope
HTML5 / WebGL   Zero (Instant 1-Click Play) Low (Browser Sandbox)   WebGL 2.0 / URP Game Jams, Demos, 2D Titles
Windows Standalone (.zip)   Moderate (Download & Unzip) Full GPU Access DirectX 12 / Vulkan / HDRP  3D Action, Deep RPGs
macOS Bundle (.app) Moderate (Gatekeeper Check) Apple Silicon Native    Metal Native API    Cross-Platform Indie Releases
8. C# Script: WebGL Canvas Viewport & Focus Adapter
In browser environments, pressing arrow keys or the spacebar can inadvertently scroll the browser window, and switching tabs can cause audio to loop erratically. Attach this production C# component to an active GameObject in your first scene:
code
C#
using System;
using UnityEngine;

/// <summary>
/// Production-grade WebGL Viewport and Browser Focus Synchronization Adapter.
/// Prevents webpage scrolling on arrow keys and manages background tab muting.
/// </summary>
public class WebGLResolutionAdapter : MonoBehaviour
{
    public static event Action<bool> OnWindowFocusChanged;

    [Header("Viewport Resolution Lock")]
    [Tooltip("Target fixed render width inside itch.io iframe.")]
    [SerializeField] private int targetWidth = 1280;
    [Tooltip("Target fixed render height inside itch.io iframe.")]
    [SerializeField] private int targetHeight = 720;
    [Tooltip("Automatically freeze Time.timeScale and mute AudioListener on tab blur.")]
    [SerializeField] private bool autoPauseOnUnfocus = true;

    private void Awake()
    {
        #if UNITY_WEBGL && !UNITY_EDITOR
        // Lock aspect ratio resolution inside the browser canvas
        Screen.SetResolution(targetWidth, targetHeight, false);

        // Prevent WebGL from capturing mouse scroll wheel for webpage scrolling
        WebGLInput.captureAllKeyboardInput = true;
        #endif
    }

    private void OnApplicationFocus(bool hasFocus)
    {
        if (autoPauseOnUnfocus)
        {
            Time.timeScale = hasFocus ? 1.0f : 0.0f;
            AudioListener.pause = !hasFocus;
        }

        OnWindowFocusChanged?.Invoke(hasFocus);
        Debug.Log($"[WebGLAdapter] Application Window Focus State: {hasFocus}");
    }
}
For foundational C# architectures and design patterns, explore the Unity C# programming guides on GameUnity.
9. Storefront Conversion: Turning Visitors into Players
The 630Ɨ500 Cover Image: High-contrast typography and clear gameplay silhouettes. Never use unreadable micro-text.
Embed an Animated Gameplay GIF: Place a 5-second gameplay GIF directly above the fold in your itch.io description.
The 3-Second Control Map: Document your keybindings right under the canvas (e.g., [WASD] to Move | [SPACE] to Jump | [E] to Interact).
10. Frequently Asked Questions (FAQ)
Do I need to upload every file from the build folder for an itch.io game?
Yes. For WebGL, package index.html, Build, and TemplateData into the root of the ZIP. For standalone desktop builds, never upload the isolated .exe; include the entire *_Data directory and UnityPlayer.dll.
Why does my Unity WebGL game show a black screen on itch.io?
Missing server decompression headers. Enable Decompression Fallback with Gzip compression in Unity's Player Settings to embed a client-side unpacker.
Why is it essential to test on itch.io rather than locally?
Browser iframe sandboxing, CORS rules, and mobile RAM constraints frequently cause asset-loading errors that do not trigger inside the Unity Editor.
Academic Citation & Whitepaper
Maslmany, A. (2026). Automated Release Engineering & WebAssembly Binary Optimization in Independent Game Publishing. CERN Zenodo.
DOI: 10.5281/zenodo.22641931
This article was originally published with interactive pipeline blueprints at GameUnity: How to Publish Your Unity Game on itch.io.
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
suppdevbot profile image
Info Comment hidden by post author - thread only accessible via permalink
DEV SUPPORTS •

You need to verify your account.

Enter fullscreen mode Exit fullscreen mode

tr.ee/dev-to

Some comments have been hidden by the post's author - find out more