Share a private Godot web build with playtesters.

To share a Godot web build that only invited playtesters can open, put the entire Web export behind a login with an explicit allowlist. A shared password lets in anyone who knows it; an unlisted URL with noindex lets in anyone who has the link. Protect the HTML, JavaScript, WebAssembly and game data files, not just the launch page.

By Daniel Ginovker ·

If you’re emailing a playable demo to a publisher, investor or closed playtest group, decide what happens when someone forwards your email. For a confidential build, require each recipient to sign in. For a low-stakes demo, a shared password or unlisted link may be enough, but describe it honestly.

1. Export a build that runs in the browser

I tested a small GDScript project with a button that increments a score, using Godot 4.7.2 and its matching Web export templates. The browser tests ran locally in headless Chromium. No hosted accounts were created.

  1. Use the Compatibility renderer. Godot 4 Web exports target WebGL 2.0, not Forward+ or Mobile. C# projects cannot currently export to Web.
  2. Set a main scene. Under Project → Export, add a Web preset named Web. Install the matching export templates if needed.
  3. For this test, leave thread support, extension support and Progressive Web App disabled. A threaded export has extra cross-origin isolation requirements; it is not the configuration tested here.
  4. Run these commands from the project directory on Linux. They create a sibling export folder. Keep every generated file together with its original name.
/usr/bin/godot --headless --editor --path . --import
mkdir -p ../export
/usr/bin/godot --headless --path . --export-release Web ../export/index.html

Serve the folder over HTTP locally, not by double-clicking the HTML file. The unprotected control build loaded and accepted a click before I added any access controls.

Godot’s export requirements: https://docs.godotengine.org/en/stable/tutorials/export/exporting_for_web.html

2. Protect the whole folder, not just index.html

HTTP Basic auth can gate the loader and every game asset before the server sends them. I tested Caddy 2.11.8 with one username and password. That is a shared credential, not proof that a visitor is an invited person.

For a local reproduction, install Caddy and save this as Caddyfile beside the export folder. The global block disables Caddy’s admin listener and config persistence for this throwaway test.

{
    admin off
    persist_config off
}
http://127.0.0.1:8766 {
    root * ./export
    basic_auth {
        tester {$PLAYTEST_PASSWORD_HASH}
    }
    header Cache-Control "no-store"
    file_server
}

From that same directory, start Caddy. The password below is disposable test data. Do not reuse it on an internet-facing host.

export PLAYTEST_PASSWORD_HASH="$(caddy hash-password --plaintext local-playtest-only)"
caddy run --config Caddyfile

Open http://127.0.0.1:8766/ and use username tester with that test password. In a second terminal, compare requests to an asset, not just the homepage:

curl -I http://127.0.0.1:8766/index.wasm
curl -I -u tester:local-playtest-only http://127.0.0.1:8766/index.wasm

The first request returned 401 Unauthorized. The authenticated request returned 200 OK with Content-Type: application/wasm. Separate GET tests confirmed that HTML, JavaScript, WASM and PCK files all rejected missing or wrong credentials. With valid credentials, the game loaded and its score button worked.

This loopback HTTP setup is not a public sharing server. Basic auth needs HTTPS outside localhost because its credentials are not encrypted by the auth scheme itself. For actual invitations, use individual credentials or an identity-based allowlist, protect every asset path and remove access when testing ends. The browser must still download the game to run it, so authentication cannot prevent an authorized tester from keeping a copy.

Caddy’s auth behavior and HTTPS warning: https://caddyserver.com/docs/caddyfile/directives/basic_auth

3. A password wrapper can leave the game files exposed

StatiCrypt encrypts HTML and decrypts it in the visitor’s browser after they enter a password. I copied the export, then encrypted only its entry page with StatiCrypt 3.5.4:

cp -r export encrypted
STATICRYPT_PASSWORD=local-playtest-only npx --yes staticrypt@3.5.4 export/index.html -d encrypted

Served from localhost, the wrong password left the prompt in place. The right password unlocked the page, Godot’s loader ran and the score button worked. So this wrapper did not break this single-threaded Godot 4.7.2 export.

But unauthenticated requests to index.js, index.wasm and index.pck still returned 200 OK with the original files. Encrypting the launch page did not encrypt or restrict the rest of the build. Do not use this setup as access control for a confidential game.

StatiCrypt documents HTML encryption and copying non-HTML files unchanged: https://github.com/robinmoisson/staticrypt

4. Unlisted is useful, but it is not invite-only

I also put the export under a random 32-character path, disabled directory listing and served it with X-Robots-Tag: noindex. The root and a wrong path returned 404. The correct link loaded in a second, fresh browser context with no login, and the game still worked.

That is what a bearer link means: possession of the link grants access. noindex asks cooperating search engines not to list a page. It does not reject visitors, stop forwarding or hide assets from someone who knows their URLs.

Google’s indexing directive: https://developers.google.com/search/docs/crawling-indexing/block-indexing

