Quick answer: Capture Haxe exceptions with their stack trace and attach the compilation target (HashLink, C++, or JavaScript) and platform, because Haxe compiles one codebase to genuinely different runtimes that fail differently. The target is essential context, since the same game can crash on one target and not another.

Haxe is a language that compiles to many targets, and games built with it, including those using the Heaps engine, can run as HashLink bytecode, as native C++, or as JavaScript in the browser, all from one codebase. This is powerful, and it means the same game runs on genuinely different runtimes that fail in different ways: a crash on the JavaScript target is a browser failure, on the C++ target a native crash, on HashLink a bytecode-level error. Setting up crash reporting for a Haxe game means capturing exceptions with the compilation target context that explains these differences.

One codebase, many runtimes

Haxe defining feature is cross-compilation: your Haxe code is compiled to a target language and runtime, and games commonly target HashLink, a fast bytecode VM for desktop, native C++ for performance and console-like targets, and JavaScript for the web. These are not just different platforms but different runtimes, each with its own execution model, error behavior, and crash characteristics.

This means a Haxe game crash depends heavily on the target. A bug might manifest as a clean exception on HashLink, a native crash on the C++ target, and a JavaScript error on the web target, and a crash might appear on only one target due to differences in how the code is compiled and run. Capturing which target a crash came from is the first and most important context for interpreting a Haxe crash, because it determines the entire nature of the failure.

Capture exceptions with the target context

Haxe has exceptions, and you can catch unhandled exceptions to capture crashes, recording the exception and stack trace. The form this takes depends on the target, since the underlying runtime differs, but the principle is the same: catch what would otherwise crash the game, capture the exception and trace, and report it. Tag every report with the compilation target.

The target tag is essential because it tells you which runtime produced the crash and therefore how to interpret the stack trace and what kind of fix to consider. An exception on the JavaScript target is interpreted like any web error, one on the C++ target like a native crash, and one on HashLink like a VM-level error. Without the target, a Haxe crash report is ambiguous, since the same codebase produces structurally different crashes depending on how it was compiled.

Handle the differences per target

Each Haxe target has its own crash characteristics that affect how you capture and read crashes. The JavaScript target runs in the browser with all its constraints and produces JavaScript stack traces, possibly minified and needing source maps. The C++ target produces native crashes that may need symbolication. HashLink produces its own stack traces from the VM. Your capture should handle the form each target uses.

This per-target handling ensures a crash from any target is readable and actionable. For the C++ target, keep symbols for symbolication; for the JavaScript target, keep source maps; for HashLink, capture the VM stack trace. Tailoring your capture to each target form, while tagging every crash with its target, is what makes a multi-target Haxe game crashes diagnosable across the genuinely different runtimes it compiles to.

Capture platform and version

Beyond the compilation target, capture the platform and OS, since a target like C++ or HashLink still runs across different desktop platforms, and the JavaScript target runs across browsers. A crash on the C++ target on one operating system, or the JavaScript target on one browser, points at a platform-specific issue within that target, which the platform context reveals.

Capture your game version and the relevant engine version, such as Heaps if you use it, so you can tell whether a crash is tied to a particular build or engine version. Behavior can change across Haxe, Heaps, and target-runtime versions, so a crash that correlates with a version tells you whether an update introduced or fixed it. The platform and version context, layered on the target tag, gives you the full environment for each Haxe crash.

Setting it up with Bugnet

Bugnet captures Haxe crashes by catching unhandled exceptions, with the capture tailored to each target form, native symbolication for C++, source maps for JavaScript, VM traces for HashLink, and you attach the compilation target, platform, and version as custom fields. Reports flow into one dashboard tagged by target, so you can see your whole cross-target game stability in one place.

Add custom fields for your game state and group identical crashes into occurrence counts. Because Haxe compiles one codebase to several runtimes, the ability to filter crashes by target is especially valuable, instantly telling you whether a crash is universal across targets, indicating a logic bug in your shared code, or specific to one target, indicating a runtime or compilation issue, which completely changes how you approach the fix.

Test the targets you ship

Because Haxe targets behave differently, test each target you ship, since a bug that never appears on your development target can crash on another. If you develop on HashLink for fast iteration but ship the C++ target for release, or ship a JavaScript web build alongside desktop, test those release targets specifically, because target-specific issues only appear when you run that target.

Pair that testing with your target-tagged crash data for the issues that appear only under specific conditions or platforms within a target. Your testing catches the gross per-target differences, and the captured crashes, tagged by target and platform, reveal the specific failures across the range players run. For a Haxe game that compiles to multiple runtimes, this combination of per-target testing and target-tagged capture is what lets you confidently ship the same code across the different worlds Haxe targets.

Haxe compiles one game into different worlds. Tag the target, or the crash makes no sense.