How to put your Ren'Py game in the browser
Ren'Py 8 has web support built into the Launcher, through the renpyweb platform. Open your project in the Launcher, use "Build Web Application" under "Web (Beta)" to produce a web.zip, then serve it from a real web server (not a double-clicked file) to test it. Web builds can't use threads, sockets, or most video, and audio needs one click before it plays. Once it works locally, zip it with index.html at the top and upload it to naughty.games.
Last checked
What you need
Ren'Py 8.x, with the current stable release being 8.5.3. Web support (the renpyweb platform) is built into the Launcher, so you do not need to install anything extra beyond the normal Ren'Py download. The first time you build for the web, the Launcher fetches the Web Platform Support files itself.
You'll also want:
- A finished, playtested build of your visual novel that runs correctly on desktop.
- A way to serve files over http:// for local testing. The Launcher can do this for you, so you don't need to set up your own server just to check a build.
- A sense of how big your assets are. Ren'Py web games are limited by download size in a way desktop builds are not, so a game with a lot of full-resolution backgrounds and long music tracks needs a plan for that (see "Common problems" below).
Ren'Py's web support does not cover everything the desktop engine does. There is no multi-threading (renpy.invoke_in_thread() is unsupported), no networking (sockets and the requests library are unavailable), and video is limited to renpy.movie_cutscene(). If your script leans on any of that, plan to cut or replace it before you export.
Export for the web
- Open your project in the Ren'Py Launcher and select it from the project list.
- Open the "Web (Beta)" section in the Launcher's left-hand menu.
- Click "Build Web Application". On the first run, Ren'Py downloads the Web Platform Support (renpyweb) files, which can take a few minutes depending on your connection. After that, it packages your project into a
web.zipfile and a matching folder of individual files, placed alongside your other build output. - If your game is image or audio heavy, open
progressive_download.txtin your project and mark large, non-essential files for on-demand loading instead of loading everything up front. Lines starting with-load at startup (this is where your GUI and first-screen assets belong); lines starting with+load in the background after the game has started, showing a pixellated placeholder for images and staying silent for music and voice until they're ready. - Rebuild after any script or asset change. The Launcher's Web section also gives you "Open in Browser" (reuse an existing build without repackaging) and "Open build Directory" (jump straight to the generated files) if you want to inspect what got produced.
There is no separate "web resolution" setting to worry about: Ren'Py scales your existing game window to fit the browser, so whatever screen size you already built for carries over.
Test it locally
Don't test a web build by double-clicking index.html. Browsers block a lot of what a Ren'Py game needs (loading the game data, playing audio, in some cases even displaying images) when a page is opened straight from the file system with a file:// address, and you'll get a blank screen or a page that never gets past loading.
The simplest fix is the Launcher's own "Build and Open in Browser" option: it packages your game and starts a small local web server for you, then opens the build in your default browser at a http://localhost address. That's enough to confirm dialogue, choices, saves, and any custom screens are behaving before you touch a real host.
If you'd rather serve the already-built files yourself, any one-line local server works, for example running python3 -m http.server from inside the build folder and opening http://localhost:8000 in your browser.
Zip it for upload
Ren'Py's own "Build Web Application" step already produces web.zip, and that's normally the file you want: unzip it and index.html sits at the top level, next to game.zip (the packaged version of your game/ folder) and the renpyweb runtime files. That layout matches what naughty.games expects: an HTML5 zip with index.html at the top.
A few things worth checking before you upload:
- Files over roughly 50 MB won't get cached by the browser between visits, so a returning player re-downloads them every session. Splitting a huge background or a long music track into smaller pieces, or compressing images harder, helps here.
- If a host rejects a file literally named
game.zip(some do, because they treat.zipinside a.zipas suspicious), Ren'Py lets you rename it, for example togame.data, as long as you update the reference to it that the Launcher wrote intoindex.html. - naughty.games accepts builds up to 250 MB unpacked and 2,000 files. A dialogue-only visual novel will rarely get close to that, but a VN with a lot of full-resolution CG art, animated sprites, or voice acting can. If you're near the limit, that's a sign to compress images, drop unused assets from
game/, or push more files into progressive download rather than the startup bundle.
Common problems
The page never loads, just shows a spinner or goes blank. Almost always this means the build was opened over file:// instead of a real server. Serve it locally the way described above, and make sure your final host serves it over http:// or https:// too.
Audio doesn't play when the game starts. This is expected, not a bug: browsers won't play sound until the player has interacted with the page once (a click, a tap, a keypress). Once they do, audio plays normally for the rest of the session.
The game freezes or throws an error on a line that worked fine on desktop. Check whether that line calls renpy.invoke_in_thread(), opens a socket, or otherwise touches something outside the web platform's supported feature set. None of that runs on the web, so it needs to be removed or reworked.
A video cutscene shows nothing. Web builds only support video through renpy.movie_cutscene(). Other ways of playing video in Ren'Py aren't available in the browser.
The build takes forever to start, or times out on a slow connection. This is the size problem again: move big, non-critical assets (extra CGs, background music variations, voice files for optional lines) into progressive download so the player sees the title screen quickly and the rest streams in behind it.
Saves seem to vanish. Web saves live in the browser's own storage, tied to the domain the game is hosted on. Moving the game to a new host, or a player clearing site data, wipes them. Point players who care about their save toward the in-game menu's option to export saves as a downloadable zip, which they can re-import later.
Publish it
Once your web build runs cleanly from a local server, it's ready for a real host. naughty.games hosts HTML5 games like this for free: upload the zip (index.html at the top level, up to 250 MB unpacked and 2,000 files), and review usually takes about 2 working days. Listing is non-exclusive, so keeping your game on itch.io or Steam alongside naughty.games is fine, there's no revenue share, and you keep 100% of whatever your own Patreon, SubscribeStar, Ko-fi, Steam, or itch links earn. We pick which games to promote by hand, looking at average time played, how many players come back the next day, and how many play past the first minute.
Head to /submit when your build is ready.
Questions
- What Ren'Py version do I need for a web build?
- Any Ren'Py 8 release has web support built into the Launcher. The current stable release is 8.5.3.
- Why is my game stuck on a blank or loading screen?
- You probably opened index.html straight from your file system. Web builds only work when served over http:// or https:// from a real web server, including the one naughty.games runs your build on.
- Can players save their game in a Ren'Py web build?
- Yes. Saves are kept in the browser, and the in-game hamburger menu lets a player export their saves as a zip and import them again later, for example on a different device.
- Does audio autoplay in a Ren'Py web build?
- No. Browsers block audio until the player interacts with the page once, so the first click or tap after the game loads is what starts sound.
- My game uses threads or sockets. Will it work on the web?
- No. renpy.invoke_in_thread() and networking calls like sockets or the requests library aren't supported on the web platform, so anything that depends on them needs to be removed or replaced before you export.
Sources
Free hosting, real players on phone and desktop, and a stats console.