Get 100 bonus credits with your first plan
Games
Pricing
←All posts

Godot·November 3, 2026·17 min read

Godot Web Export: How to Export a Godot 4 Game to HTML5

How to export a Godot 4 game to the web: templates, the Web preset, threads and SharedArrayBuffer headers, file size, audio, itch.io hosting and common errors.

To export a Godot 4 game to the web, install the export templates, add a Web preset under Project > Export, leave Thread Support off, and export to a file named index.html. Serve the folder from a web server or zip it for itch.io. Opening the HTML file by double-clicking won't work.

The short answer

  • Default to single-threaded. Since Godot 4.3 it's the default, needs no special headers and works on itch.io, Poki and CrazyGames.
  • Only turn on threads if you need them. They need two response headers and rule out ads and third-party integrations on the page.
  • Your game will use the Compatibility renderer (WebGL 2). Forward+ and Mobile don't exist on the stock web export, so test how it looks.
  • C# projects can't export to the web in Godot 4. GDScript can.
  • Audio starts after a click or key press. Put a start screen in front of the game.
  • Serve it compressed. Gzip takes the .wasm to about a quarter of its size, but not every host does that for you.

We make Oryn, which produces a web build of every game automatically, so weigh that. The rest of this guide applies to any Godot 4 project. It's based on the Godot 4.7 documentation as it read on November 3, 2026; we didn't run new export tests for it. Where a number comes from one developer's project, we say so.

Try this prompt in Oryn

“A one-screen 2D arcade game for the browser: a lighthouse keeper catches falling stars in a lantern before they hit the sea. A tap-to-start screen, three lives, a score counter, keyboard and touch controls.”

Build it in Oryn

Check these three things before you export

The language. Godot's docs say C# projects in Godot 4 can't currently export to the web, and suggest Godot 3 if you need C# in the browser. If you're still choosing, Godot vs Unity covers how this affects the decision, since Unity's web export does take C#.

The renderer. Godot 4 on the web can only target WebGL 2.0 through the Compatibility rendering method. The docs say Godot doesn't support WebGPU yet, which Forward+ and Mobile would require. A Forward+ project still exports, because the project setting rendering/renderer/rendering_method.web defaults to gl_compatibility. It just won't look the same, as covered below.

Native plugins. GDExtensions need to be compiled for the web specifically, and loading them needs Extensions Support and the same cross-origin headers as threads. A plugin written in pure GDScript has no such problem, so check your addons folder first.

How to export a Godot game to the web

  1. Install the export templates

    Open Editor > Manage Export Templates, tick the platform you need and click Install Selected Templates. You can also install from a TPZ file downloaded from the Godot website (exporting projects docs). If your game uses emoji or languages such as Chinese or Japanese, install the ICU Data option too. Templates must match your editor version.

  2. Add a Web preset

    Open Project > Export, click Add… and choose Web. The defaults suit most games. If templates are missing, the dialog shows an error and blocks the export until you fix it.

  3. Set the options that matter

    Leave Thread Support off unless you've read the next section. Tick VRAM Texture Compression > For Mobile if phones are a target; for a game that also targets desktop browsers, keep For Desktop on as well. Enabling both gives a bigger but more compatible export.

  4. Export to an empty folder as index.html

    Click Export Project and name the file index.html, since web servers load that by default. You get several files side by side: .html, .js (startup code), .wasm (the engine), .pck (your game) and .png (the boot splash). Keep the names you exported with, because the docs warn that renaming them can cause problems.

  5. Test it on a local server

    Save Godot's serve.py into the export folder and run python serve.py --root .. It sends the two cross-origin headers, so threaded builds work too. It's for testing only; the docs say to use a server such as Apache or nginx in production. If a runnable web template is installed, the editor also shows a button near the play controls that opens the game in your default browser.

  6. Open the browser console

    Press F12, or Ctrl + Shift + I (Cmd + Option + I on macOS), to see JavaScript, engine and WebGL errors. Godot may capture those shortcuts while the game has focus. If so, open the developer tools from the browser's menu.

