Profiling in the Browser
Learn about how to find and analyze key metrics in the browser tools.
Profiling Web Applications in the Browser
In Optimization Recommendations and Requirements, we stressed the importance of profiling web applications before beginning any optimization. Here, we give an overview of how browser developer tools can be used to profile application metrics
In this section, we use screenshots from Chrome, as it is has the largest user base. However, developer tooling functions similarly across browsers. For instance, Edge and Chrome use the exact same developer tools, with some minor UI differences. Safari has a slightly different collection of tools, but it can be used to achieve similar results. In the next section, we provide platform-specific resources for profiling web applications.
🧰 Accessing Developer Tools

Most profiling utilities are accessible in the "Developer Tools" menu (Web Inspector in Safari). This menu is accessed in a different way on each browser:
Chrome
Ctrl-Shift-J (Windows) Command-Option-K (Mac)
Edge
F12
Safari
Command-Option-C
Firefox
Ctrl-Shift-K. (Windows) Command-Option-K (Mac)
⏱️ Profiling Application Metrics
The Developer Tools browser menu can be used to access profilers for the core application metrics described in Optimization Recommendations and Requirements. Here, we give an overview of generating profiles with these tools and interpreting the results.
Overview
We recommend enabling the built-in FPS overlay on desktop devices while developing an application. This allows developers to quickly detect if a change has impacted performance, even when not they are not doing optimization work. This helps prevent performance regressions from accidentally getting out to users.
Guide: Enabling the FPS Overlay
Focus the Developer Tools Menu and enter ctrl/cmd + shift + P . This opens a search menu:

Type "show FPS" into the search menu and hit Enter

Observe the FPS counter in the top left corner of the application.

Interpreting Results
Average FPS is displayed at the top of the overlay (69.6 FPS in the picture above)
Variance in FPS can be determined from the colored bar below the average FPS. Yellow segments represent samples above 60 fps, while red segments represent samples below 60 fps. In the image above, FPS is hovering around 60 fps, so short red segments are interspersed with short yellow segments.
In a well-optimized application, all segments will be yellow:

In a poorly-optimized application, many segments will be red:

GPU memory usage is displayed at the bottom of the overlay. GPU performance typically scales with memory usage. In the image above, there is very little GPU overhead.
Overview
Most optimization work in the browser revolves around generating profiles in the "Performance" tab (Timelines in Safari). In this tab, we can break down how much time is spent each frame on scripting, shaders, and garbage collection (GC). We can also view outlier frames, i.e. frames that last much longer than the average frame, contributing to instability.
Guide: Generating a Performance Profile
Select the Performance tab (Timelines in Safari) and click the "record" button.

If your browser supports memory profiling, be sure to toggle the option. This allows you to analyze garbage collection pauses with more detail.

Developers can enable CPU throttling to approximate performance on less-powerful mobile devices. We recommend selecting "mid-tier mobile", as Chrome normalizes these values across devices.

The performance profiler generates a flame graph, which shows how much time is spent in individual functions in each frame. The functions stack downwards, so the core render function will be near the top, and native calls, JavaScript APIs, and WebGL calls will be at the bottom.

We also see the amount of memory being used during the profile. This typically has a "sawtooth" pattern, as garbage collection will automatically trigger once memory usage reaches a certain level.

Garbage collection appears in the flame graph as either a "Minor GC" or "Major GC" event, corresponding to a partial garbage collection or a full garbage collection, respectively. The differences between minor and major GC are explored in more depth on the v8 blog.

GPU overhead is recorded at the bottom of the profile, but there is relatively little detail provided.

Interpreting results
In a well-optimized application, the flamegraph will have a small width relative to the size of the length of the frame. In the screenshot below with mid-tier mobile throttling selected, we spend about 5ms per frame in scripting, leaving plenty of room for GPU overhead. This application can be expected to run at above 60 FPS on most devices:

In a poorly-optimized application with the same throttling, we see much more time spent in scripting, over 20 ms in this case. This application will run well below 60 fps, as this does not include time spent on the GPU. Here, we can see a lot of time spent in the "render" function. This suggests that the developer should reduce the number of draw calls in the application.

In a well-optimized application, there should be a long time between Minor GC events. To achieve this, developers should reduce temporary allocations, as described in Challenges and Optimization Strategies.
A "Major GC" event will correspond to a noticeable freeze in the application. These should be minimized as much as possible. Major garbage collection events can also be avoided by using temporary variables, but often correlate to a major scripting event, such as hundreds of meshes being removed from the scene at once. In these circumstances, it may be better to split up the work across multiple frames with setTimeout, allowing for multiple small GC pauses that are less noticeable to the user.
Overview
It can be challenging to locate the memory allocations that contribute to long garbage collection pauses or application crashes. In many cases, these allocations are split across many different functions and objects, each of which needs to be optimized. To identify these functions and objects, developers can take a "Heap Snapshot", which captures all of the application's allocated memory objects at a given time point and where they are still being used.
Generating a Memory Snapshot
Select the Memory tab in Developer Tools

Click the record button to take a heap snapshot

