Install ClickStream

Every ClickStream tenant installs through its own first-party tracking domain. You add a CNAME on t.yourdomain.com → ClickStream, we verify it and provision SSL, then your SDK loads from your own hostname. We don't sell direct access to our collector or SDK CDN endpoints — first-party is the only supported mode.

This page assumes you've already run through the dashboard account setup and DNS provisioning flow described in First-party tracking (required). If you haven't: do that first — the SDK's domain gate will reject events sent to a hostname that isn't registered to your API key.

What you need before you start

  1. A ClickStream account at einstein.clickstream.com with at least one site created.
  2. An API key (cs_live_… or cs_test_…) minted from the dashboard. You paste the key once into the data-key attribute; no secrets leave the SDK bundle.
  3. A first-party tracking subdomain (e.g. t.example.com) that's already verified and active in the dashboard. The green "Active" badge next to the hostname is the gate.

Pick your platform first

ClickStream has three property types. The type you create in Einstein decides which key you get and how you install. Pick the one that matches what you are tracking:

Property typeWhat it tracksKey you getHow you install
WebsiteA web property with a domain and DNS.Your shared account key (cs_live_*), domain-gated.Script tag or @clickstreamhq/sdk — runs in the browser.
Mobile appA native iOS / Android / React Native app. No URL, no DNS.A dedicated mobile key (cs_mob_live_*), provenance-exempt.@clickstreamhq/react-native or direct REST from Swift / Kotlin.
ServerBackend / server-to-server event ingestion. No URL, no DNS.A dedicated server key (cs_srv_live_*), provenance-exempt.Direct REST from your backend, or @clickstreamhq/next server helpers.

Website keys require a browser Origin/Referer that matches your configured domains. Mobile and server keys skip that gate — that is what lets a native app or a backend call POST /v1/events directly with no spoofed Origin and no fake web URL. Create the matching property type in the dashboard; do not reuse a website key off the web.

Choose the install for the outcome you want

Most websites should start with the script tag, then add Edge capture when they want proof for traffic that does not run JavaScript.

GoalInstall thisResult
Measure human behavior on a websiteBrowser SDK script tag or @clickstreamhq/sdkPageviews, clicks, forms, sessions, identity, and behavior scores.
Use Signals in page code@clickstreamhq/signals or @clickstreamhq/reactHuman-only UI and lane-aware behavior.
Measure AI/search and crawler coverageCloudflare Edge captureNon-JavaScript requests appear in Human + AI Traffic and Signals coverage proof.
Stream events into your own systemsSignals FeedReal-time labeled event feed for Scale tier and above.
Track a native mobile app@clickstreamhq/react-native or direct REST with a cs_mob_live_* keyScreen views, taps, identity events, and Signals snapshots — no DOM, no Origin.
Send events from a backendDirect REST with a cs_srv_live_* key (device.clientPlatform: 'server')Server-to-server custom/identify events with no browser provenance.

Script tag (recommended — all stacks)

Paste this into your site's <head>:

<script
  src="https://t.example.com/sdk.js"
  data-key="cs_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  async
></script>

Replace t.example.com with your registered tracking domain. The SDK loader is domain-scoped — the collector verifies the request origin against the domains configured for your API key and rejects mismatches. Put this tag on every page; the SDK handles SPA route changes internally.

That's it. Pageview / click / session events start flowing to the dashboard within seconds.

Cloudflare edge capture for crawlers and answer engines

The browser SDK is the source of truth for human interaction. Search crawlers, answer engines, link previews, monitors, and other non-JavaScript clients often never run that SDK, so ClickStream also supports a first-party Cloudflare Worker install.

Use both layers when you want complete Signals coverage:

The onboarding Add Code → Cloudflare Edge Capture tab generates a Worker snippet with your API key and tracking hostname already filled in. Paste it into a Cloudflare Worker or Pages _worker.js in front of your site. See Edge capture for the full install, verification commands, and expected dashboard display.

After both layers are installed, use Signals API for page-code decisions and Signals coverage proof to confirm that human traffic, AI/search coverage, monitoring, automation, and review traffic stay in separate lanes.

NPM / pnpm / yarn (modern web apps)

For build-tool-managed browser apps, use @clickstreamhq/sdk to install the same first-party pixel you would otherwise paste as a script tag. The public package intentionally exposes the pixel installer helpers only; the full browser tracker runs from your first-party tracking domain after the helper injects the script.

