import { init } from '@everframe/web';
const everframe = init({
apiKey: 'evf_live_…',
appVersion: '2.4.0',
console: { maxEntries: 100, levels: ['warn', 'error'] },
});
Core
| Option | Type | Default | What it does |
|---|---|---|---|
apiKey | string | — | Required. Your app’s SDK key. Publishable — it only grants report submission, so shipping it in a web bundle is the intended use. |
appName | string | see below | Name recorded in context.app. Nothing is detected for you — set it. |
appVersion | string | '0.0.0' | Version recorded in context.app. Nothing is detected for you — wire it to your build. |
appBuild | string | — | Exact deployed build ID or commit SHA, recorded in context.app.build on errors and user-filed reports. |
disabled | boolean | false | Stops capture, patching, the outbox, config fetching and crash handling. init() still mounts the host element and the hotkey, and the reporter can still open — it is not an uninstall. destroy() is. |
debug | boolean | false | Installs the replay diagnostic seam. It does not turn on verbose console logging. |
onError | (err) => void | — | Called when a safe-wrapped public client call fails. Not every internal async failure routes here. |
Unset, appName falls back to 'unknown-app' on a submitted report and
'unknown' on an unattended crash report — two placeholders on two code paths,
which is its own reason to set it.
Reporter trigger
The SDK installs the app’s dashboard-configured report hotkey. It defaults to
Mod+Shift+B (Cmd+Shift+B on macOS and Ctrl+Shift+B elsewhere). The
dashboard value is authoritative and cannot be replaced through SDK config.
Capture
| Option | Type | Default | What it does |
|---|---|---|---|
console.maxEntries | number | 100 | Console ring-buffer capacity. |
console.levels | string[] | all five | log, info, warn, error, debug. Narrowing to ['warn','error'] is the cheapest way to shrink reports on a chatty app. |
network.maxEntries | number | 100 | Network ring-buffer capacity. |
sessionReplay.disabled | boolean | false | Never start the replay buffer. |
networkBodies.disabled | boolean | false | Never capture request/response bodies. |
crashReporting.disabled | boolean | false | Suppresses automatic error reports and captureException(). |
installIdentifier.disabled | boolean | false | Stops this app sending its install identifier, which counts distinct installs toward your plan’s usage. Not retroactive — installs already counted this month stay counted. |
redaction | object | built-in rules | See Redaction. |
sessionReplay.disabled and networkBodies.disabled are client vetoes over
a server gate: the effective state is serverEnabled && !disabled, so a client
can turn those off and can never turn them on. See
Server config.
crashReporting.disabled, installIdentifier.disabled and redaction have no
server gate — they are plain local settings.
Replies
| Option | Type | Default | What it does |
|---|---|---|---|
replies.disabled | boolean | false | No polling, no UI, no reply token on submit. |
replies.ui | 'default' | 'headless' | 'default' | headless renders no reply UI — you consume everframe.threads.* and build your own. |
replies.pollIntervalMs | number | 60 000 | Poll cadence. Floored to 60 s regardless of what you pass. |
Browser specifics
| Option | Type | Default | What it does |
|---|---|---|---|
cspNonce | string | — | Threaded into the screenshot library and injected styles. Required under a strict CSP, or the reporter renders unstyled. |
theme | ReporterTheme | — | Reporter colours, paid plans only. See Branding. |
__everframeShadowDom | boolean | true | Render the reporter inside a Shadow DOM for style isolation. |
Opting out of the shadow root renders into a plain <div> and puts the
stylesheet in the document head instead, at which point the reporter inherits
your page’s CSS and can be broken by it. It exists for tooling that cannot
pierce shadow roots — some e2e frameworks, some screen-reader automation — and
is not a styling hook. Unlike the rest of this table, this one is honoured
only here: @everframe/react re-exports the same config type but portals the
reporter into document.body unconditionally, so setting it there does nothing.
The handle
init() returns the imperative surface. Config is set once; these are called
whenever.
const everframe = init({ apiKey: 'evf_live_…' });
| Method | What it does |
|---|---|
open() | Opens the reporter. Resolves { status: 'submitted' | 'queued' | 'cancelled', … }. Rejects if the handle was destroyed or the reporter is not mounted. |
setUser(user) | Attach or clear the end user on future reports. See Identity. |
setIdentityToken(source) | Supply a verified identity instead of a self-asserted one. |
addBreadcrumb(input) | Add a custom entry to the trail. See Breadcrumbs. |
captureException(error, options?) | Report a caught failure with optional severity, context, and metadata. Returns void; delivery uses the outbox. See Crash reporting. |
setExtra(value) | Free-form metadata carried on every later report — a string, an object, or a resolver function (see below); each call replaces the last. Capped at 16 KiB — see Errors & limits. |
threads | List, read and reply to reply threads from this device. |
kill() | Stops this instance capturing or submitting anything further. |
destroy() | Full teardown — hotkey, listeners, polling, host element, client. Safe to call twice. |
There is deliberately no markSensitive() on this handle. Masking is driven
entirely by the two surfaces in Sensitive content; a
method of that name exists on @everframe/react’s hook but has never been wired
to anything, and this handle does not inherit a privacy call that silently does
nothing.
The three forms of setExtra
everframe.setExtra('checkout, card declined'); // string
everframe.setExtra({ cartId, step, flags }); // object — serialised for you
everframe.setExtra(() => ({ cartId, step: currentStep })); // resolver — preferred
Prefer the resolver. It runs once per report, at assembly time, so what it
returns reflects your state when the bug happened rather than whenever you last
called setExtra. The other two forms freeze a snapshot at call time, which
goes stale the moment anything changes.
Each call replaces the last, whichever form you use. The payload is capped at
EXTRA_MAX_CHARS (16 KiB, exported from @everframe/web); an over-budget
payload is dropped, not trimmed — see Errors & limits.
kill() versus disabled versus destroy()
Three ways to stop the SDK, and they are not interchangeable:
| Stops capture | Stops submission | Removes the UI | Reversible | |
|---|---|---|---|---|
disabled: true | Yes | Yes | No — hotkey and reporter still mount | Only by re-initialising |
kill() | Yes | Yes | No — mounted UI and seams stay | No |
destroy() | Yes | Yes | Yes | Call init() again |
kill() is the consent control. After it lands nothing is captured and nothing
leaves the device — including a reporter that is already open: pressing Send
discards the report, shows “Reporting is turned off — this report was not sent.”,
and settles the pending open() as cancelled. Use it when a user withdraws
consent mid-session; use destroy() when you are unmounting the app.
Precedence
Three things can set the same value. Highest wins:
- Server config — plan entitlements and per-app settings from
GET /api/config - This config object
- SDK defaults
With one asymmetry: for the gated features above, local config can only ever subtract. That is deliberate — a customer can disable capture for privacy reasons without being able to enable something their plan does not include.