Ziva’s Share Web build preview is this kind of link

If unlisted access meets your needs, Ziva’s Share Web build can export and host the game from the Godot editor. It is free on every Ziva plan while signed in, with no paid upgrade required for sharing. The upload limit is 300 MiB after compression, described as 300 MB in the docs.

  1. Open the chat header’s ⋮ menu and choose Share Web build.
  2. Use Open preview to test it, then copy the Preview URL.
  3. For an unlisted build, stop before Approve and publish.

The preview URL uses a random ID under ziva.sh/api/share-build-preview/. Its route serves files without checking the viewer’s account or an invitation, and sends X-Robots-Tag: noindex. Anyone holding the preview link can open it. It is not password-protected or restricted to your playtesters. Ziva’s dialog labels this field “only you can see this”, but the route does not check who opens it, so treat the link as a bearer link.

Publishing is different: it makes the game public in the https://play.ziva.sh gallery and triggers a Discord announcement. Do not publish a confidential demo to obtain a share link.

Active previews have no time-based expiry check. Rebuilding replaces the preview link, publishing removes the preview files, and deleting the share removes its stored build files. Published share links are documented as non-expiring. Do not treat a preview as a permanent URL or assume it will expire after your test.

The author is a cofounder of Ziva.

These details were checked against Ziva’s current code and docs, not a live upload: https://ziva.sh/docs/share-web-builds

5. Hosted options for a closed playtest

The options below are based on official documentation checked on 7 November 2026. I did not deploy this build to them or test their login flows. Check both the page and direct asset URLs before sending a confidential demo.

itch.io: Restricted, not just Draft

Upload a ZIP containing index.html and all the export files as an HTML5 game. Choose Restricted visibility. You can grant access with download keys that recipients attach to their accounts, then revoke those keys later.

The optional page password is a shared secret, and itch.io also allows it in the URL. That is not an individual invitation. Draft pages have secret-link access, but itch.io advises against distributing drafts because others cannot download or purchase them.

These docs describe page access. I have not verified whether a copied HTML5 CDN asset URL remains gated. Do not assume the page setting proves that.

https://itch.io/docs/creators/access-control
https://itch.io/docs/creators/html5

Cloudflare Pages + Access: an email allowlist

Use a Cloudflare Access Allow policy for your testers’ exact email addresses. One-time PIN login can verify approved addresses without asking testers to join your Cloudflare team.

Pages preview URLs are public by default. Enable access policy protects preview deployments, not the production project.pages.dev hostname or custom domains. Cover every hostname serving the build, with no public asset bypass.

Pages limits each asset to 25 MiB. My raw index.wasm was 37.7 MiB, so this export would not fit unchanged. Check file sizes before choosing it; do not move oversized files to an unprotected public bucket.

https://developers.cloudflare.com/pages/configuration/preview-deployments/
https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/one-time-pin/
https://developers.cloudflare.com/pages/platform/limits/

Netlify: check the plan and visibility scope

Netlify’s built-in shared password is available on Pro and Enterprise, not credit-based Free or Personal. On credit-based Pro, set it under Project configuration → General → Visitor access → Project visibility.

Choose protection for production and previews if both contain the build. A password is still transferable. For identity-based access, review Netlify’s private-project and team-login rules. On credit-based Free and Personal, a private project is visible only to its Team Owner, so that is not a closed-group playtest solution.

https://docs.netlify.com/manage/security/secure-access-to-sites/password-protection/

Vercel: password protection is not on Hobby

Vercel lists Password Protection at $20 per month per protected project on Pro, included on Enterprise, and unavailable on Hobby. Existing Pro teams on its legacy Advanced Deployment Protection package pay $150 per month per team instead.

Vercel Authentication is a different option, available on all plans. It checks a visitor’s Vercel login and deployment access; Hobby permits one external user per account. Choose the right deployment scope and avoid shareable bypass links if access must remain tied to approved people.

https://vercel.com/docs/deployment-protection/methods-to-protect-deployments/password-protection
https://vercel.com/docs/deployment-protection/methods-to-protect-deployments/vercel-authentication

6. Check the link before you send the outreach

  • Open a fresh signed-out browser. Try the launch page and copied URLs for the JS, WASM and PCK files. A protected build must refuse the files, not merely hide a Play button.
  • Sign in as a permitted tester, load the game and play through the part you are asking them to review. Then test a non-invited account.
  • Check alternate hostnames, old deployments and embedded asset URLs. A protected custom domain does not help if the same build is public elsewhere.
  • Put the expected play time, supported browser, login instructions and one clear feedback request in your email. Use the same access method in your own test that the recipient will use.
  • Set a date to revoke access or delete the build. Revocation stops future requests, not copies already downloaded.

For a publisher demo that must stay with named recipients, choose identity-based access and verify the asset requests. For an informal feedback round, an unlisted link is simpler. The important part is not calling those two things the same kind of private.

Book a call

20 minutes · Google Meet

Loading available times…