To export from a build script, name the preset and output path. The output directory has to exist already (command line docs).

godot --headless --path path/to/project --export-release "Web" build/web/index.html

Threads or no threads

Threaded web builds use SharedArrayBuffer, and browsers restricted that API after the Spectre and Meltdown exploits. Godot's 4.3 web export report says the team "bet on the wrong horse" by going all-in on threads, and then brought single-threaded exports back. That's now the default, and the docs call it the preferred way to export.

Single-threaded (default)Thread Support on
Headers neededNoneCOOP and COEP, over HTTPS or localhost
Ads and third-party integrations on the pageAllowedRuled out by cross-origin isolation
itch.io, Poki, CrazyGamesWorks better, per the docsNeeds extra setup, or may not work
macOS and iOS browsersWorks well, per the docsLong history of compatibility issues
PerformanceLower; no threadsHigher
Audio latencyLow with default Sample playbackLow with Stream playback too

Go threaded if profiling shows your game needs the performance and you control the server. Otherwise stay on the default.

The headers for a threaded build

The server has to send exactly these two response headers, from a secure context (HTTPS, with localhost usually exempt):

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Without them, or the workaround below, the docs say the project won't run. Here's a sample nginx block with compression:

location /game/ {
    add_header Cross-Origin-Opener-Policy "same-origin" always;
    add_header Cross-Origin-Embedder-Policy "require-corp" always;
    gzip on;
    gzip_types application/wasm application/octet-stream application/javascript;
}

Hosts that read a _headers file take this form, at the root of the published folder (Netlify, Cloudflare Pages):

