Loader and data-stagepass
Add the loader, tag your assets and use the sp runtime API.
Add the loader
Add the loader to Project Settings, Custom Code, Head Code in Webflow and publish once. Use the major pin @2.
<script src="https://cdn.jsdelivr.net/npm/@stagepass/loader@2/dist/loader.min.js"></script>Options go on the loader tag itself:
<script
src="https://cdn.jsdelivr.net/npm/@stagepass/loader@2/dist/loader.min.js"
data-stagepass-version="2026-11-01"
data-stagepass-session-hours="24"
></script>Tag scripts and stylesheets
Replace src or href with data attributes. Without a session, the loader writes the production URL back, so visitors get the same files as before.
<script
data-src="https://cdn.example.com/app.min.js"
data-stagepass="true"
data-stagepass-path="js/app.js"
></script><link
rel="stylesheet"
data-href="https://cdn.example.com/styles.css"
data-stagepass="true"
data-stagepass-path="css/styles.css"
>During a session the loader builds https://<domain>/<path>?_cb=<timestamp>. Scripts get defer unless you set async or defer yourself, and they run in document order.
Attribute reference
| Attribute | Where | What it does |
|---|---|---|
data-stagepass | Asset | Marks a script or link rel="stylesheet" for Stagepass. Any value counts, use "true" for clarity. |
data-src | Script | Production URL of the script. Loaded for everyone without a session. |
data-href | Stylesheet | Production URL of the stylesheet. |
data-stagepass-path | Asset | Path to the file in your linked folder. Optional. Without it, the file name from the production URL is used. |
data-stagepass-v | Asset | Appends ?v=<value> to the production URL for cache busting. Wins over the loader version. |
data-stagepass-version | Loader tag | Appends ?v=<value> to every tagged production URL. Bump it when you deploy. |
data-stagepass-session-hours | Loader tag | Session lifetime in hours. Default 12. |
data-stagepass-mute-console | Loader tag | With "true", mutes the browser console in production while no session is active. Off by default. |
data-stagepass-staging-hosts | Loader tag | Comma separated host names that count as staging, in addition to *.webflow.io. Used by sp.env() and sp.vars.env. Optional. |
data-stagepass-alias | Loader tag | An extra global name for the API, for example "spx". It must be a valid identifier and is only set when that global is free. Optional. |
<script
src="https://cdn.jsdelivr.net/npm/@stagepass/loader@2/dist/loader.min.js"
data-stagepass-staging-hosts="staging.example.com,preview.example.com"
data-stagepass-alias="spx"
></script>Modes and sessions
| Parameter | Result |
|---|---|
?stagepass=my-project.sp | Local mode. Tagged files load from your .sp domain. |
?stagepass=localhost:5173 | Local mode against a dev server on localhost with that port. |
?stagepass=debug | Debug mode. Stagepass logs, but no files are swapped. |
?stagepass=off, 0 or false | Ends the session. Same as End session in the session card. |
The loader removes the parameter from the address bar and stores the session in localStorage under stagepass_domain, with an expiry. Values other than debug, localhost, localhost:<port> or a valid name ending in .sp are rejected and clear the session.
Global Variables (sp.vars)
Access runtime information via sp.vars (preferred), or stagepass.vars / window.stagepass.vars:
sp.vars.isLocal // boolean - true if Stagepass active or localhost
sp.vars.env // 'local' | 'staging' | 'production'
sp.vars.domain // string - Current domain (local or production)
sp.vars.timestamp // number - Session start time (for cache-busting)
sp.vars.version // string - Loader version
sp.vars.client // object - Client runtime info (theme/browser/os/device/viewport/locale/capabilities)Flat helpers
Short helpers on sp for the most common checks. sp.vars keeps working as before.
sp.env() // 'local' | 'staging' | 'production'
// local = active swap session to a .sp domain
// staging = *.webflow.io or data-stagepass-staging-hosts
sp.is('staging') // boolean
sp.can('localStorage') // also: sessionStorage, cookies, serviceWorker
sp.client('theme') // or sp.client() for the whole object
const off = sp.on('theme', (t) => {}) // also: 'session'; returns unsubscribe
off()
sp.use('my-module', '2.1.0', (api) => { /* register */ })| Helper | What it does |
|---|---|
sp.env() | The current environment: local during a swap session, staging on *.webflow.io or a staging host, otherwise production. |
sp.is(env) | true when sp.env() matches. |
sp.can(feature) | Checks localStorage, sessionStorage, cookies or serviceWorker. |
sp.client(key) | One part of sp.vars.client, or the whole object without a key. |
sp.on(event, fn) | Listens to theme or session changes. Returns a function that removes the listener. |
sp.use(name, version, fn) | Registers a module with its version. The loader checks the major version. |
Client Runtime Info (sp.vars.client)
The loader exposes technical client/runtime data:
sp.vars.client.theme.preferred // 'light' | 'dark' | 'no-preference'
sp.vars.client.theme.current // 'light' | 'dark' | 'unknown' (auto-updated)
sp.vars.client.browser.family // 'chrome' | 'safari' | 'firefox' | 'edge' | 'opera' | 'unknown'
sp.vars.client.browser.major // number | null
sp.vars.client.os.family // 'macos' | 'windows' | 'ios' | 'android' | 'linux' | 'unknown'
sp.vars.client.device.type // 'mobile' | 'tablet' | 'desktop' | 'unknown'
sp.vars.client.device.touch // boolean
sp.vars.client.viewport.width // number (auto-updated on resize)
sp.vars.client.viewport.height // number (auto-updated on resize)
sp.vars.client.viewport.dpr // number (auto-updated on resize)
sp.vars.client.locale.language // string (e.g. 'de-DE')
sp.vars.client.locale.timezone // string | null
sp.vars.client.capabilities.cookiesEnabled // boolean
sp.vars.client.capabilities.localStorage // boolean
sp.vars.client.capabilities.sessionStorage // booleanNotes:
- Browser/OS/device detection is heuristic (best effort).
clientvalues are runtime data, not analytics consent/tracking signals.theme.currentandviewport.*are refreshed while the page is running.
Local URL helper (sp.resolveLocalUrl)
The loader exposes a single place to build local asset URLs (used by modules and by custom code):
// Returns local URL when a Stagepass session is active, otherwise ''
sp.resolveLocalUrl('js/app.js'); // e.g. 'https://my-project.sp/js/app.js?_cb=1234567890'
sp.resolveLocalUrl('/lib.js'); // leading slash is normalizedLogging API
Stagepass provides a structured logging API that wraps the browser console when a Stagepass session is active:
// Preferred API
sp.log('Hello from Stagepass'); // info / log
sp.log('warn', 'Something looks off'); // warn level
sp.log('error', 'Something went wrong'); // error level
sp.warn('This is a warning');
sp.error('This is an error');sp.log automatically prefixes messages with a timestamp and (if available) the calling file and line, e.g. [🎫 11:58:02 | app.js:830]. Logging is only active when a Stagepass session is enabled; otherwise the helper functions are effectively no-ops. During a session the flag counts these warnings and errors together with console.warn, console.error, uncaught errors and failed resources. See Flag states. The deprecated globals splog / spwarn / sperror were removed in v2.
In debug mode the loader warns when several tagged files share the same local file name.
TypeScript types
The loader package ships complete declarations for sp and window.stagepass in global.d.ts, with JSDoc, examples and typed sp.on(...) events. Add the package to your tsconfig.json:
{ "compilerOptions": { "types": ["@stagepass/loader"] } }For module types, see Modules.
Profiles for coding agents
Projects created or upgraded with stagepass new or stagepass upgrade get the sp reference in AGENTS.md automatically, generated from the modules the site loads. See CLI. For projects without the CLI, use one of the following canonical profiles in your project-level AGENTS.md so AI coding agents know exactly which Stagepass runtime APIs are available.
Canonical profile files
- Loader only:
AGENTS.LOADER.md - Loader + Modules (Injector, Cookies and Maintenance):
AGENTS.MODULES.md
How to use
- Copy the relevant file content into your project
AGENTS.md. - Keep only one active profile per project to avoid ambiguous API assumptions.
- If your tooling supports remote include/import in AGENTS files, you can reference the raw GitHub URL instead of copy-paste.