Tools

Embed Script

The os.js script is the single entry point that powers analytics, widgets, and the SDK on your site.


Installation#

Add the script tag to every page where you want tracking and widgets. It loads asynchronously and won’t block page rendering.

index.html
<script src="https://operatorstack.dev/os.js"  data-project="pk_xxxxx"  data-chat="false"  data-dev="true"></script>

How it works#

When the script loads, it performs these steps in order:

  1. Reads the data-project key from the script tag
  2. Fetches your project configuration (cached for 5 minutes in localStorage)
  3. Starts tracking page views and events automatically
  4. Renders any widgets found on the page (Shadow DOM isolated)
  5. Exposes the window.OperatorStack SDK
  6. Resolves the ready promise

Configuration caching#

Project configuration is cached in localStorage using a stale-while-revalidate strategy:

  • Production: 5-minute TTL. Serves cached config immediately, fetches fresh in background.
  • Dev mode: No caching. Always fetches fresh config.

Data attributes#

Property Type Description
data-project *stringYour project key (e.g., pk_xxxxx). Required.
data-api stringOverride the API base URL (for self-hosted deployments)
data-chat stringSet to "false" to suppress the chat bubble on this specific page. Useful for pages where chat is distracting. (default: "true")
data-dev stringSet to "true" for development mode: disables config caching, enables console logging. (default: "false")
Enable dev mode with data-dev="true" to see configuration changes immediately without waiting for the cache to expire.

Event batching#

Events are queued and sent in batches for performance:

  • First batch sends immediately (via setTimeout(0) to coalesce synchronous init events)
  • Subsequent events flush every 5 seconds
  • On page unload or tab hide, remaining events are sent via sendBeacon

Event types#

The following event types are tracked automatically or can be sent via the SDK:

Property Type Description
page_view autoFired on every page load
widget_impression autoFired when a widget is rendered on the page
waitlist_signup autoFired on successful waitlist submission
form_submission autoFired on form submission
contact_message autoFired on contact form submission
referral_conversion autoFired when a referred visitor signs up
chat_opened autoFired when chat bubble is opened
chat_closed autoFired when chat window is closed
chat_message_sent autoFired when visitor sends a chat message
console_error autoJavaScript errors from the host page (max 1,000/day)
performance autoCore Web Vitals (TTFB, FCP, LCP, CLS, INP) when performance monitoring is enabled
custom SDKCustom events via trackEvent() (max 10,000/day)

Shadow DOM isolation#

All widgets render inside Shadow DOM, which means:

  • Widget styles won’t leak into your page
  • Your page styles won’t affect widget appearance
  • Each widget is self-contained with its own scoped CSS

Widget HTML attributes#

Place these elements anywhere on your page. The embed script finds and replaces them with rendered widgets.

<!-- Waitlist signup form --><div data-os-widget="waitlist"></div> <!-- Contact form --><div data-os-widget="form" data-os-form="contact"></div> <!-- Custom form (by form key) --><div data-os-widget="form" data-os-form="frm_abc123"></div>

Visitor identification#

OperatorStack uses a three-tier fallback strategy for visitor identification, with no cookies required:

visitor_idlocalStorage UUID

Most stable identifier. A random UUID generated on first visit and stored in localStorage. Persists across sessions on the same browser.

client_visitor_hashBrowser fingerprint

SHA-256 hash of User-Agent, screen resolution, language, timezone, and hardware info. Stable across sessions and survives localStorage clearing. Does not rotate.

visitor_hashServer-side hash

SHA-256 hash of IP + User-Agent + Accept-Language + month. Computed server-side as final fallback. Rotates monthly.

Do Not Track#

When a visitor’s browser sends the DNT: 1 header and your project has “Respect Do Not Track” enabled, the script skips all analytics tracking. Widgets and the SDK still function normally.

API endpoints#

GET/v1/projects/{projectKey}/configPublic
Fetch project configuration including all enabled widgets and settings.
POST/v1/projects/{projectKey}/events/batchPublic
Submit a batch of analytics events. Returns 202 Accepted immediately.