This generates an overview of how much memory is consumed by your application, and where the majority of memory is allocated. It is important to minimize the amount of temporary "object" and "array" memory used by your application, as this memory contributes the most to garbage collection pauses.

Interpreting Results
Minimizing large objects
Select an object that is utilizing lots of memory. Typically, these will be ArrayBuffers, Meshes, Vectors, other game engine objects, or plain JavaScript arrays like the ArrayBuffer below:


We can then see that the ArrayBuffer is being allocated as matrix transform data for instances of a mesh. Given the large amount of memory being allocated for this matrix, it may make sense to reduce the number of instances rendered by the corresponding mesh, as this could cause a GC pause when it is disposed.

Minimizing large quantities of small objects
In addition to the large ArrayBuffer allocation, we also see a large number of Vector3 objects being allocated (43,363)
Most of these Vector3 objects are in use by the engine, but some of them correspond to temporary variables created in a loop in our experience logic. These temporary variables should ideally be reused, as described in .
Overview
There are three main tools for profiling loading time: the performance profiler, Lighthouse (only available in Chrome and Edge), and the network tab. Lighthouse generates a report on how long the application takes to load
Guide: Profiling Loading Performance
To profile scripting performance while loading, reload the page while recording performance. This generates a performance profile that is identical to the one described in General Performance.

In the generated profile, we can see lots of time being spent decoding textures. This could be reduced by using smaller texture sizes, which take less time to decode, or by merging textures into a single texture atlas.

Guide: Generating Lighthouse Reports
Chrome has built-in tools for analyzing loading time performance in the "Lighthouse" tab.

This gives information on asset download sizes, how long the initial load takes, and how long it takes for the application to come fully interactive. This is useful in determining TTID. TTID roughly corresponds to the "First Contentful Paint" metric. There is not an exact analogue for TTFD, as Lighthouse cannot determine whether or not the canvas is interactive.

In a poorly optimized application, Lighthouse will give information on specific assets to optimize, such as textures, meshes, and code.


Guide: Inspecting Network Downloads
The network tab can be used to inspect the size and timing of network fetches. To profile network activity, open the network tab, and reload the page. Select "Disable Cache" to ensure that everything is downloaded over the network.

Look for assets with large sizes. Here, we may choose to compress the skybox texture even more, as the combined assets are about 6 MB.

📱 Profiling Mobile Devices
There are two main ways to capture mobile performance metrics:
directly profiling a connected mobile device
emulating a mobile device in the browser
These techniques should be used in combination. Profiling mobile hardware gives more representative data, while emulation can be used to provide a wider range of data points. Crucially, GPU performance does not scale in browser emulators, so frame rate may be higher in the emulator. Emulators should primarily be used to approximate CPU performance across a range of devices and to validate image quality across a range of resolutions.
Prerequisites
Access to an Android Device
Install Android Debug Bridge (ADB) to connect to the android device.
Install Chrome or Edge on your desktop/laptop computer. In Edge, replace
chrome://withedge://for the following steps.
Connecting to an Android Device via USB
Connect an android device via USB
In a terminal, run
adb devicesto start the debugging serverNavigate to chrome://inspect/devices and click "inspect" the connected device
This brings up the Developer Tools menu for the connected device. From here, profiling is the same as on a desktop
Generating Native Performance Profiles
In chrome://inspect/devices, select the "trace" option.
If debugging an Android XR device, select
Edit categories> checkxr.debugClick record to begin generating a native trace.
Prerequisites
Access to an iOS device
Connecting to an iOS device
Profile the application using safari dev tools.
Emulating a Mobile Device
Open Developer Tools and select the icon in the top left corner that looks like a laptop computer. This enables device emulation, allowing a developer to select from a range of devices to emulate.

Developers can then select a device to emulate in the main browser window, and apply throttling to the CPU. Below, we selected an iPhone 12 Pro with Mid-tier Mobile throttling:

Emulating a WebXR Device
For WebXR Emulation, install the Meta Immersive Web Emulator. It is supported on Chrome and Edge. This allows developers to profile immersive experiences more accurately, and gives tools for manipulating the XR headset and controllers:

Profiling Resources for Web Browsers and Devices
Beyond the overview we have provided, each browser provides detailed guides for debugging and profiling applications. Here we provide lists of resources for each major browser, as well as resources for connecting to mobile devices from Chrome and Safari.
Platform Support
🖥️ Desktop & 📱 Mobile
Core Developer Tools
Additional Tooling
Tracing Tool: Provides more introspection into the native side of chrome, showing JavaScript engine traces and GPU tracing.
Lighthouse: Tools for optimizing app start time and file size.
Immersive Web Emulator Plugin: emulate XR devices in Chrome Developer Tools
Display frame rate
Mobile Tooling
Platform Support
🖥️ Desktop
Core Developer Tools
Additional Tooling
Immersive Web Emulator Plugin: emulate XR devices in Edge Developer Tools
Mobile Tooling
Platform Support
Desktop & 📱 Mobile
Core Developer Tools
Timelines (Scripting and Memory profiler)
Mobile Tooling
Last updated
Was this helpful?