Quick answer: The most common cause is opening the exported HTML file directly from disk using the file:// protocol. Browsers block WebGL, Web Workers, and fetch requests from file:// origins. You must serve the exported game from an HTTP server. Other causes include missing files in the export, incorrect Content-Type headers on the server, web worker path issues, minification breaking scripts, and Content Security Policy headers blocking the runtime.
Here is how to fix a Construct 3 exported game that shows a blank screen or fails to run. You exported your project as HTML5, NW.js, or a mobile build. The export completed without errors. But when you open the game, all you see is a white or black screen, a loading bar that never completes, or nothing at all. The game works perfectly in Construct 3’s preview mode, which makes this even more confusing. The issue is almost always related to how the browser or platform loads and executes the exported files.
The Symptom
After exporting your Construct 3 project, the game fails to run in one or more of these ways:
A completely blank (white or black) screen with no loading indicator. The page loads but the canvas never initializes. This usually means JavaScript execution failed before the engine could start.
A loading bar that appears but gets stuck at 0% or some percentage and never completes. This means the engine started but could not load one or more required assets. The browser console typically shows 404 or CORS errors in this case.
The game loads and shows the first frame but then freezes or crashes immediately. This often indicates a Web Worker initialization failure or a JavaScript error in the game logic that only manifests outside of preview mode.
The game works when served from one hosting platform but not another, or works in Chrome but fails in Firefox or Safari. This points to server configuration differences or browser-specific restrictions.
What Causes This
There are seven common causes:
1. Opening from file:// protocol. This is the single most common cause. When you double-click the exported index.html file, the browser opens it using the file:// protocol. Modern browsers enforce strict security restrictions on file:// origins: they block cross-origin requests (including loading other local files via fetch), disable Web Workers, and may disable WebGL. Since Construct 3’s runtime relies on all three, the game cannot start.
2. Missing files in the export. If the export process is interrupted or if you selectively copy files from the export folder, critical files may be missing. The runtime needs all JavaScript modules, the data.json or .c3p archive, audio files, and sprite sheets. A single missing file can prevent the game from loading.
3. Web server required for WebGL. Even when serving from HTTP, some minimal server configurations do not enable WebGL correctly. If the server does not support range requests or sends incorrect cache headers, WebGL context creation can fail on certain browsers.
4. Incorrect Content-Type headers. Web servers must send the correct MIME type for each file type. If JavaScript files are served as text/plain instead of application/javascript, or if .wasm files are served without the application/wasm MIME type, the browser will refuse to execute them. This is especially common on custom or misconfigured servers.
5. Web Worker path issues. Construct 3 uses Web Workers for its runtime. Workers are loaded relative to the HTML file’s location. If you move the HTML file to a different directory or deploy behind a reverse proxy that changes the URL path, the worker scripts may not be found. The browser console will show a 404 error for the worker file.
6. Minification breaking scripts. If you enable the “Minify script” export option, the JavaScript minifier may rarely break code that relies on specific variable names or property ordering. This is uncommon with Construct 3’s own runtime but can affect custom JavaScript plugins or behaviors that were not designed with minification in mind.
7. Content Security Policy (CSP) headers blocking eval. Some hosting platforms (Netlify, Vercel, GitHub Pages with custom headers, corporate intranets) set CSP headers that restrict JavaScript execution. Construct 3’s runtime may use eval(), new Function(), or Blob URLs for Web Workers, all of which can be blocked by strict CSP policies.
The Fix
Step 1: Serve from an HTTP server. Never open the exported game directly from disk. Use a local HTTP server for testing:
# Python 3 (built-in HTTP server)
cd /path/to/exported/game
python -m http.server 8080
# Open http://localhost:8080 in your browser
# Node.js (using npx, no install needed)
cd /path/to/exported/game
npx serve -p 8080
# Open http://localhost:8080 in your browser
# PHP (built-in server)
cd /path/to/exported/game
php -S localhost:8080
Step 2: Check the browser console for errors. Open the developer tools (F12) and look at the Console tab. The errors will tell you exactly what is failing:
// Common console errors and what they mean:
// CORS error: loading from file:// or cross-origin
// "Access to script at 'file:///...' from origin 'null' has been blocked"
// FIX: Use an HTTP server
// 404 error: missing file
// "GET http://localhost:8080/scripts/c3runtime.js 404 (Not Found)"
// FIX: Re-export and copy ALL files from the export folder
// MIME type error: wrong Content-Type header
// "Refused to execute script because its MIME type ('text/plain')"
// FIX: Configure server MIME types (see Step 3)
// CSP error: blocked by Content Security Policy
// "Refused to evaluate a string as JavaScript because 'unsafe-eval'"
// FIX: Modify CSP headers (see Step 6)
// Worker error: Web Worker failed to load
// "Failed to construct 'Worker': Script at '...' cannot be accessed"
// FIX: Check worker path configuration (see Step 5)
Step 3: Configure server MIME types. Ensure your web server sends correct Content-Type headers. Here is an example for common server configurations:
# Apache (.htaccess)
AddType application/javascript .js
AddType application/wasm .wasm
AddType application/json .json
AddType application/octet-stream .c3p
AddType audio/webm .webm
AddType audio/ogg .ogg
AddType font/woff2 .woff2
# Nginx (in server or location block)
types {
application/javascript js;
application/wasm wasm;
application/json json;
audio/webm webm;
audio/ogg ogg;
font/woff2 woff2;
}
// Node.js Express server with correct MIME types
const express = require("express");
const app = express();
// Serve static files with correct MIME types
app.use(express.static("game", {
setHeaders: (res, path) => {
if (path.endsWith(".wasm")) {
res.setHeader("Content-Type", "application/wasm");
}
if (path.endsWith(".js")) {
res.setHeader("Content-Type", "application/javascript");
}
}
}));
app.listen(8080, () => console.log("Game server on http://localhost:8080"));
Step 4: Verify all exported files are present. After exporting, check that all files are in the output folder. A typical HTML5 export includes:
// Expected export folder structure:
// index.html - Main HTML file
// data.json - Project data (or embedded in index.html)
// scripts/ - Runtime JavaScript files
// c3runtime.js - Main Construct 3 runtime
// main.js - Entry point module
// register-sw.js - Service worker registration
// sw.js - Service worker
// images/ - Sprite sheets and images
// media/ - Audio files (.webm, .ogg)
// style.css - Loading screen styles
// icons/ - App icons (for PWA/mobile)
//
// If ANY of these are missing, re-export the entire project.
// Do not selectively copy files from old exports.
Step 5: Fix Web Worker paths. If you deploy behind a reverse proxy or in a subdirectory, the worker paths may break. You can set the base URL in the exported HTML:
<!-- In index.html, find the script that initializes the runtime -->
<!-- If your game is served from a subdirectory like /games/mygame/ -->
<!-- the worker paths need to resolve relative to that directory -->
<!-- Option 1: Use a <base> tag -->
<base href="/games/mygame/">
<!-- Option 2: Deploy the game at the root of a domain/subdomain -->
<!-- e.g., https://mygame.example.com/ instead of -->
<!-- https://example.com/games/mygame/ -->
<!-- This avoids all relative path issues -->
Step 6: Adjust Content Security Policy headers. If your hosting platform enforces CSP, you need to allow the features Construct 3 requires:
# Required CSP directives for Construct 3 games
# Add to your server configuration or hosting platform headers
Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-eval' blob:;
worker-src 'self' blob:;
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob:;
media-src 'self' data: blob:;
connect-src 'self';
# For Netlify (_headers file):
/*
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-eval' blob:; worker-src 'self' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; media-src 'self' data: blob:;
# For Vercel (vercel.json):
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; script-src 'self' 'unsafe-eval' blob:; worker-src 'self' blob:;"
}
]
}
]
}
Step 7: Disable minification for debugging. If the game fails only when exported with minification, re-export with “Minify script” set to “No” in the export options. If the un-minified version works, the issue is likely in a custom plugin or third-party addon that does not survive minification. Contact the addon developer or avoid minification for that project.
// Export settings for debugging:
// Menu > Project > Export
// Export options:
// Minify script: No (for debugging)
// Deduplicate images: Yes
// Recompress images: Yes
//
// Once the game works un-minified, re-enable minification
// and test again. If it breaks, the minifier is the problem.
Why This Works
Each fix addresses a different layer of the web platform’s security and configuration model:
Serving from HTTP removes the most restrictive security sandbox. The file:// protocol treats every file as a separate origin, so the game’s HTML cannot load its own JavaScript modules, create Web Workers, or use fetch to load data files. HTTP/HTTPS gives the game a proper origin where all files in the same directory are considered same-origin.
Correct MIME types satisfy browsers’ strict MIME checking. Chrome and Firefox refuse to execute JavaScript served as text/plain and refuse to compile WebAssembly served without application/wasm. These checks exist to prevent servers from accidentally serving executable content that was not intended to be executed.
Complete file exports ensure the runtime has every asset it needs. Construct 3’s loader expects specific files at specific paths. A missing c3runtime.js means the engine never initializes. A missing sprite sheet means the loader hangs waiting for a resource that will never arrive.
Worker path resolution ensures Web Workers can find their source scripts. Workers are loaded with an absolute or relative URL, and if that URL does not resolve to the correct file on the server, the worker creation fails and the game freezes because the runtime runs inside the worker.
CSP adjustments grant the game permission to use JavaScript features that strict security policies block by default. unsafe-eval allows the runtime to use eval() and new Function(). blob: allows the creation of Blob URLs for dynamically generated worker scripts. Without these, the runtime cannot initialize.
"Every time I see a blank screen after export, the first thing I check is whether they opened the file directly from disk. Nine times out of ten, that is it. Use a server. Even a one-liner Python server is enough."
Related Issues
If the exported game loads but runs slowly, see our guide on low FPS and performance lag for runtime optimization. If the game loads but touch does not work on mobile devices, check touch input not working on mobile. And if the game runs but saved data is lost between sessions, see Local Storage not saving data for storage configuration issues.
Use a server. Never open from file://. Never.