📖 Original Article / Read Full Guide:
For the complete original version of this guide, visit Publish a Unity Game on Itch.io: WebGL & ZIP Guide.
Exhaustive release engineering masterclass on how to publish a Unity game on itch.io. Covers root-level ZIP archive hierarchies, solving WebGL black screens via Decompression Fallback, fixing browser memory crashes, automating delta updates with the Butler CLI, and high-converting storefront design.
📌 The Short Answer: How Do You Upload a Unity Game to itch.io?
To publish a Unity game on itch.io, build your project for WebGL (for instant in-browser play) or Standalone Windows/Mac (for downloadable play).
-
For WebGL: Compress the build files directly so that
index.htmlsits at the absolute root of the ZIP file (never inside a nested folder). In Unity Player Settings, enable Decompression Fallback to prevent black loading screens. On itch.io, set the project kind to HTML, tick "This file will be played in the browser", and configure canvas dimensions (1280×720). -
For Standalone builds: Upload the executable alongside its entire
_Datafolder andUnityPlayer.dllinside a single structured ZIP archive.
💡 Architect's Field Notes: A Pipeline, Not a Folder Upload
"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: Unity to itch.io
-
WebGL Root Invariance:
index.htmlmust sit directly in the root of the ZIP file, never in a subfolder. - Decompression Fallback: Enable Gzip/Brotli fallback in Unity to eliminate black loading screens on itch.io.
-
Standalone Integrity: Package the
.exe,UnityPlayer.dll, and*_Datafolder together. Never upload the.exealone. - Automated Updates: Use the Butler CLI to push binary delta patches directly from your terminal.
📑 Table of Contents
- Do You Need to Upload Every File? (Correct ZIP Structure)
- Unity WebGL Build Architecture
- How to Add a Browser Playable Game to itch.io
- Comprehensive Troubleshooting Guide
- Standalone Desktop Packaging
- Automated Deployment: Mastering the Butler CLI
- itch.io Project Distribution Matrix
- Full C# Implementation: WebGL Canvas Viewport & Focus Adapter
- Storefront Conversion Engineering
- Frequently Asked Questions (FAQ)
📁 1. Do You Need to Upload Every File?
One of the most frequent questions from developers publishing a Unity build to itch.io 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 an output directory containing:
-
index.html(The entry web document) -
Build/(Contains the.wasm,.data, and.framework.jsbinaries) -
TemplateData/(Contains loading bars, icons, and CSS formatting)
❌ THE #1 MISTAKE: Zipping the Parent Folder
plaintext
MyGame.zip
└── WebGL_Build_Folder/ <-- WRONG! Itch.io cannot see index.html here
├── index.html
├── Build/
└── TemplateData/
Result on itch.io: "There was an issue loading your game. No index.html found at root level."
✅ THE CORRECT WAY: Zipping the Contents Directly
code
Code
MyGame.zip
├── index.html <-- PERFECT! Directly in the root of the 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. Name the ZIP whatever you like; itch.io will parse it instantly.
B. The Standalone Desktop Rule (Windows / Mac)
If you are uploading a downloadable Windows game, do not upload only the .exe file. A Unity executable cannot run without its runtime dependencies. You must compress:
MyGame.exe
UnityPlayer.dll (The core rendering dynamic link library)
UnityCrashHandler64.exe
MyGame_Data/ (Contains all scenes, 3D models, and C# scripts)
MonoBleedingEdge/ (Required if your build uses Mono runtime instead of IL2CPP)
⚙️ 2. Unity WebGL Build Architecture
When you build for WebGL, your compiled C# code is converted via IL2CPP into optimized WebAssembly (Wasm). To ensure smooth execution inside browser sandboxes without crashing:
Switch Platform: Navigate to File > Build Settings, select WebGL, and click Switch Platform.
Configure Compression & Decompression Fallback: Open Project Settings > Player > Publishing Settings:
Set Compression Format to Gzip (or Disabled for debugging).
Crucial: Check the box for Decompression Fallback. Since itch.io servers do not always serve custom Content-Encoding: gzip headers, enabling this fallback bundles an internal JavaScript decompressor into your build, completely preventing the fatal black loading screen error.
Tune Memory Allocation: Under Publishing Settings, set WebGL Memory Size between 256 MB and 512 MB. Setting this above 1024 MB causes out-of-memory crashes on Chrome and mobile devices.
🌐 3. How to Add a Browser Playable Game to itch.io
To configure your project so players can click "Play Game" immediately in their web browser:
Log into your itch.io dashboard and click Create New Project.
Under Classification, select Games.
Under Kind of project, change the dropdown from Downloadable to HTML ("You have a ZIP or HTML file that will be played in the browser").
Scroll down to the Uploads section and click Upload files. Select your root-level WebGL .zip archive.
Once the upload completes, tick the checkbox: "This file will be played in the browser".
Configure Viewport Embed Dimensions:
Set Manual size: 1280 px width by 720 px height (or matching your Unity canvas resolution).
Enable Fullscreen button to let players expand the canvas.
Enable Automatically start on page load or tick Click to launch if you want a splash screen.
Under Visibility & access, set the project to Draft or Restricted to test it before public release.
🛠️ 4. Comprehensive Troubleshooting Guide
🚨 Problem 1: "There was an issue loading your game. No index.html found"
The Cause: You compressed the enclosing folder instead of compressing the files inside it. Itch.io looks strictly for /index.html in the ZIP root.
The Fix: Extract your ZIP, open the folder so you see index.html right in front of you, select all files, and create a fresh ZIP archive. Re-upload to itch.io.
🚨 Problem 2: Unity WebGL Stuck on Black Screen
The Cause: The browser attempted to load Gzip or Brotli compressed WebAssembly files (.unityweb), but itch.io's server did not send the decompression header.
The Fix: In Unity, go to Project Settings > Player > Publishing Settings and check Decompression Fallback. Alternatively, set Compression Format = Disabled.
🚨 Problem 3: "Out of Memory" (OOM) or JavaScript Heap Exhaustion
The Cause: The Unity WebGL memory pool was configured too high (e.g., 2048 MB), or large uncompressed textures flooded browser VRAM.
The Fix: Reduce WebGL Memory Size in Unity Player Settings to 384 MB or 512 MB. Compress all textures to ASTC or Crunch compression.
🚨 Problem 4: Windows Standalone Crashes with "Failed to Load Mono"
The Cause: You uploaded only the .exe file or the user extracted the .exe without the accompanying *_Data folder and UnityPlayer.dll.
The Fix: Ensure your ZIP archive contains the entire directory payload.
📦 5. Standalone Desktop Packaging
If your game relies on complex graphics shaders, compute shaders, or high-fidelity assets that exceed WebGL browser capabilities, standalone downloadable builds are essential.
Root Archive Packaging: Compress the executable together with its UnityPlayer.dll and *_Data folder into a single ZIP.
Separate Architectures: Upload distinct packages for Windows 64-bit, macOS, and Linux.
macOS Gatekeeper Workaround: Remind Mac players in your page description that if macOS displays a developer verification error, they can run xattr -cr /path/to/game.app in Terminal to bypass Gatekeeper quarantine.
🤖 6. Automated Deployment: Mastering the Butler CLI
Professional studios and game jam veterans automate their pipeline using Butler, itch.io's official command-line deployment tool:
code
Bash
# 1. Authenticate Butler with your itch.io account
butler login
# 2. Push an optimized WebGL build to your html5 channel
butler push ./Builds/WebGL yourusername/my-game:html5
# 3. Push a Windows standalone build with automatic version tagging
butler push ./Builds/Windows yourusername/my-game:windows-beta --userversion 1.0.4
Binary Delta Patching: Butler uploads only modified file differences. If you adjust a few balance numbers in a C# script, Butler pushes a tiny 2MB diff instead of re-uploading a 400MB archive.
📊 7. itch.io Project Distribution Matrix
Project Format Player Friction Hardware Overhead Shader & Graphics Limits Optimal Game Scope
HTML5 / WebGL (In-Browser) Zero (Instant 1-Click Play) Low (Browser Sandbox) WebGL 2.0 / URP Only Game Jams, Web Demos & 2D Titles
Windows Standalone (.zip) Moderate (Download & Unzip) Full Desktop GPU Access DirectX 12 / Vulkan / HDRP 3D Action, Deep RPGs & Steam Demos
macOS Universal Bundle (.app) Moderate (Security Check) Apple Silicon Native Metal Native API Cross-Platform Indie Releases
💻 8. Full C# Implementation: WebGL Canvas Viewport & Focus Adapter
Attach this production C# adapter to a persistent GameObject in your starting scene to lock the canvas resolution, capture inputs exclusively, and handle tab blurring cleanly:
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}");
}
}
🎨 9. Storefront Conversion Engineering
Uploading your Unity game successfully takes ten minutes; convincing players to click "Play Game" requires visual conversion engineering:
The 630×500 Cover Image: Your cover banner is your primary billboard. Feature high-contrast typography, recognizable character silhouettes, and zero unreadable micro-text.
Embed an Animated Gameplay GIF: In your page description, embed an animated 5-second GIF right above the fold. Animated gameplay captures player attention ten times faster than text paragraphs.
The 3-Second Control Map: Document your control scheme directly underneath the game 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 builds, you must upload all files (index.html, Build/ folder, TemplateData/ folder) compressed into a single ZIP where index.html sits at the root. For standalone Windows builds, upload the .exe alongside the entire *_Data directory and UnityPlayer.dll inside the ZIP archive.
Why does my Unity WebGL game show a black screen on itch.io?
This is typically caused by missing server decompression headers. Enable Decompression Fallback with Gzip compression in Unity's Player Settings to embed a client-side JavaScript 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 or localhost.
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.

Top comments (0)