pnpm add @clickstreamhq/sdk
import { installClickstreamPixel } from '@clickstreamhq/sdk';

installClickstreamPixel({
  apiKey: 'cs_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  endpoint: 'https://t.example.com', // your first-party tracking domain — required
  replay: true,
});

The helper appends <script src="https://t.example.com/sdk.js?key=..."> for you and copies safe data-* options onto the script. Point endpoint at the same t.example.com hostname you verified in the dashboard. Events sent to an unregistered hostname are rejected with 403 domain_not_allowed.

Public exports:

Use the browser global exposed by the loaded pixel for event calls:

import { installClickstreamPixel } from '@clickstreamhq/sdk';

installClickstreamPixel({
  apiKey: 'cs_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  endpoint: 'https://t.example.com',
});

window.clickstream?.trackEvent({ name: 'docs_filter_changed', category: 'interaction' });
await window.clickstream?.identify('user@example.com');

Full reference: Browser pixel helper.

React — @clickstreamhq/react

pnpm add @clickstreamhq/sdk @clickstreamhq/react @clickstreamhq/signals
// app/providers.tsx (or similar root component)
'use client';

import { useEffect } from 'react';
import { installClickstreamPixel } from '@clickstreamhq/sdk';
import { ClickStreamProvider } from '@clickstreamhq/react';

export function Providers({ children }: { children: React.ReactNode }) {
  useEffect(() => {
    installClickstreamPixel({
      apiKey: process.env.NEXT_PUBLIC_CLICKSTREAM_KEY!,
      endpoint: 'https://t.example.com',
      replay: true,
    });
  }, []);

  return (
    <ClickStreamProvider
      apiKey={process.env.NEXT_PUBLIC_CLICKSTREAM_KEY!}
      endpoint="https://t.example.com"
    >
      {children}
    </ClickStreamProvider>
  );
}

ClickStreamProvider configures the Signals client. The pixel installer loads the tracker that creates _cs_uid / _cs_sid, sends events, and exposes window.clickstream.identify() and window.clickstream.trackEvent() for the React hooks.

'use client';

import { useVisitor, useIdentify, useTrack } from '@clickstreamhq/react';

export function HelpPanelButton() {
  const { ctx: visitor } = useVisitor();
  const identify = useIdentify();
  const track = useTrack();

  const isHuman = visitor?.behavioralClass === 'human' && visitor?.bot.isBot === false;

  return (
    <button
      onClick={async () => {
        track({ name: 'help_panel_opened', category: 'interaction' });
        await identify('user@example.com');
      }}
    >
      {isHuman ? 'Open help panel' : 'View help'}
    </button>
  );
}

Full reference: React adapter.

Next.js (App Router) — @clickstreamhq/next

Next.js apps usually combine three pieces: the browser pixel installer for tracking, the React provider for client components, and the Next adapter for Server Components / Route Handlers / edge middleware.

pnpm add @clickstreamhq/sdk @clickstreamhq/next @clickstreamhq/react @clickstreamhq/signals
// app/providers.tsx
'use client';

import { useEffect } from 'react';
import { installClickstreamPixel } from '@clickstreamhq/sdk';
import { ClickStreamProvider } from '@clickstreamhq/react';

export function Providers({ children }: { children: React.ReactNode }) {
  useEffect(() => {
    installClickstreamPixel({
      apiKey: process.env.NEXT_PUBLIC_CLICKSTREAM_KEY!,
      endpoint: 'https://t.example.com',
      replay: true,
    });
  }, []);

  return (
    <ClickStreamProvider
      apiKey={process.env.NEXT_PUBLIC_CLICKSTREAM_KEY!}
      endpoint="https://t.example.com"
    >
      {children}
    </ClickStreamProvider>
  );
}
// middleware.ts — optional edge prefetch of VisitorContext
import { clickStreamMiddleware } from '@clickstreamhq/next/middleware';

export default clickStreamMiddleware({
  apiKey: process.env.CLICKSTREAM_API_KEY!,
  endpoint: 'https://t.example.com',
  prefetch: true,
});

export const config = { matcher: ['/docs', '/account/:path*', '/settings/:path*'] };
// app/docs/page.tsx — Server Component
import { getServerVisitor } from '@clickstreamhq/next/server';

export default async function DocsPage() {
  const { visitor } = await getServerVisitor({
    apiKey: process.env.CLICKSTREAM_API_KEY!,
    endpoint: 'https://t.example.com',
  });
  if (visitor && visitor.scores.intent >= 70) return <DetailedDocs />;
  return <DefaultDocs />;
}

