Godot Web Export Basics: Make Your Game Playable in the Browser and Put It on itch.io

Created: 2026-09-22Last updated: 2026-10-10

How to export a Godot game in a form people can play in the browser, check it locally, and then put it on itch.io.

When you want people to play your game, the easiest form is one they can play just by opening it in a browser. With Godot's Web export and itch.io (a site where you can publish indie games for free), all you have to hand over is a URL.

But double-clicking the exported index.html doesn't start the game, and just uploading a zip to itch.io shows only a download button on the page. What you hand over for the Web isn't a file but a page, so where and how you place it becomes part of how it runs.

This article explains how to confirm it runs in your local browser first, then put it on itch.io.

A browser opened via file:// is blank white; opened via http://localhost:8060, a Japanese label and a square are displayed

What You'll Learn

  • The set of files a Web export produces
  • Why it won't open via file://, and how to run it locally
  • The three settings on itch.io, and how to test while keeping it private
  • Three browser-specific limits (sound, key input, fonts)

Tested with: Godot 4.7

Sponsored

The files a Web export produces

For Windows, you get two files, an .exe and a .pck (one if you turn on Embed PCK). For the Web, you get a row of files prefixed with the name you chose for the export target.

If you set the export target to index.html, you get something like this.

index.html                         What the browser reads first
index.js                           Code for starting up
index.wasm                         The engine itself
index.pck                          The game's data
index.audio.worklet.js             Audio processing
index.audio.position.worklet.js    Audio processing
index.png / index.icon.png / index.apple-touch-icon.png   Boot splash and icons
Windows gives two files, exe and pck, but the Web gives a whole set of files headed by index.html that belong together

This set belongs together. When distributing, include every file produced by that export. If a required file is missing, it may fail to start, or only the sound may fail.

There's a reason to name the export target index.html. Many hosts read index.html first when a folder is opened. When you put a zip on itch.io, this name is also the entry point.

For rendering, only Compatibility works on the Web. Forward+ and Mobile don't run. Project Settings → Rendering → Renderer → Rendering Method has a separate .web field, which is set to gl_compatibility (that is, Compatibility) from the start. Even if you develop in Forward+ day to day, the Web build is exported with this field's setting. Lighting and shadows are drawn the Compatibility way, so 3D can look different from the editor.

General export topics, and reinstalling templates when a preset turns red, are in Export Basics.

Running it in your local browser (Run in Browser)

Double-click the exported index.html, and the browser opens, but the game doesn't start. Sometimes it stays white; sometimes an error appears. Look at the address bar, and it starts with file://.

file:// means you opened a local file directly; http:// means it was served from a host called a server. In the file:// state, the browser can't fetch the .wasm or .pck sitting next to it. The browser distinguishes between opening something as a file and having it served from a host.

In other engines: Unity's Web build (WebGL) is also normally run through a web server rather than opened directly via file://. Unity's Build And Run starting a local web server plays the same role as Godot's Run in Browser. Unreal Engine 5 has no built-in browser export.

With file://, the arrows from the browser to index.wasm and index.pck are blocked; with http://, they all connect

To check locally, run it from the editor. Create one Web preset (settings per export target) and turn on Runnable (the setting that lets you launch it directly from the editor), and a Web item appears between the stop and run buttons. Choose Run in Browser from there, and a built-in server starts and a browser opens. By default, it's http://localhost:8060/tmp_js_export.html.

What's running here is something the editor re-exported to a temporary folder. It's separate from the index.html in the export folder you saved. It's a tool for first checking whether the game runs on the Web; check the files you'll distribute after uploading the zip.

Turn on Runnable in the Web preset and choose Run in Browser from the run buttons, and a browser opens

Check every time whether the address bar says file://. When you get a white screen, look here first.

Sponsored

Three settings on itch.io

Create an account and set up a new project page. Choosing HTML for Kind of project on the creation screen lines up the settings that follow. The zip to upload is made by selecting every file inside the export folder and compressing them. If you compress the folder itself, index.html ends up one level deeper when the zip is opened. Make sure index.html is visible at the top level of the zip.

Run in Browser only re-exports to a temporary folder and opens it locally. What you distribute is the Export Project folder, zipped so index.html is visible at the top level

From there, you touch three places.

What you touch on itch.io: the play-in-browser checkbox, the width and height in Embed options, and the Draft visibility setting
  1. Upload the zip under Uploads and tick This file will be played in the browser. Without it, the other person downloads it, opens it locally, and ends up at the blank file:// page from before
  2. Decide how it's displayed and its dimensions in Embed options. To embed it in the page, enter the width and height. If you've set Stretch to canvas_items and keep (settings that stretch the whole screen while keeping the aspect ratio) as in the hands-on, even smaller numbers with the same aspect ratio as the game shrink it while keeping the ratio
  3. Set the visibility to Draft, and it isn't public. Change it once you're ready to show people

