Frontend Setup: JavaScript/TypeScript via CDN
This guide installs the SF Veritas Recorder SDK directly from the
jsdelivr CDN via a single <script> tag —
no npm install, no bundler, no code changes. Useful for static sites,
Shopify / WordPress / Webflow embeds, server-rendered pages, and any
frontend where adding a build dependency isn't practical.
If your frontend already has a build step (React, Vue, Angular, etc.), prefer the npm install path — you get TypeScript types, the Babel source-map plugin, and smaller per-request download via your existing bundler.
Minimal snippet
Drop this into your page's <head> (or just before </body>) and
you're done:
<script
src="https://cdn.jsdelivr.net/npm/@sailfish-ai/recorder@1.11.6"
data-api-key="<see-api-key-from-your-account-settings-page>"
data-service-identifier="acme-corp/web-app/index.html"
data-service-version="1.0.0"
data-domains-to-propagate-header-to="*"
></script>
That's it. The UMD build auto-initializes when the script executes —
any data-* attributes on the <script> tag are picked up and
forwarded to initRecorder(...) automatically.
/dist/... suffix@sailfish-ai/recorder's package.json declares a jsdelivr entry,
so cdn.jsdelivr.net/npm/@sailfish-ai/recorder@<version> resolves
directly to the UMD build. Shorter + future-proof if the internal
filename ever changes.
How data-* attributes map to initRecorder options
The auto-init reads the <script> tag's dataset and forwards each
entry to the initRecorder({ ... }) call that the npm path would let
you write explicitly. The mapping follows the standard
HTML5 dataset
convention: a camelCase option named fooBarBaz lives at
data-foo-bar-baz="...". Lower-case every word, hyphen between
word boundaries.
A few examples:
initRecorder option | data-* attribute |
|---|---|
apiKey | data-api-key |
serviceIdentifier | data-service-identifier |
serviceVersion | data-service-version |
domainsToPropagateHeaderTo | data-domains-to-propagate-header-to |
enableFiberTracking | data-enable-fiber-tracking |
captureResponseBodyMaxMb | data-capture-response-body-max-mb |
All supported attributes are listed below.
Header, not pluralThe frontend SDK's option is named domainsToPropagateHeaderTo
(singular "Header"). The backend SDK uses the plural
domainsToPropagateHeadersTo. They're two separate options in two
separate SDKs — make sure you copy the right one when moving code
between frontend and backend examples.
Because attribute values are always strings in HTML, non-string options are coerced:
- Arrays (e.g.
data-domains-to-propagate-header-to): comma-separated values. Spaces around commas are trimmed. Example:data-domains-to-propagate-header-to="*.acme.com,api.acme.com". - Booleans (e.g.
data-enable-fiber-tracking): the literal string"true"enables the flag; anything else (including"false"or the attribute being absent) leaves the SDK default. - Numbers (e.g.
data-capture-response-body-max-mb): parsed withNumber(). Non-numeric values are silently ignored.
Full attribute reference
Required
| Attribute | Type | Description |
|---|---|---|
data-api-key | string | Your Sailfish Enterprise API key. Auto-replaced for logged-in readers as <ApiKey />. |
Service identification
| Attribute | Type | Default | Description |
|---|---|---|---|
data-service-identifier | string | "" | Unique identifier in <org>/<repo>/<path> format. |
data-service-version | string | "" | Version of your application. |
data-git-sha | string | Auto-detected | Git commit SHA for version tracking. Usually set by your build pipeline. |
Domain allowlist / blocklist
| Attribute | Type | Default | Description |
|---|---|---|---|
data-domains-to-propagate-header-to | CSV | [] | Domains that SHOULD receive tracing headers. Supports wildcards (*.example.com, api.example.com/v1/*). Auto-replaced for logged-in readers as <AllowedDomainsCsv />. |
data-domains-to-not-propagate-header-to | CSV | see below | Domains to EXCLUDE from header propagation. |
By default, tracing headers are not propagated to common third-party services (Twitter, Gravatar, Zendesk, AWS, etc.) to avoid CORS issues. See the Header Propagation section of the npm guide for the default exclusion list.
Network body capture
| Attribute | Type | Default | Description |
|---|---|---|---|
data-capture-streaming-response-body | boolean | true | Capture a limited prefix of streaming response bodies. Set to "false" to disable. |
data-capture-response-body-max-mb | number | 10 | Maximum response body size (MB) to capture. |
data-capture-stream-prefix-kb | number | 64 | Maximum prefix size (KB) to capture from streaming responses. |
data-capture-stream-timeout-ms | number | 10000 | Timeout (ms) for streaming prefix capture. |
Performance
| Attribute | Type | Default | Description |
|---|---|---|---|
data-defer-recording | boolean | true | Defer heavy DOM recording until after the page is interactive. |
data-chunk-snapshot | boolean | false | Break the initial full-DOM snapshot into async chunks. |
data-use-ws-worker | boolean | false | Route the WebSocket ingest through a Web Worker to keep it off the main thread. |
Tracking
| Attribute | Type | Default | Description |
|---|---|---|---|
data-enable-fiber-tracking | boolean | true | Enable React Fiber tracking — adds data-sf-source attributes to DOM elements. Has no effect if React isn't present. |
data-enable-ip-tracking | boolean | false | Fetch visitor IP in the background for session metadata. |
Issue reporting
| Attribute | Type | Default | Description |
|---|---|---|---|
data-custom-base-url | string | — | Custom base URL for the triage / report-issue interface. |
data-show-eng-ticket-fields-in-report-issue-modal-default | boolean | false | Show engineering-ticket fields (stack trace, session ID, etc.) in the report-issue modal by default. |
Advanced / internal
| Attribute | Type | Default | Description |
|---|---|---|---|
data-library | string | "JS/TS SNIPPET" | Identifier telemetry uses to tag which integration sent the event. Leave as default unless you have a specific need to override. |
Options only available via npm
Two initRecorder options take structured-object values that HTML
data-* attributes can't reasonably carry:
serviceAdditionalMetadata— aRecord<string, any>of custom metadata merged onto every session.reportIssueShortcuts— aPartial<ShortcutsConfig>controlling keyboard shortcuts for the report-issue modal.
If you need either of these, switch to the npm install
path and call initRecorder({ ... })
directly. Everything else from the CDN snippet is equally available
via npm.
Verifying the setup
- Deploy your page with the
<script>added. - Load the page in a browser. Open devtools → Network and
confirm the request to
cdn.jsdelivr.net/npm/@sailfish-ai/recorder@<RecorderVersion />returns200. - Open the Sailfish dashboard and trigger some activity on the page — you should see telemetry appearing within a few seconds.
Troubleshooting
Script 404s on jsdelivr
Double-check the version pin. @<RecorderVersion /> in the snippet
above is substituted by the docs site to the current published
version when you're signed in; if you copy the markdown source
verbatim (unsubstituted), replace it with a concrete version from
npm.
Script blocked by Content Security Policy (CSP)
Allow cdn.jsdelivr.net in your script-src directive:
Content-Security-Policy: script-src 'self' https://cdn.jsdelivr.net;
If you use a strict nonce-based policy, add the nonce to the
<script> tag: <script nonce="..." src="..." data-...></script>.
Tracing headers not appearing on cross-origin requests
Browser CORS rules only allow the sailfish-trace header through if
your server explicitly opts in via
Access-Control-Allow-Headers: sailfish-trace. Add that header on
the receiving service, or include it in the preflight response. The
allowlist (data-domains-to-propagate-header-to) controls which
domains the SDK attempts to add the header to — the browser's CORS
layer has the final say.
Nothing appears in the Sailfish dashboard
- Confirm
data-api-keyis set and the value is correct (or<ApiKey />rendered to a real UUID for logged-in readers). - Check the browser console for errors prefixed with
Sailfish. - Verify the script loads before the events you want to capture. If you load it late (e.g. deferred, lazy-loaded after user interaction), the SDK will miss everything prior.
Next steps
- Check the Sailfish dashboard to verify telemetry is flowing.
- For deeper customization (custom metadata, keyboard shortcuts, source-file tracking via Babel plugin), switch to the npm install path.
- Set up your backend application for full-stack observability.