/*
  Cross-Origin-Opener-Policy: same-origin
  Cross-Origin-Embedder-Policy: require-corp

If you can't set headers at all, tick Progressive Web App > Enable in the export options. Its service worker simulates them, with Enable Cross Origin Isolation Headers on, and still needs HTTPS. It also makes the game installable and able to load offline after the first visit, and adds the stale-build problem listed under errors.

Compatibility renderer: what changes on the web

If you built in Forward+, expect your game to look different in the browser. Export early, because lighting and environment may need manual changes when you move to or from Compatibility, and that gets more expensive the later you find out.

These are marked unsupported in Compatibility on the renderers page, as of Godot 4.7:

  • SDFGI and VoxelGI global illumination
  • Screen-space reflections and SSIL
  • Volumetric fog
  • Depth of field blur
  • TAA and FSR2
  • Particle trails and particle SDF collision

SSAO and glow are supported. OmniLights and SpotLights are limited to 8 per mesh by default (Forward+ allows 512 per cluster), and you can raise that. To preview all of this without exporting, click the renderer name at the top right of the editor and switch your project to Compatibility, or start new web-first projects there.

Safari is the browser to test separately. The docs say it has WebGL 2.0 issues that other browsers don't, and they recommend Chromium-based browsers or Firefox.

File size and load time

A web player downloads everything before the game starts, so size affects whether they stay. Two sets of numbers from real exports give a rough baseline, and neither is an official figure:

  • One Godot 4.3 user reported a 35 MB .wasm and a 56 MB .pck.
  • One developer's test of a tiny 2D project measured a default web export of 42.0 MB, or 8.72 MB zipped, on Godot 4.4.

In order of effort, here's what helps.

Turn on compression at the host. This is the largest single gain. The docs say the .wasm goes down to around a quarter of its size with gzip, and that Brotli precompression can save more. GitHub Pages gzips on the fly. The docs list itch.io and GitLab Pages as hosts that don't, though GitLab accepts files you gzip yourself. Serve .wasm as application/wasm, because another MIME type can prevent startup optimizations, and .pck as application/octet-stream.

Shrink the .pck. That's your game's content, so it's the file you have direct control over. Exclude editor-only and source files with the Resources tab's filters in the export preset, and look at your largest textures and audio tracks first. Only enable the VRAM compression formats your targets need, since each format adds data.

Compile a custom template. This is the big step for the engine itself, and the docs recommend it for mobile load times. On Optimizing a build for size, the main switches are disable_3d=yes (about 15% smaller, for 2D games only), disable_advanced_gui=yes and a build_profile generated by the editor's engine compilation configuration tool. The profile can be too aggressive about features only created at runtime, so test afterward. The web already compiles for size by default, so optimize=size won't save much there.

That same test went from 42.0 MB to 17.4 MB after stacking these options, ending with a compilation profile. Zipped, that was 3.70 MB, and Brotli brought it to 2.70 MB. Its project was close to a best case, with a bouncing sprite and one label, so expect less from a real game. You'll need Emscripten and a working build setup; Compiling for the Web has the steps, and you point the preset's custom template field at the result.

Audio and the user-gesture rule

Browsers restrict sound that starts by itself. The docs' fix is to ask the player to click, tap or press a key first, typically on a splash or title screen. So make your first scene a start button, and begin the music after it:

func _on_start_button_pressed():
    MusicPlayer.play()
    get_tree().change_scene_to_file("res://game.tscn")

MusicPlayer here is an autoload, so the track keeps playing through the scene change.

The second audio surprise is the playback mode. Since 4.3, web exports play sound as Web Audio samples by default, which keeps latency low without threads and prevents garbled audio in single-threaded builds. In that mode:

  • AudioEffects don't work, including effects on audio buses.
  • Reverb and doppler don't work.
  • Procedural audio generation doesn't work.
  • Positional audio may misbehave, depending on the node's properties.

If your game relies on these, set Audio > General > Default Playback Type.web to Stream, or set Playback Type to Stream on a single AudioStreamPlayer, AudioStreamPlayer2D or AudioStreamPlayer3D. You get the full feature set back at the cost of more latency, especially without threads. Setting only the node that needs an effect keeps the rest of the game on samples.

For the music itself, see our guides to royalty-free game music and AI game music and sound.

Mobile browsers

Web builds run on phones with caveats. The docs say native Android and iOS exports perform far better, and that WebAssembly adds overhead on hardware that's already constrained. The upside is that players skip the app store. If you can ship native as well, how to make a mobile game covers that route.

To make the web version hold up on phones:

  • Lower settings for mobile browsers. Godot has feature tags for the OS behind the browser, checked at runtime:

    var mobile_web := OS.has_feature("web_android") or OS.has_feature("web_ios")
    
  • Compress for mobile GPUs. Tick For Mobile in the preset, and if the export dialog asks for it, enable Import ETC2 ASTC under Project Settings > Rendering > Textures > VRAM Compression. It's off by default.

  • Handle touch. emulate_mouse_from_touch is on by default, so buttons respond to taps, but anything using key presses needs on-screen controls. For text input on phones, there's an experimental option in the preset, html/experimental_virtual_keyboard.

  • Set a stretch mode. The canvas matches the browser window by default, so phone screens and rotation will change your layout. Godot's multiple resolutions guide covers the settings, and Canvas Resize Policy gives you fixed-size control when you want it.

  • Watch memory on Safari. Godot's 4.3 report noted that even its Platformer 2D demo could trigger Safari's "this webpage is using significant memory" reload. Test on a real iPhone.

To lock orientation for players who add the game to their home screen, use the PWA options, which include an orientation setting.

Where to host it

HostCompressionCustom headersLimits to know
itch.ioNone on the fly, per Godot's docsExperimental opt-in settingReported at 1,000 files, 500 MB total, 200 MB per file
GitHub PagesGzipUse the PWA workaround1 GB site, 100 GB a month soft limit
NetlifyNot checked_headers fileNot checked
Cloudflare PagesNot checked_headers file25 MiB per file, 20,000 files on the free plan
Your own serverYou configure itYou configure themYours

itch.io

Zip the export folder's contents so index.html sits at the top level, since itch's HTML5 guide says the zip must contain a file called index.html. Upload it, set the project's kind to HTML, mark the upload as playable in the browser, and set the embed size to your game's resolution.

Single-threaded builds need nothing more. For a threaded build, the project's embed options have a SharedArrayBuffer support checkbox (itch.io announcement). Treat it as a partial fix: itch labels it experimental, and Godot's report says it relies on a feature that Safari and Firefox for Android don't support.

We couldn't load itch's guide when writing this, because the page blocked our fetch. The limits in the table come from a guide to web game platforms and a forum thread, so check them against the official page before a big upload. That same third-party guide says hosted paths are case-sensitive, which matches the Godot warning below.

GitHub Pages, Netlify and Cloudflare Pages

For a single-threaded build, any static host works: upload the folder and share the link. GitHub Pages is the easiest free route, with a 1 GB limit on published sites.

Cloudflare Pages has a catch for Godot specifically. Its maximum file size is 25 MiB, so a stock .wasm reported at 35 MB wouldn't fit, and neither would a larger .pck. Cloudflare's suggestion for larger files is to store them in R2, and a custom template can also bring the engine under the limit.

Web game portals

The docs say single-threaded export is more compatible with publishers such as Poki and CrazyGames. Each portal has its own submission rules and SDK requirements, which we didn't review. Because threaded builds rule out third-party integrations on the page, plan on single-threaded if a portal or ad network is your target.

Common Godot web export errors and fixes

Missing export templates or a blocked Export button. Install the templates for your exact editor version under Editor > Manage Export Templates. Custom engine builds need custom templates.

"The following features required to run Godot projects on the Web are missing: Cross Origin Isolation, SharedArrayBuffer." You'll find this one all over the forums (example thread). The build expects threads and the host isn't sending the headers. Turn off Thread Support and export again, which is the right fix for most games. If you're on Godot 4.0 to 4.2, upgrade to 4.3 or newer to get single-threaded export. Otherwise add the headers, use the PWA option or tick itch's checkbox.

Blank page or CORS errors when opening index.html from disk. Browsers treat local files as opaque origins, so loading the game's other files fails on file:/// URLs. Run a local server.

Missing files that worked in the editor. Godot's PCK virtual filesystem is case-sensitive, while Windows and macOS usually aren't, so res://Player.png and res://player.png behave differently after export. The docs recommend snake_case for all files. Files that Godot doesn't import, such as a JSON data file, also need adding to the preset's non-resource filter.

Dark or different-looking 3D. That's the Compatibility renderer. Rebalance lighting and environment with the project switched to Compatibility, and replace the unsupported effects listed above.

The export is blocked because the project uses C#. The docs offer no Godot 4 route. Port the scripts to GDScript or use Godot 3.

No sound. The browser is waiting for a user gesture, so add a start screen. If sound plays but effects don't, you're on Sample playback; see the audio section.

An old version of the game keeps loading. With PWA or one-click deploy, a service worker can serve a previous build, and sometimes even a different project. In developer tools, go to the Application tab, then unregister the service worker and reload (docs).

Saves disappear. user:// lives in IndexedDB. Players must allow cookies, games in an iframe, as on many portals, need third-party cookies too, and private browsing doesn't persist. OS.is_userfs_persistent() can check this, though the docs warn it may give false positives. Tell players when a save might not stick.

Fullscreen or mouse capture does nothing. Browsers only allow these in response to an input event, so do it inside the callback. Checking the Input singleton in _process isn't enough:

func _unhandled_input(event):
    if event.is_action_pressed("toggle_fullscreen"):
        DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)

The fullscreen project setting has the same problem at startup, and only a custom HTML shell can work around it.

Gamepad isn't detected. Gamepads don't appear until a button is pressed, they need a secure context, and mappings can be wrong because the browser can't reliably identify the model. Show a "press any button" prompt.

The game stops when I switch tabs. The browser pauses the project in an inactive tab, so _process() and _physics_process() stop, and networked games may disconnect. A separate, unfocused window keeps running.

Multiplayer or HTTP calls fail. Low-level networking isn't available. You have the HTTP classes, WebSocket (client) and WebRTC, and HTTP is subject to the same-origin policy, with no chunked responses or blocking mode. Calls to your own API from another domain need CORS on that API.

My edits to the HTML are gone. Godot regenerates the HTML page on each export. Use Custom HTML shell or Head Include in the preset, as described in Custom HTML page for Web export.

Once it runs on your host, test the final link in Chrome, Firefox and Safari on a computer, then on one Android phone and one iPhone. To see what the engine has shipped, look through games made with Godot.

Frequently asked questions

Can Godot 4 export to HTML5?

Yes. Godot's Web export produces an HTML page, a WebAssembly engine and a .pck of your game, and it needs WebAssembly and WebGL 2.0 in the player's browser. GDScript projects export normally. C# projects can't export to the web in Godot 4 as of the 4.7 docs.

Why doesn't my Godot web game work on itch.io?

The most common cause is a threaded build, which shows an error about Cross Origin Isolation and SharedArrayBuffer. Turn off Thread Support and export again, using Godot 4.3 or newer. Also check that index.html sits at the top level of your zip.

Do I need SharedArrayBuffer for a Godot web export?

Only if you enable Thread Support or Extensions Support. Those need the Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp headers. The default single-threaded export since Godot 4.3 needs neither.

Does Godot web export support Forward+ or WebGPU?

Stock Godot doesn't. The 4.7 docs say Godot can only target WebGL 2.0 through the Compatibility renderer and doesn't support WebGPU yet, so a Forward+ project exports using Compatibility. Features such as SDFGI, volumetric fog and screen-space reflections aren't available there.

How do I make a Godot web export smaller?

Serve it with gzip or Brotli first, since gzip takes the .wasm to about a quarter of its size. Then cut large textures and audio from the .pck, and if you need more, compile a custom web template with unused engine features disabled. One developer's small 2D test went from 42.0 MB to 17.4 MB that way.

Do Godot web games work on phones?

Yes, with lower performance than native exports. Enable VRAM compression for mobile, add touch controls and a tap-to-start screen, and test on real devices, especially Safari on iPhone. Use the web_android and web_ios feature tags to lower settings at runtime.

Previous

How to Make Game Music: Themes, Loops and Godot Import

Next

Godot Assets: Free Sources and Import Settings for Godot 4

Don't pick a model. Just ask Oryn.

Art, 3D models, music and sound effects: Oryn picks the right model for each and builds a playable game around them, for desktop and mobile.

Make my game

On this page

  • Check these three things before you export
  • How to export a Godot game to the web
  • Threads or no threads
  • Compatibility renderer: what changes on the web
  • File size and load time
  • Audio and the user-gesture rule
  • Mobile browsers
  • Where to host it
  • Common Godot web export errors and fixes
  • Frequently asked questions

Don't pick a model. Just ask Oryn.

Art, 3D models, music and sound effects: Oryn picks the right model for each and builds a playable game around them, for desktop and mobile.

Make my game
GamesGuidesBlogComparisonsTools3D game maker2D game makerMobile game makerHorror game makerPlatformer makerAI RPG makerPuzzle game makerIdle game makerGodot AIReviewsAffiliatesFAQPricingTermsPrivacyGuidelinesWithdraw from contractCancel contracts hereImprint
.dev
Made with love in Mannheim, GermanyMade within Mannheim, Germany

Cookies and analytics

With your permission, PostHog and our own MRRocket, both in the EU, measure usage and record masked interactions for session replay. Text, inputs and media are masked or blocked; cookies are used. You can decline or withdraw in Cookie settings. Oryn works the same without this. With your permission, the ad platforms Reddit, Meta, Google Ads also learn whether you came from one of our ads and signed up or paid. Privacy notice