SpeedCurve LUX
SpeedCurve LUX is a Real User Monitoring (RUM) tool that measures the performance your users experience. It tracks Core Web Vitals, custom timing marks, and JavaScript errors.
Nuxt Config Setup
Add this to your nuxt.config.ts to load SpeedCurve LUX globally. Alternatively you can use the useScriptSpeedCurve composable for more control.
export default defineNuxtConfig({
scripts: {
registry: {
speedcurve: {
trigger: 'onNuxtReady',
}
}
}
})useScriptSpeedCurve()
The useScriptSpeedCurve composable lets you have fine-grain control over when and how SpeedCurve LUX is loaded on your site.
const { proxy } = useScriptSpeedCurve()Please follow the Registry Scripts guide to learn more about advanced usage.
Example
Using SpeedCurve LUX in a component.
<script setup lang="ts">
const { proxy } = useScriptSpeedCurve()
// noop in development, ssr
// just works in production, client
function handleAction() {
// use proxy methods here
}
</script>
<template>
<div>
<button @click="handleAction">
Send Event
</button>
</div>
</template>The composable comes with the following defaults:
- Trigger: Client The LUX primer is injected into
<head>immediately;lux.jsloads when Nuxt hydrates.
Setup
SpeedCurve LUX is opt-in. Register it in scripts.registry.speedcurve to resolve and inline the LUX primer at build time. Install the @speedcurve/lux peer dep alongside:
pnpm add -D @speedcurve/lux
export default defineNuxtConfig({
modules: ['@nuxt/scripts'],
scripts: {
registry: {
// Minimum registration — enables the composable per-page.
// Pass `id` here and you can omit it from each useScriptSpeedCurve() call.
speedcurve: {},
},
},
})
export default defineNuxtConfig({
modules: ['@nuxt/scripts'],
scripts: {
registry: {
speedcurve: { id: 'YOUR_SPEEDCURVE_ID', trigger: 'onNuxtReady' },
},
},
})
If speedcurve isn't registered, useScriptSpeedCurve builds with an empty primer fallback. If it's registered but @speedcurve/lux is missing, the build fails with an install hint. Pinning your own @speedcurve/lux version means you control when the primer snippet updates.
You can access the LUX object as a proxy directly, or await $script to get the loaded instance.
const { proxy } = useScriptSpeedCurve({ id: 'YOUR_ID' })
proxy.LUX.label = 'my-page'
const { onLoaded } = useScriptSpeedCurve({ id: 'YOUR_ID' })
onLoaded(({ LUX }) => {
LUX.label = 'my-page'
})
SPA navigation
Set spaMode: true to enable SpeedCurve's SPA tracking mode. The composable wires Vue Router automatically:
router.beforeEachcallsLUX.startSoftNavigation()(closes the previous beacon, starts a new one)nuxt.hook('page:finish')callsLUX.markLoadTime()after the next paint (sets the END mark)- Cancelled navigations seal the phantom beacon with
addData('luxNavFailed', '1')for easy filtering
useScriptSpeedCurve({
id: 'YOUR_ID',
spaMode: true,
autoTrackSpaNavigations: true, // default when spaMode is true
})
To disable auto-wiring and instrument manually:
useScriptSpeedCurve({
id: 'YOUR_ID',
spaMode: true,
autoTrackSpaNavigations: false,
})
// Then call LUX.startSoftNavigation() and LUX.markLoadTime() yourself
Custom page labels
By default the composable uses String(to.name ?? to.path) as the page label for each navigation. Pass a function to label to override it:
useScriptSpeedCurve({
id: 'YOUR_ID',
spaMode: true,
label: to => to.meta.title as string ?? to.path,
})
Set label: false to disable labeling entirely. Pass a plain string to set a static label (only meaningful without spaMode, since the router hook overwrites it on every navigation).
CSP
Add these directives to your Content Security Policy:
script-src cdn.speedcurve.com;
img-src lux.speedcurve.com;
connect-src lux.speedcurve.com beacon.speedcurve.com;
Reference: https://support.speedcurve.com/docs/add-rum-to-your-csp
idstring required Your SpeedCurve customer ID.
spaModebooleanEnable SPA (single-page application) mode. When true, lux.js tracks soft navigations instead of full page loads.
autoTrackSpaNavigationsboolean = true (when spaMode is true)Automatically wire Vue Router hooks for SPA tracking when spaMode is true. Set to false to instrument navigations manually.
labelstring | Function | false = String(to.name ?? to.path)Page label shown in the SpeedCurve dashboard. Accepts a static string, a function `(to) => string | false` for per-navigation labels, or `false` to disable labeling entirely. A callback returning `false` skips updating the label for that navigation.
sampleratenumberSampling rate (0–100). Percentage of sessions that send beacons. Upstream spelling is lowercase — matches LUX UserConfig.
sendBeaconOnPageHiddenboolean = trueSend the beacon when the page is hidden (pagehide event).
trackErrorsboolean = trueTrack JavaScript errors.
maxErrorsnumber = 5Maximum number of errors to track per page view.
minMeasureTimenumberMinimum time (ms) before a beacon can be sent.
maxMeasureTimenumber = 60000Maximum time (ms) after which the beacon is sent regardless of load state.
newBeaconOnPageShowbooleanStart a new beacon when the page becomes visible after being hidden.
trackHiddenPagesboolean = falseTrack pages loaded in background tabs.
cookieDomainstringCookie domain for cross-subdomain session tracking.
Example
Loading SpeedCurve LUX through app.vue with SPA tracking enabled.
<script setup lang="ts">
useScriptSpeedCurve({
id: 'YOUR_SPEEDCURVE_ID',
spaMode: true,
})
</script>