WebGL Browser Compatibility
Debugging and trouble shooting WebGL builds

Building and Running a WebGL Project

When you build a WebGL project, Unity will create a folder with the following files:

  • an index.html file which browsers can navigate to to load your content.
  • a Development or Release folder containing your generated build output files (which one depends on whether you do a development build or not).
  • a TemplateData folder (at least when building with the default template), containing the loading bar and other template assets. See the manual page on WebGL templates for more info.

The a Development or Release contains the following files (replace MyProject with the name of your project). If you make a release build, files in this folder will be compressed and have a gz suffix. See the comments on Distribution size below.

  • a MyProject.js JavaScript file containing the code for your player.
  • a MyProject.js.mem file containing a binary image to initialize the heap memory for your player.
  • a MyProject.data file containing the asset data and scenes.
  • a UnityLoader.js file containing the code needed to load up the Unity content in the web page.

You can view your WebGL player directly in most browsers by simply opening the index.html file. For security reasons, Chrome places restrictions on scripts opened from local file: URLs, so this technique will not work. If you use Unity’s Build & Run command (menu: File > Build & Run) then the file will be temporarily hosted in a local web server and opened from a localhost URL (this avoids the security restrictions). You can also run Chrome with the --disable-web-security command line option to enable it to load content from file: urls.

Build Player Options

WebGL allows you to select an Optimization level in the Build Player window. These correspond to optimization flags (-O1 - -O3) passed to the emscripten compiler. In general, “Slow” produces unoptimized builds, but has much lower build times then the other options, so it can be used for iterating on code issues. “Fast” produces optimized builds, and “Fastest” enables some additional optimizations, but makes your builds take a long time to complete (so you might want to use it only for final releases).

When you tick the “Development Build” checkbox, Unity will generate a development build (with Profiler support and the development console for errors, like on other platforms). Additionally, Development builds are non-minified, so the generated JavaScript is human-readable and preserves function names (so you will get useful stack traces for errors), but very large to distribute.

The “Autoconnect Profiler” checkbox must be used when you want to profile your Unity WebGL content. It is not possible to connect the Profiler to a running build like on other platforms, as the profiler connection is handled using WebSockets on WebGL, but the browser will only allow outgoing connections from the content, so the only way to use the Profiler in WebGL is to check “Autoconnect Profiler” to have the content connect to the Editor.

Player Settings

WebGL has some additional options in the Player Settings (menu: Edit > Project Settings > Player).

The Strip Engine Code option in Other Settings lets you enable code stripping for WebGL. If you enable Stripping, Unity will not include code for any classes you don’t use - so if you don’t use any physics components or methods for instance, the whole physics engine will be stripped from your build. See the stripping section below for more details.

The WebGL memory size field in Publishing Settings lets you specifiy how much memory (in MB) the content should allocate for its heap. If this value is too low, you will get ‘out of memory’ errors when your loaded content and scenes would not fit into the available memory. However if you set this value too high, your content might fail to load in some browsers or on some machines, because the browser might not have enough available memory to allocate the requested heap size. This value is written to a variable named “TOTAL_MEMORY” in the generated html file, so if you want to experiment with this setting, you can edit the html file to avoid the need to rebuild your project. See the manual page on WebGL memory usage for more details.

The Enable Exceptions popup in Publishing Settings lets you enable exception support in WebGL. If you don’t need any exception support, set this to “None”, which will give you the best performance and smallest builds. Any exception thrown will cause your content to stop with an error in that setting. However if you need to use exceptions, you can set it to:

  • Explicitly Thrown Exceptions Only (default), which will allow catching exceptions which are explictly thrown from a “throw” statement, and will make “finally” blocks in your code work. This will make the generated JavaScript code from your user scripts bigger and slower, but is usually not that much of an issue if scripts are not the main bottleneck in your project.
  • Full, which, additional to the above, will also generate exceptions for Null References and for out of bounds array access. These are generated by embedding checks for any access to references into the generated code, so it will cause additional code size increases and slowdowns. Also, this will add managed stack traces to exceptions. It is advisable to use this mode only when you need to debug issues in your code, as it generates very large and very slow builds.

The Data caching checkbox in Publishing Settings lets you enable automatic local caching of your player data. If this is enabled, your assets will be stored to a local cached in the browsers IndexedDB database, so that they won’t have to be re-downloaded in subsequent runs of your content. Note that different browsers have different rules on allowing IndexedDB storage, and may ask the user for permission to store the data if this is enabled, and your build exceeds some size limit defined by the browser.

Distribution size

When publishing for WebGL, it is important to keep your build size low so people get reasonable download times before the content will start. For generic tips on reducing asset sizes, see Reducing the File Size of the Build. Some additonal comments specific to WebGL:

  • Specify the “Crunch” texture compression format for all your compressed textures in the Texture Importer.
  • Don’t deploy Development builds, they are not compressed or Minified and so have much larger file sizes.
  • Set Optimization Level to “Fastest”
  • Set “Enable Exceptions” in Player Settings to “None” if you don’t need exceptions in your build.
  • Enable “Strip Engine Code” in Player Settings.
  • Take care when using third-party managed dlls, as those may drag in a lot of dependencies and increase the emitted code size significantly.