Full reference: Next.js adapter.

Vue.js

Vue apps can use either the script-tag install or @clickstreamhq/sdk. The browser pixel exposes window.clickstream for simple page code and window.cs for the tracker instance. Wrap the bridge in an idiomatic composable:

<!-- public/index.html -->
<script
  src="https://t.example.com/sdk.js"
  data-key="cs_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  async
></script>
// src/composables/useClickstream.ts
import { onMounted, ref } from 'vue';

export function useClickstream() {
  const tracker = ref<any>(null);
  onMounted(() => {
    const cs = (window as any).clickstream;
    if (!cs) {
      console.warn('[clickstream] SDK loader not yet ready');
      return;
    }
    tracker.value = cs;
  });
  return tracker;
}

Use tracker.value?.trackEvent({ name: 'help_panel_opened' }) inside components. A dedicated @clickstreamhq/vue adapter is not currently shipped.

Mobile apps — @clickstreamhq/react-native

Native mobile is its own property type with its own key. Create a Mobile app property in Einstein (no URL, no DNS) — it mints a dedicated cs_mob_live_* key that is exempt from the browser Origin gate. That key, plus a device.clientPlatform field on every event, is the whole mobile contract. There is no spoofed Origin header and no fabricated web URL.

For React Native and Expo, use the supported package:

pnpm add @clickstreamhq/react-native @react-native-async-storage/async-storage
import AsyncStorage from '@react-native-async-storage/async-storage';
import { AppState } from 'react-native';
import { createClickStream } from '@clickstreamhq/react-native';

export const cs = createClickStream({
  apiKey: 'cs_mob_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', // Mobile app key
  endpoint: 'https://t.example.com',                     // your first-party collector domain
  storage: AsyncStorage,
  appStateProvider: AppState,
});

cs.screen('CheckoutScreen', { title: 'Checkout' });
cs.tap('add_to_cart', { value: 1 });
cs.identify('user@example.com', { customerId: 'user_12345' });

The tracker is Hermes-safe (no crypto.subtle, no DOM), batches and persists events through AsyncStorage, rotates sessions on AppState foreground transitions, and re-exports Signals on the /signals subpath. For native iOS (Swift URLSession) and Android (Kotlin OkHttp), use direct REST with the same mobile key and device.clientPlatform.

For the full native pattern — React Native, Swift, Kotlin, identity hashing, native bot semantics, and Signals reads — see Mobile apps.

Server / backend — cs_srv_live_*

To send events from a backend, create a Server property in Einstein. It mints a cs_srv_live_* key that is also provenance-exempt. Set device.clientPlatform: 'server' and use a logical route as page.path (no http URL required):

POST https://t.example.com/v1/events HTTP/1.1
X-API-Key: cs_srv_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "type": "custom",
  "visitorId": "cs_visitor_abc",
  "sessionId": "cs_session_xyz",
  "timestamp": 1713797640000,
  "name": "subscription_renewed",
  "page": { "path": "billing/renewal", "title": "Renewal" },
  "device": { "userAgent": "acme-backend/1.0", "viewport": { "width": 0, "height": 0 }, "clientPlatform": "server" }
}

Next.js apps can read VisitorContext server-side with @clickstreamhq/next/server using the same server key. See Next.js adapter and Event schema for the full server-to-server contract.

Plain HTML (no bundler)

The script-tag install works as-is. If you need to reach the tracker from inline handlers:

<script
  src="https://t.example.com/sdk.js"
  data-key="cs_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  async
></script>

<button onclick="clickstream?.trackEvent({ name: 'download_pressed' })">Download</button>

Verifying the install

  1. Open the dashboard, pick your site, and watch the Live Sessions panel.
  2. Load any page on your site in an incognito tab. You should see a session appear within 1–2 seconds.
  3. If nothing arrives after 30 seconds:
    • Open DevTools → Network and filter for your tracking domain. Look for 200 responses on /sdk.js and /v1/events; a 403 means the Origin doesn't match your configured domains.
    • Confirm the API key in data-key matches the key shown in the dashboard.
    • Confirm the loading origin is listed in the site's Allowed Domains — wildcards like *.example.com are supported.
    • Re-run dig +short t.example.com and confirm the answer resolves to feynman.clickstream.com (see First-party tracking).

Next steps