N.B. LUX Sidecar requires a SpeedCurve RUM account. Sign up for a free trial.
LUX Sidecar adds a small set of browser-derived dimensions to
SpeedCurve LUX. It is a companion
script, not a replacement for the LUX agent: it sends its values through
LUX.addData() and relies on LUX to collect and beacon them.
The script is deliberately zero-config. Include it on pages where the standard
LUX snippet has already established window.LUX.addData(), and it will record
the values that the browser makes available for that navigation. Where LUX is
not present, it remains inert.
Load your usual SpeedCurve snippet first, then load LUX Sidecar. The external
LUX agent may load before or after Sidecar; the inline snippet must come first
so that LUX.addData() is available.
<!-- Your standard SpeedCurve LUX snippet goes here. -->
<script>[…]</script>
<script
src=https://cdn.speedcurve.com/js/lux.js?id=YOUR_ID
async
crossorigin=anonymous
></script>
<script src=path/to/lux-sidecar.js defer></script>The supplied file is a classic browser script; no module loader, build step, or initialisation call is required.
LUX Sidecar adds the following custom data when its underlying browser APIs and navigation values are available:
SpeedCurve limits all concatenated custom-data names and values to 500 characters. Sidecar therefore keeps descriptive semantic names in its source while sending compact beacon keys. Configure each SpeedCurve variable using its beacon key and retain the semantic name as its human-readable label.
| Semantic name | Beacon key | Value | Meaning |
|---|---|---|---|
rtt |
rtt |
Number (ms) | The Network Information API’s current navigator.connection.rtt estimate. |
downlink |
dl |
Number (Mbps) | The browser’s rounded, connection-wide estimate of downlink speed. It is not the measured throughput of the document navigation. |
saveData |
sd |
Boolean | Whether the user has asked the browser to reduce data usage. |
cpuTier |
cpu |
Number (tier) | The browser-reported static CPU performance tier from the early CPU Performance API proposal: 0 means unknown; the current proposed tiers are 1–4, with higher values representing more capable hardware, and future tiers may be added. The Chrome design sketch is not approved to ship and proposes HTTPS-only availability. It describes expected hardware capability rather than current CPU load. Configure it as a SpeedCurve dimension, not a metric. |
lcpContentType |
lcpt |
String | The semantic type of the latest Largest Contentful Paint candidate: image when it has a URL, otherwise text. This is inferred from URL presence, not the DOM node name. |
fromCache |
fc |
Boolean | true when the navigation’s transferSize is zero; false when it is greater than zero. No value is added for other values. |
protocol |
p |
String | The application-layer protocol used for the navigation, such as h2 or h3. The value may be empty or may describe the connection to an intermediary rather than the origin. |
contentEncoding |
ce |
String | The browser-reported content coding for the document navigation, such as br, gzip, or zstd. Empty or unavailable values are omitted. |
responseStatus |
rs |
Number | The final HTTP response status exposed for the document navigation. |
viaSW |
sw |
Boolean | Whether the navigation was intercepted by a service worker. |
swStartupTime |
sws |
Number (ms) | Approximate time spent starting or activating the service worker before its fetch event was dispatched. This is not total service-worker request-processing time. |
frombfCache |
bfc |
Boolean | Whether the pageshow event reports that the view was restored from the back/forward cache. |
blockedFrombfCache |
bfcb |
Boolean | true when notRestoredReasons confirms that a history navigation had to reload instead of using bfcache; false when pageshow.persisted confirms a bfcache restoration. Ordinary navigations and browsers without the API are omitted. |
fromPrerender |
pr |
Boolean | Whether the document is currently prerendering, or its navigation has a non-zero activationStart. |
compressionDelta |
cd |
Number (fraction) | The proportion of HTML body bytes saved by content encoding, rounded to at most two decimal places: 0.4 means 40% smaller, 0 means unchanged, and -0.15 means 15% larger. This excludes response headers and is unavailable when the browser masks or omits the body sizes. |
uno |
uno |
Number (ms) | Unattributed Navigation Overhead: the part of time to first byte not covered by the named redirect, DNS, connection, or request-to-response-start phases. |
ttlb |
ttlb |
Number (ms) | Time from navigation start to responseEnd: the complete document-response time, beyond first byte. |
uno and ttlb are rounded to the nearest millisecond and added only when the
result is finite and non-negative.
Tim Vereecke coined the term Unattributed Navigation Overhead to describe TTFB sub-parts that may or cannot be directly attributed due to privacy constraints. Oftentimes, though not always, this is cross-origin redirects. Thus, UNO itself is a residual and derived measurement which represents everything observed but not directly attributable. For each Navigation Timing entry, Sidecar calculates it as:
(responseStart − startTime)
− (redirectEnd − redirectStart)
− (domainLookupEnd − domainLookupStart)
− (connectEnd − connectStart)
− (responseStart − requestStart)
Unavailable or protected phase timestamps contribute zero to their phase, so their elapsed time remains in the residual. This makes UNO useful for exposing time that the browser includes in initial-document TTFB but cannot attribute to the named phases it exposes. Calculate it per navigation before aggregating; subtracting separately calculated percentiles would not represent the same thing.
The script uses Navigation
Timing
and, when exposed by the browser, the Network Information
API
and prerendering state. Missing data is expected: for example, rtt is not
added if navigator.connection.rtt is unavailable, and no navigation-derived
values are added where there is no Navigation Timing entry.
contentEncoding is a nascent Resource Timing addition with limited browser
support. Sidecar feature-detects it and does not infer a value when the browser
does not expose one.
lcpContentType requires Largest Contentful Paint observation support and an LCP
candidate; it is omitted when either is unavailable. It is a semantic type
inferred from LCP URL presence, not the DOM node name.
fromCache is a practical transfer-size heuristic, not a comprehensive cache
taxonomy. It distinguishes zero-byte transfers from transfers that required
network bytes; it does not attempt to classify every cache or revalidation
outcome.
Prerendered views can include work that happened before the user activated the
page. Use fromPrerender to segment those records when interpreting navigation
timings such as UNO and TTLB.
blockedFrombfCache uses the experimental, limited-availability
notRestoredReasons API. Missing values therefore mean ‘unknown or not
applicable’, not ‘eligible for bfcache’.
SpeedCurve creates a separate page view for a bfcache restoration only when its
experimental LUX.newBeaconOnPageShow
setting is enabled. Sidecar does not enable that account-level behaviour, so a
restored view’s frombfCache: true and blockedFrombfCache: false values are
only independently reportable when the host integration opts into it.
LUX Sidecar is released under the MIT License. The licence text is retained in
lux-sidecar.js.