Check from the page view, not the edit screen. The embed first shows itch.io's launch button (Run game); press it and the game starts.

The first input, sound, and key input

Browsers have a mechanism that doesn't play sound until the user interacts. It's there to keep music from blaring the moment a page opens.

Godot tries to resume audio when it receives a key press or click. Even so, sounds played before any input either never play or are heard late. If your game plays a sound effect in _ready(), the results differ between the Windows build and the browser.

A sound play()ed in _ready() comes before the click and is blocked; a sound played after the click gets through

Play the first sound you want heard in response to an action, such as pressing a start button.

The keyboard is similar. A game embedded in a page may not receive input until you click the screen. If pressing the arrow keys scrolls the page instead, the game isn't receiving input yet. Clicking the screen once fixes it.

Japanese fonts in the Web build

When running on a PC, the OS's fonts fill in glyphs the font doesn't have. That's why Japanese text shows up just by putting it in a Label. How relying on that fallback makes the typeface change from system to system is covered in Japanese Font Basics. The same applies to any characters the default font doesn't cover, such as Chinese or Korean.

That fallback isn't available on the Web. In the same project, the characters turn into boxes only in the browser.

The PC build is readable because the OS font fills in missing glyphs, but the Web build has no fallback and shows boxes

The fix is to put a Japanese font file in the project folder and assign it. For a single Label, use Font under Theme Overrides; for the whole project, set Project Settings → GUI → Theme → Custom Font. Just adding the file doesn't make it used.

Sponsored

Hands-On: Check four things in your local browser

A game jam submission, a test request to a friend, a portfolio — the first step for all of them is getting it "running in your own browser." You can check up to here even without an itch.io account. Check these four things.

  • Whether the address is http://
  • Whether the Japanese text is readable
  • Whether sound plays and the square moves after input
  • Whether the Japanese text turns into boxes when you remove the font

① What to place

