Godot guide · · 8 min read
Exporting a Godot 4 game to the web for itch.io
The Godot 4 web export settings we use for itch.io: threads off, no SharedArrayBuffer, Compatibility renderer, index.html, zipping, embed size and mobile.

One web preset per game, named Web (itch.io)
Several of our Godot 4 games can be played in the browser on itch.io: Burger Stack, Mine Fever, Tidy Tiles and Hearthtide from our mobile line, plus the Thalorra and GRAVENTH demos. Each game has its own Web export preset next to the iOS, Android and desktop presets, named Web (itch.io) (Web Demo (itch.io) for GRAVENTH), so a browser build never borrows settings from a store build by accident.
In the mobile games the browser tweaks live on a separate itch-web branch. That branch holds the preset and a handful of code changes, which keeps the store versions untouched. This article walks through the exact options in those presets, using the names you will find in export_presets.cfg.
Threads off, so no SharedArrayBuffer on itch
The most important line in all of our web presets is variant/thread_support=false. Godot's documentation explains that only threaded web exports use SharedArrayBuffer, which needs the page to be served with the Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp headers. Without them, a threaded build does not start at all. Since Godot 4.3 a single-threaded export is available and is the default, and the docs note that it also works well on macOS and iOS.
itch.io offers a SharedArrayBuffer support checkbox under Embed options, Frame options, which adds those headers for you. itch describes it as experimental and lists side effects: requests to other domains fail by default and iframe embeds stop working on the page, including YouTube videos in comments. Because our presets leave threads off, we leave that checkbox unticked and skip the whole problem: itch.io/t/2025776/experimental-sharedarraybuffer-support
The trade-off is audio and heavy background work. On the web Godot defaults audio to Sample playback (audio/general/default_playback_type.web), which keeps latency low without threads but does not support AudioEffects. If your game depends on bus effects, test them in the browser build early. Sample playback also decodes each sound fully into memory: in Hearthtide that failed for the long music tracks and froze the game, so in the browser build the music players switch to AudioServer.PLAYBACK_TYPE_STREAM while short sound effects stay as samples. We also keep variant/extensions_support=false: GDExtensions need their own web builds and also require cross-origin isolation.
- variant/thread_support=false: runs on itch.io without special headers.
- variant/extensions_support=false: no GDExtensions in the browser build.
- SharedArrayBuffer support on itch: only needed if you turn threads on.
- Turn threads on only if you measured a real need, then test Chrome, Firefox and Safari.
GL Compatibility is the web renderer
Godot 4 targets WebGL 2.0 in the browser, so web builds use the Compatibility rendering method; Forward+ and Mobile are not supported on the web. Burger Stack, Mine Fever and GRAVENTH are set to gl_compatibility everywhere (renderer/rendering_method and renderer/rendering_method.mobile), so the browser shows exactly what players see on their phones.
Thalorra is the counter-example. It uses Forward+ on desktop and relies on rendering/renderer/rendering_method.web, which defaults to gl_compatibility. That works, but lighting, glow and shaders can look different from the desktop build, so we review the web version on its own instead of assuming it matches.
Texture compression is the other renderer-related choice. Our mobile games export with both vram_texture_compression/for_desktop and vram_texture_compression/for_mobile enabled, because players open them on laptops and phones. Godot's docs say this gives a bigger but more compatible export. The two PC demos keep only the desktop option to save download size.