If you make a release build, Unity will compress the build output files using gzip compression. If your web server is configured correctly, these files will be decompressed by the browser during download on the http protocol level. However, this means that you need to make sure that your http server actually supplies the compressed data. If you are hosting your files on an Apache web server, Unity will write an invisible .htaccess file into the build results folder, which tells Apache to compress the transfers, so this should just work. If you are using other web servers, check your server’s manual.

If your web server is not configured to serve files gzip compressed on the http protocol level, starting with Unity 5.3, Unity will decompress the data for you at load time in JavaScript. So you will still be using compressed files, but there will be a slight extra delay at startup for decompressing the data. You can tell that this happens when you see a message like this in your browser’s JavaScript console:

Decompressed Release/build.asm.jsgz in 82ms. You can remove this delay if you configure your web server to host files using gzip compression.

AssetBundles

Since all your asset data needs to be pre-downloaded before your content will start, you should consider moving assets out of your main data files and into AssetBundles. That way, you can create a small loader scene for your content which loads up quickly, and dynamically load assets on-demand as the user proceeds through your content. Also, AssetBundles will help with asset data memory, since you will be able to unload asset data from memory for assets you don’t need any more by calling AssetBundle.Unload].

Some considerations apply when using AssetBundles on the WebGL platform:

  • When you are using class types in your AssetBundle which are not used in your main build, this can cause Unity to strip the code for those classes from the build, which will then cause it to fail when trying to load assets from the AssetBundle. See the section on Stripping below to learn how to fix that.

  • Since WebGL does not support threading, and since http downloads will only become available when finished, Unity WebGL builds need to decompress AssetBundle data on the main thread when the download is done, thus blocking the main thread. To avoid this interruption, you may want to avoid using the default LZMA Format for your AssetBundles, and compress using LZ4 instead, which is decompressed very efficiently on-demand. If you need smaller compression sizes then LZ4 delivers, you can configure your web server to gzip-compress the files on the http protocol level (on top of LZ4 compression).

  • AssetBundle caching using WWW.LoadFromCacheOrDownload is supported in WebGL using the IndexedDB API from the browser to implement caching on the user’s computer. Note that IndexedDB may have limited support on some browsers, and that browsers may request the user’s authorization to store data on disk.

Stripping

By default, Unity will perform code stripping on your build - this can be controlled using the Strip Engine Code option in Other Settings. Code stripping will scan your project for any UnityObject-derived classes used (either by being referenced in your script code, or in the serialized data in your scenes), and it will strip the code of any Unity subsystems which have none of their classes used from the build. This will make your build emit less code, resulting in both, smaller downloads and less code to parse (meaning code will be parsed faster and using less memory). So, it is generally advisable to always build with stripping enabled.

It is possible, however, that code stripping may cause issues with your project and strip code which is needed. This can be the case when you load AssetBundles at runtime which contain classes which are not included in the main build, and have thus been stripped from the project. You will see error messages like this in your browser’s JavaScript console when that happens (potentially followed by more errors):

Could not produce class with ID XXX
  • where XXX can be looked up in the Class ID Reference to see which class it is trying to create an instance of. In such cases you can force Unity to include the code for that class in the build, either by adding a reference to that class to your scripts or to your scenes, or by adding a link.xml file to your project. Here’s an example which makes sure that the Collider class (and thus, the Physics module) gets preserved in a project - add this xml code to a file called link.xml, and put that file into your Assets folder:
<linker>
    <assembly fullname="UnityEngine">
        <type fullname="UnityEngine.Collider" preserve="all"/>
    </assembly>
</linker>

You can always try disabling the Strip Engine Code option for testing, if you suspect that stripping is causing problems with your build.

Unity does not yet provide a convenient way to see which modules and classes are included in a build, which would allow you to optimize your project to strip well. We are working on providing that information - in the meantime, you may want to look at the generated file Temp/StagingArea/Data/il2cppOutput/UnityClassRegistration.cpp after making a build, to get an overview of included classes and modules.

Note that the Strip Engine Code option only affects Unity engine code. IL2CPP will always strip byte code from your managed dlls and scripts. This can cause problems when you need to reference managed types dynamically through reflection rather then through static references in your code. If you need to access types through relection, you may also need to set up a link.xml file to preserve those types. See the documentation page on iOS Build size optimization for more information on link.xml files.

Moving build output files

If you want to change the location of your output files relative to the index.html file, you can do so by editing the dataUrl, codeUrl, and memUrl fields and the UnityLoader.js script tag in the index.html file. You can specifiy URLs on external servers for these if you want to host your files on a CDN, but you will need to make sure that the hosting server has enabled CORS for this to work. See the manual page on WebGL networking for more information about CORS.

WebGL Browser Compatibility
Debugging and trouble shooting WebGL builds