Quick answer: Add a global JavaScript error handler and unhandled promise rejection handler to capture exceptions. Listen for WebGL context loss events. Collect the browser user agent, screen size, WebGL renderer string, and game state with each error. Use source maps to deobfuscate minified stack traces.
HTML5 browser games do not crash the way desktop games do — there is no crash dump, no core file, no operating system dialog. Instead, they fail silently. A JavaScript exception freezes the game loop. A WebGL context loss turns the screen black. An out-of-memory condition causes the browser tab to slow to a crawl or close without warning. Setting up crash reporting for HTML5 browser games requires understanding these failure modes and building capture mechanisms for each one.
How Browser Games Fail
Browser games experience several distinct failure modes, each requiring different capture strategies. JavaScript errors are the most common — uncaught exceptions or type errors that halt execution of your game loop. Unhandled promise rejections occur in async code paths and can silently break game logic without visible errors. WebGL context loss happens when the browser reclaims GPU resources, turning your game screen black. Out-of-memory failures occur when your game exceeds the browser tab’s memory allocation. Infinite loops or long-running scripts trigger the browser’s “page unresponsive” dialog.
Each of these failures looks different to the player but shares a common outcome: the game stops working and the player has no useful information to report. Without crash reporting, you have no idea how many players are experiencing these issues or what is causing them.
Capturing JavaScript Errors
The foundation of browser game crash reporting is the global error handler. Add a listener for both the error event and the unhandledrejection event on the window object. The error event catches synchronous exceptions while unhandledrejection catches promise failures.
When an error fires, capture the error message, the stack trace, the file name and line number, the browser user agent string, the current URL, and any game state that is accessible (current scene, player position, game time). Package this data and send it to your crash reporting endpoint.
Bugnet’s web SDK handles this setup automatically. Include the SDK script, initialize it with your project ID, and all JavaScript errors and promise rejections are captured and reported with full browser context. For games using frameworks like Phaser or Pixi.js, the SDK integrates at the browser level without needing framework-specific hooks.
Handling WebGL Context Loss
WebGL context loss is one of the most frustrating browser game failures because it is often not caused by your code. The browser can reclaim your WebGL context when GPU memory is under pressure, when the user switches tabs and the browser decides to free resources, when GPU drivers crash and recover, or when the device enters a low-power state.
Listen for the webglcontextlost event on your canvas element. When it fires, log the event with device metadata and attempt recovery. Some engines handle context restoration automatically — check whether yours does. If not, you can listen for webglcontextrestored and reinitialize your renderer.
Track WebGL context loss frequency in your crash reporting. If certain browsers or GPU configurations experience it disproportionately, you may need to reduce your VRAM usage or texture sizes for those configurations. The WebGL renderer string, available from the WebGL context, tells you the player’s GPU and can help identify hardware-specific patterns.
Source Maps for Readable Stack Traces
If your game code is minified or bundled (which it should be for production), raw stack traces will contain obfuscated function names and incorrect line numbers. Source maps solve this by mapping minified code back to your original source.
Generate source maps during your build process. Most bundlers (webpack, Rollup, esbuild) support source map generation with a configuration flag. Upload the source maps to your crash reporting service so that incoming error reports are automatically deobfuscated. Do not serve source maps to players — they expose your original source code. Keep them on your server or in your crash reporting tool.
With source maps in place, a stack trace that shows a.b at chunk-4f2a.js:1:23456 becomes PlayerInventory.addItem at inventory.js:47:12. The difference in debuggability is enormous.
Browser-Specific Challenges
Different browsers handle errors, WebGL, and memory differently. Chrome, Firefox, Safari, and Edge all have quirks that affect your crash reporting data.
Safari has historically had more restrictive WebGL support and different memory limits than Chrome. Audio autoplay restrictions are also stricter in Safari, which can cause errors in games that start audio programmatically. Safari’s error events sometimes lack stack traces for cross-origin scripts, which can affect games loaded in iframes on other sites.
Firefox handles garbage collection differently than Chrome, which can cause different performance characteristics and memory-related failures. Firefox also has different WebGL extension support, which matters if your game uses advanced rendering features.
Mobile browsers have stricter memory limits and more aggressive tab killing. A game that runs fine on desktop Chrome might get killed by mobile Safari after consuming too much memory, with no error event fired. Tracking session starts without corresponding session ends can help you identify these silent kills.
Include the full user agent string in every crash report so you can filter by browser and version. Patterns in your crash data will reveal browser-specific issues that need targeted fixes or workarounds.
Collecting Meaningful Context
A JavaScript error with a stack trace tells you where the crash happened but not why. Context makes the difference between a quick fix and hours of investigation. Capture as much game state as practical with each error report.
Useful context includes the current game scene or level, the player’s position or state, active UI screens, recent player actions (the last ten inputs or game events), game settings (quality level, audio settings), total session duration, and current frame rate. Store this context in a circular buffer that updates continuously and is read when an error occurs. This gives you a snapshot of the game state at the moment of failure without significant runtime overhead.
Testing Your Crash Reporting
After setting up crash reporting, verify that it actually works. Deliberately trigger each type of failure and confirm that the report arrives in your dashboard with correct data. Throw an uncaught exception and verify the stack trace is readable. Reject a promise without handling it. Simulate WebGL context loss using the WEBGL_lose_context extension. Try to allocate memory until the tab fails. Run your game in each target browser and verify that reports capture browser-specific metadata correctly.
Test your crash reporting in production conditions, not just in development. Minification, content delivery networks, cross-origin policies, and ad blockers can all interfere with error reporting. Verify that reports arrive from your production build hosted on your production domain.
Browser games fail silently. Crash reporting gives them a voice.