Single-page applications (SPA)
Real User Monitoring (RUM) is how you gather performance data from real users. If you're not currently a RUM customer, you can follow the simple steps in the Setup Guide.
Using RUM in a typical separate-page website requires no additional configuration. SpeedCurve RUM uses the web browser's internal events to determine when a page load started and finished. Measuring pages in a single-page application (SPA) requires a little extra work, because the start and end time of a page vary depending on the SPA's implementation.
APIs
There are four main APIs involved in making RUM work with your SPA:
-
LUX.auto = false - Setting this variable tells SpeedCurve RUM to not send page data automatically. This allows you to determine the end point of your SPA page load.
-
LUX.send() - Call this function when you are ready to send the data that has been collected for the current page view. In most cases this function should be called immediately before
LUX.init()
. -
LUX.init() - Call this function when the user initiates a SPA page transition. For example, if the user clicked a button or link that causes a page transition, you would call
LUX.init()
immediately after the button is clicked. -
LUX.markLoadTime() - Call this function when you consider your SPA to be finished loading. For example, you would call
LUX.markLoadTime()
after all JSON responses have been received and the DOM has been updated. If you don't call this function, the load time will be recorded as the time whenLUX.send()
is called. This function is therefore optional, but recommended.

Using page labels in a SPA
In a SPA, RUM page labels can be set at any point before LUX.send()
is called.
Using custom data in a SPA
Custom Datacan be added at any point in a SPA, and it will be associated with the current page view. Custom data values are persisted across all SPA page views.
Using user timing marks & measures in a SPA
For the initial page load, user timing marks and measures in a SPA work the same as they do in a regular web application. For subsequent SPA pages, measures continue to work the same but marks are taken relative to the previous LUX.init()
call.
Recommended implementation for a SPA
- Set
LUX.auto = false
to gain full control over how data is collected and when the beacon is sent. - Set
LUX.sendBeaconOnPageHidden = true
to reduce data loss due to page abandonment. - Call
LUX.markLoadTime()
when the current page or view has completely rendered — usually at the end of the "mounted" lifecycle callback of various frameworks (componentDidMount
in React,mounted
in Vue v2, etc). - Call
LUX.send()
as late in the page lifecycle as possible to maximize data collection. This can even be called directly beforeLUX.init()
. - Call
LUX.init()
as soon as the user navigates to a new page or view. - (Optional) set
LUX.maxMeasureTime = 30000
if the default time of 60 seconds results in noisy data.
Learn more:
Verifying a SPA implementation
Verifying a SpeedCurve RUM implementation for a SPA can be done in two steps:
- Checking for soft navigation data
- Looking at the Load Time distribution
Checking for soft navigation data
"Soft navigation" refers to a page transition within a SPA. To check whether you are sending soft navigation data to SpeedCurve, open any RUM dashboard. We recommend looking at the RUM Live dashboard so that you can see the most recent user data. Click on Add Filter at the top of the dashboard to add a Page Attribute filter.

Select Page was a soft navigation and set the value to True. Click the Apply button to apply the new filter.

You can now check the data on the dashboard to validate whether soft navigations are being sent to SpeedCurve.
Looking at the Load Time distribution
The Load Time distribution tells you how many users are experiencing different load times. To find your Load Time distribution, open the RUM Performance dashboard. Using the same steps as above, apply a Page Attribute filter with Page was a soft navigation set to False. This ensures we are only viewing the data for full page loads, not soft navigations.
When RUM is implemented correctly in a SPA, the Load Time for full page loads should have a fairly normal distribution, like this:

In some cases, the distribution might show a large number of users with a Load Time of less than 1 second, like this:

This normally happens because LUX.send()
is being called too early, and important performance data is being lost. If your Load Time distribution for full page loads looks like this, you should ensure that LUX.send()
is called immediately before LUX.init()
.
⚠️ Please note that it is normal for Load Time distributions to look like this if you are using LUX.markLoadTime()
. This is because the Load Time for soft navigations is typically much faster than a full page load. This is why we apply the Page Attribute filter when checking the distribution.
Updated 8 days ago