Create one new scene. The label deliberately uses Japanese so you can see the font issue for yourself.

  • In Project Settings → Display → Window → Size, set Viewport Width to 1280 and Viewport Height to 720
  • In the same place, set Stretch → Mode to canvas_items and Aspect to keep (stretches the whole screen to the window while keeping the aspect ratio)
  • Prepare one Japanese font (.ttf or .otf) that's licensed for distribution and copy it into the project folder. Free fonts like Noto Sans JP are easy to work with
  • Put a Node2D at the root named Main. Attach main.gd, save it as main.tscn, and set it with Set as Main Scene from the FileSystem dock's right-click menu
  • Add a ColorRect as a child of Main at position (540, 310), size (200, 100). Set Filter in the Mouse group to Ignore (so clicks on the square aren't grabbed by the square and reach the script)
  • Add a Label as a child of Main named MessageLabel. Position (480, 200). Set its text to 「クリックかスペースで始めます」 ("Click or press Space to start")
  • In MessageLabel's Inspector, set Theme Overrides > Fonts > Font to the font file you added
  • Add an AudioStreamPlayer as a child of Main named ClickSound. Put a short sound file in Stream
  • For ColorRect and MessageLabel, turn on "Access as Unique Name" from the right-click menu (this lets you get them by name alone, like %ColorRect)

If you forget to set the font, the characters turn into boxes when you check the Japanese text.

# main.gd
extends Node2D

const SPEED := 400.0

var _started := false

@onready var box: ColorRect = %ColorRect
@onready var label: Label = %MessageLabel
@onready var sound: AudioStreamPlayer = $ClickSound

func _unhandled_input(event: InputEvent) -> void:
	if _started:
		return
	if not event.is_pressed() or event.is_echo():
		return                            # Don't count releases or held-key repeats
	if event is InputEventMouseButton:
		if event.button_index != MOUSE_BUTTON_LEFT:
			return                        # Don't start from the mouse wheel
	elif event is InputEventKey:
		if event.keycode not in [KEY_SPACE, KEY_ENTER]:
			return
	else:
		return
	_started = true
	sound.play()                          # Play the first sound in response to input
	label.text = "動いています"            # "Running" (Japanese on purpose, to test the font)

func _process(delta: float) -> void:
	if not _started:
		return
	box.position.x += Input.get_axis("ui_left", "ui_right") * SPEED * delta

② Export

Open Project → Export... and choose Web from Add.... If the preset is red, the templates aren't installed, so install them following the steps in Export Basics.

  • Turn on the preset's Runnable
  • Leave Options → Variant → Thread Support off (turning it on requires extra settings on the host; covered in the bonus section)
  • Press Export Project..., choose a new empty folder, and name the file index.html

Open the exported folder, and you'll see files starting with index. It's tempting to double-click index.html here, but that's the first mistake.

Go back to the editor, choose the Web item from the run buttons, and run Run in Browser. What runs here is re-exported to a temporary folder, but it tells you whether the game runs on the Web.

③ Run it and check

Before starting, the label 「クリックかスペースで始めます」 and the square are visible; clicking or pressing Space plays a sound, the label changes to 「動いています」, and the square moves

When the browser opens, look at the address bar first. If it starts with http://localhost:8060/..., it's being served from a host. If it's file://, you've opened the index.html in the export folder.

In the center of the screen is a square, and above it you can read 「クリックかスペースで始めます」 in Japanese. If you see a row of boxes, the font setting isn't getting through.

Left-click the screen or press Space, and a sound plays and the label changes to 「動いています」 ("Running"). After that, the left and right keys move the square. Before starting, pressing left or right does nothing. If there's no sound, also check whether the browser tab is muted.

Finally, remove the font in just one place. With no Japanese font set in the theme or project settings, clear MessageLabel's Theme Overrides → Fonts → Font and open it again with Run in Browser. The Japanese that was readable when you pressed F5 in the editor turns into boxes in the browser. It was readable on the PC because the OS font was filling in, and this one change shows that the Web has no such fallback. Once you've checked, put the font back.

If you have an account, upload to itch.io from here. What Run in Browser showed was re-exported to a temporary folder, so if you fixed anything while checking, first re-export with Export Project.... Then select every file inside the export folder, zip them, upload to Uploads, and tick This file will be played in the browser. Enter width 1280 and height 720 in Embed options, keep the visibility at Draft, view the page, press Run game, and check the same things. The address is https://. In the embed, click the game screen first. Before you click, the arrow keys are used to scroll the page.

There are two key points.

  • Resist the urge to open it right after exporting: Double-clicking index.html almost always gives you a white page. Do your first check with the editor's browser run
  • Pass all four locally before uploading: When itch.io shows a white page, you can tell whether the cause is the game or how it's placed. If it runs locally, suspect three things: whether you re-exported, the play-in-browser checkbox, and Thread Support

General export settings are in Export Basics, and what to decide when starting a project with the Web in mind is in Initial Project Setup.

Troubleshooting

SymptomCauseFix
Fixed locally, but itch.io still has the old versionOnly Run in Browser's temporary folder is new; the export folder you distribute is still the old oneRe-export with Export Project... before zipping
Runs locally, but only itch.io shows whiteWith Thread Support on, the host needs extra settingsRe-export with it off and first check whether it runs
Scrollbars appear or the aspect ratio breaks on itch.ioThe width and height in Embed options don't match the game's screen sizeFirst set them to the same dimensions as the game (1280×720). If that doesn't fix it, also check Godot's Stretch settings
The preset is red and you can't export to the Web even after reinstalling templatesThe 4.7 .NET editor can't export to the WebIf the project is GDScript only, open it in the standard editor and export

Bonus: Good to Know First

  • Leave Thread Support for when you need it: Turning it on requires a mechanism called SharedArrayBuffer on the browser side, and the host server has to return certain headers. itch.io has a setting for this, but ship with it off first and consider it only once performance becomes a problem
  • Loading is slow because of size: The engine alone is tens of megabytes. At first, it's enough to leave out long wav files and large unused images, and not to add several weights of a Japanese font
  • Web saves live in a different place: user:// is placed in storage the browser keeps for that site. It's separate from saves made when running in the editor, and clearing the browser's site data deletes it
  • Web-only differences: You can check whether it's the Web build with OS.has_feature("web"). Use it for small differences, like hiding the Quit button on the Web
Sponsored

Summary

  • What comes out is a set: All the files headed by index.html belong together. When distributing, gather the whole set into a zip
  • It won't run via file://: To view locally, use the editor's Run in Browser. Check every time that the address bar says http://
  • Three places to touch on itch.io: The play-in-browser checkbox, the embed dimensions, and the visibility setting
  • Sound and keys come after input: Play the first sound in response to a click or key, and in embeds, click the game screen first
  • Add a font for Japanese: The Web has no OS font fallback

When you first open your game in a browser, where will these differences show up?

Read nextOn to Networking
Networking

Godot LAN Multiplayer Basics: Connect Over the Same Wi-Fi So Each Player Moves Their Own Character

Read this note
Godot Notes in this section104