Export to index.html, then zip the contents
Each preset exports to a file called index.html in its own folder, for example builds/itch/burger-stack/index.html. Godot recommends index.html as the file name and warns that renaming exported files, including the main HTML file, can cause problems. itch.io also requires a file called index.html in the ZIP, because that is the page players see.
A typical export is nine files: index.html, index.js, index.wasm, index.pck, two audio worklet scripts and three icons. We zip those files directly, not the folder around them, so index.html sits at the top of the archive. itch.io limits a ZIP to 1,000 files, 500 MB extracted and 200 MB per file, and file names are case sensitive.
Two habits keep the folder clean. We export outside the project or put an empty .gdignore file in the build folder, so the editor does not import the exported icons and PNGs back into the project. And we use exclude_filter to leave out folders the browser never needs, such as tests, tools, docs, android, ios and the sample files of mobile plugins.
Inside the game, mobile-only features are wrapped in OS.has_feature("web"). In the browser our games show no ads and no in-app purchases, the Restore button and the haptics toggle are hidden, and paid items are clearly marked as available in the mobile app. Fonts need a check too: in the browser there is no system font to fall back on, so a symbol missing from your bundled fonts simply does not appear. For Hearthtide we added a small symbol font as a fallback in the web build.
Viewport size, fullscreen and the HTML options
All our web presets use html/canvas_resize_policy=2, the Adaptive policy, which resizes the canvas to fill as much of the page as possible. Combined with window/stretch/mode="canvas_items" and window/stretch/aspect="expand" in our mobile games, the game fills whatever frame itch.io gives it.
On itch.io we pick Embed in page and enter the viewport dimensions. Match the aspect ratio of your game. Thalorra has a 640x360 base resolution with integer scaling, so its embed is 1280x720, exactly twice the base size, with fullscreen enabled: mekai-games.itch.io/thalorra. If your game has no fullscreen button of its own, itch.io can generate one for you.
The remaining HTML options are small but useful. html/focus_canvas_on_start=true lets keyboard input work without an extra click. html/head_include adds a short style tag that paints the page background in the game's color, for example a dark green behind Burger Stack and black behind GRAVENTH, so the edges never flash white. html/export_icon=true uses the game icon as the favicon. progressive_web_app/enabled stays false, because itch.io hosts the page for us.
Mobile browsers, file size and loading
If you tick Mobile Friendly in the itch.io embed settings, phones always open the game with Click to launch in fullscreen, whatever embed mode you chose for desktop. Godot's documentation reminds you that CPU and GPU performance is at a premium on mobile, even more so with WebAssembly, and that Safari has WebGL 2.0 issues other browsers do not. We test every web build on a real phone before making it public, and we keep html/experimental_virtual_keyboard=false because our games have no text fields.
Most of the download is the engine itself. In our builds index.wasm is about 38 MB, the same for every game, while index.pck goes from under 3 MB for Tidy Tiles to about 39 MB for Hearthtide. In the ZIP the wasm file shrinks to about 9 MB, roughly a quarter of its size, while the pck barely shrinks because its textures are already compressed. To make a web build lighter, work on the pck: smaller textures, fewer unused assets and a tight exclude_filter.
itch.io's documentation says its CDN applies GZIP to uncompressed .wasm, .pck, .js and .html files automatically, so we upload the files exactly as Godot exports them. Players still need a moment for the first load, so leave Click to play on for anything bigger than a small prototype.
Our Godot web export checklist for itch.io
This is the list we go through before every browser upload.
- Separate preset named Web (itch.io), with its tweaks on its own branch.
- variant/thread_support=false and variant/extensions_support=false.
- Renderer set to gl_compatibility, or rendering_method.web checked if desktop uses Forward+.
- vram_texture_compression/for_desktop on; for_mobile on too if phones will play it.
- Export path ends in index.html; exported files are never renamed.
- Build folder outside the project or marked with .gdignore.
- exclude_filter drops tests, tools, docs and mobile-only folders.
- Ads, purchases and other store features hidden behind OS.has_feature("web").
- Long music tracks set to stream, and every symbol checked against the bundled fonts.
- html/canvas_resize_policy=2 (Adaptive) and html/focus_canvas_on_start=true.
- ZIP the folder contents so index.html is at the top level.
- On itch.io: Embed in page with the game's aspect ratio, fullscreen button, Mobile Friendly.
- SharedArrayBuffer support left off, since the build has no threads.
- Test on desktop Chrome, Firefox and Safari, and on a real phone, before publishing.