SDK reference
The script tag and the npm package (@spectosh/browser) share one recorder. This page lists everything you can configure and call.
Recording starts at once
The recorder captures from the moment it starts: errors, console output, requests and the page itself are held in memory while the project's settings load (one request, cached at the edge), then filtered by those settings and sent — or dropped, if the project is paused, sampled out or doesn't know the key. So start it as early as you can: the script tag first in <head>, startRecording() in your entry file before the app renders, or SpectoProvider at the root.
Keys know where they live
A key is all an install needs. pk_… belongs to the hosted service; a project in another region or on a self-hosted instance has a key that says so — pk_…@eu.specto.sh, pk_…@replay.example.com — and its Install page shows it that way. The settings request also confirms the key: a host that doesn't know it records nothing, and the console says why, so a key without its host never sends data to the wrong place.
Script tag
<script src="https://specto.sh/specto.js" data-key="pk_your_key" defer></script>
| Attribute | Values | Effect |
|---|---|---|
data-key | pk_… | Required. The project’s publishable key (Settings → Install). |
data-host | host | Where the project lives. Defaults to the host that served the script (or the key's own @host). |
data-endpoint | URL | Full ingest URL (legacy; overrides data-host). |
data-privacy | strict | Mask all text, not only inputs; drop console text and the query strings of recorded URLs. |
data-sample-rate | 0–1 | Fraction of sessions recorded, decided once per session. |
data-consent | required | Record and store nothing until Specto.consent(true). |
data-console | false | Skip console capture. |
data-details | false | Skip network request details (method, URL and status are still kept). |
data-feedback | true | Add a floating feedback button wired to your inbox. |
data-traces | true | Send a W3C traceparent header with same-origin requests, so backend traces join the replay. |
data-trace-origins | origins | More origins for that header, comma-separated (their CORS must allow it). |
window.Specto
| Call | Does |
|---|---|
Specto.identify(id, traits) | Attach your user id (up to 256 characters) and up to 25 flat traits (string, number or boolean; strings up to 256 characters) to the session. Use an opaque id rather than an email where you can. |
Specto.track(name, props) | Add a custom event to the timeline. String props are scrubbed and cut to 500 characters. |
Specto.captureError(error) | Report an error your app caught itself — it shows on the timeline and in Issues like an uncaught one. |
Specto.consent(true | false) | Consent mode: true starts recording (and remembers it); false stops and forgets it. |
Specto.optOut() | Stop now and never record this browser again. |
Specto.optIn() | Undo optOut() and start again. |
Specto.sessionUrl() | A link to this session’s replay — handy in support tickets. |
Specto.stop() | Stop capturing and restore everything the recorder patched. |
Specto.session | The active recorder, or undefined when nothing is recording. |
Specto.init(options) | Start by hand when the script tag has no data-key (same options as below, plus feedback). |
npm package
npm install @spectosh/browserimport { startRecording, identify, track } from '@spectosh/browser' // in your entry file, before the app renders const rec = startRecording({ key: 'pk_your_key' })
| Export | Does |
|---|---|
startRecording(options) | Start recording; returns the recorder. Calling it again while recording returns the same recorder. |
identify(id, traits) | As Specto.identify. |
track(name, props) | As Specto.track. |
captureError(error, info) | As Specto.captureError; info.componentStack rides along. |
sessionUrl() | As Specto.sessionUrl. |
stopRecording() | Stop the active recorder. |
grantConsent() | Consent mode: remember consent and start with the last options. |
revokeConsent() | Forget consent and stop. |
optOut() / optIn() | As on window.Specto. |
hasConsent() / isOptedOut() | Read the stored choice. |
scrubText(text) | The redaction the SDK applies to console lines and errors (emails, tokens, card-like numbers). |
SDK_VERSION | The package version. |
TypeScript types ship with the package — for @spectosh/browser and @spectosh/browser/react.
Options
| Option | Default | Meaning |
|---|---|---|
key | — | Required. pk_…, or pk_…@host for a project in another region or on a self-hosted instance (copy it from the Install page). |
host | the key's | Where the project lives, overriding the key's — e.g. your own domain proxying to Specto. |
endpoint | — | Full ingest URL (legacy; overrides host). |
privacy | 'balanced' | 'strict' masks all text, drops console text and keeps only the path of recorded URLs. |
sampleRate | 1 | Fraction of sessions recorded. |
consent | 'granted' | 'required' waits for consent. |
console | true | Capture console output. |
networkDetails | true | Capture request details (timing, sizes, a few response headers). |
configUrl | the host's /api/sdk/config | Where the project's settings are fetched; false skips it (and the key check). |
traces | false | Send a traceparent header with same-origin requests (backend traces). |
traceOrigins | [] | More origins to send it to. |
The recorder
| Property | Meaning |
|---|---|
rec.sessionId | The current session id. |
rec.sessionUrl() | Link to the replay. |
rec.flushNow() | Upload what is buffered right away. |
rec.stop() | Stop and restore everything the recorder patched. |
rec.disabled, rec.reason | Set when nothing is being recorded: dnt, opted-out, consent-required, not-sampled, recording-disabled, unknown-key (the host has no such project), unconfirmed (the hosted service couldn't be asked about a key without a host) or stopped. |
React
@spectosh/browser/react starts the recorder from your app's root, catches the errors React swallows, and gives components a hook. React is a peer dependency (17 and later).
import { createRoot } from 'react-dom/client' import { SpectoProvider, spectoErrorHandler } from '@spectosh/browser/react' createRoot(document.getElementById('root'), { onCaughtError: spectoErrorHandler(), // React 19 onUncaughtError: spectoErrorHandler(), }).render( <SpectoProvider apiKey="pk_your_key" user={user}> <App /> </SpectoProvider> )
| Export | Does |
|---|---|
<SpectoProvider apiKey user …options> | Starts recording during its first render — before any component's effects run, so the first requests of a page load are captured. Once per page: StrictMode, remounts and hot reloads reuse the running recorder, and unmounting never stops it. On the server it renders its children and nothing else. user ({ id, …traits }) is identified whenever it changes; every other prop is a startRecording option. |
useSpecto() | identify, track, captureError, sessionUrl, stop and the consent controls. |
<SpectoErrorBoundary fallback> | An error boundary that reports what it catches with the component stack. fallback is an element or ({ error, reset }) => …. The way to catch render errors on React 18. |
spectoErrorHandler(next?) | For React 19's createRoot options onCaughtError, onUncaughtError and onRecoverableError: reports the error, then calls next — or logs it, as React does by default. |
An error reported by both a boundary and a root handler is recorded once. Next.js, Remix and the other frameworks: framework guides.
Project settings win when stricter
At start the SDK fetches the project's settings (Settings → Privacy, cached at the edge) — the same request confirms the key. The stricter of those and your options applies: the dashboard can pause recording, force strict privacy, turn off console or request details, or lower the sample rate without a redeploy. Ingest enforces the same settings server-side.
Sessions, storage and limits
A session continues across page loads in the same tab (each load is recorded as a navigation, so funnels see every page), ends after 30 minutes without interaction and rotates after 4 hours. Batches upload every few seconds from a Web Worker, are numbered so retries never duplicate data, and the tail goes out with sendBeacon when the page is hidden. A full DOM checkpoint every 5 minutes keeps a lost batch from ruining a replay.
| Stored | Where | Why |
|---|---|---|
| the session | sessionStorage | continue the session across page loads in this tab |
specto-vid | localStorage | a random visitor id for retention cohorts (no fingerprinting) |
specto-consent | localStorage | the visitor’s consent, in consent mode |
specto-optout | localStorage | the visitor opted out |
No cookies. Visitors with Do-Not-Track or Global Privacy Control turned on are never recorded. More: privacy controls, consent banners, troubleshooting.

