Crossdeck Docs
Dashboard

Web SDK quickstart

Quickstart 10 min · For React, Next.js, Vue, Svelte, vanilla JS, and plain HTML

From a fresh Crossdeck account to your first event landing in the dashboard in under ten minutes. Two values to paste, four lines of code, one verification screen.

You can also do this from the onboarding wizard.

If you just signed up, the dashboard's Onboarding flow generates the same snippet you'll build manually here — same code, same heartbeat, same green tick. This page exists for developers who closed the wizard, came back later, or want to read the steps before they paste anything into their codebase.

Before you start

You'll need:

You don't need to connect a payment rail (Stripe, Apple, Google Play) to see your first event — telemetry flows the moment the SDK initialises. Rail connections are a separate guide.

Step 1 · Find your appId and publishable key

Crossdeck identifies your app with two values:

ValueWhat it looks likeWhat it does
appId app_web_92b2d6a5728a4d Identifies which app inside your project the events belong to. Stable, never rotates.
publicKey cd_pub_test_… or cd_pub_live_… Authenticates the SDK to the ingest endpoint. Safe to ship in your client bundle.
Test keys for development, live keys for production.

A cd_pub_test_… key routes into the sandbox environment — events here never affect production analytics, billing, or your customer-facing dashboards. Switch to cd_pub_live_… only when you're ready to ship. The SDK's environment argument must match the key's prefix (we error loudly if it doesn't).

Where to find them

  1. Open the Crossdeck dashboard and select your project from the workspace switcher (top-left).
  2. From the left sidebar, click Developers, then API keys. The direct path is /dashboard/developers/api-keys/.
  3. The page lists your apps. Each app card shows the appId at the top and two publishable keys below — one test, one live. Click the copy icon next to either to copy it to your clipboard.

If you haven't created a web app yet, the dashboard shows a + Add app button. Picking Web mints both keys instantly.

Step 2 · Install the SDK

Pick the install path that matches your stack. Every path ships the same SDK — the npm package and the CDN bundle expose the same Crossdeck API.

npm — for bundled apps (React, Next.js, Vue, Svelte, Vite, Webpack)

npm install @cross-deck/web

Or pnpm add / yarn add / bun add — same package name across every registry. The npm scope is @cross-deck with a hyphen, not @crossdeck.

CDN script tag — for plain HTML, Webflow, Framer, no-build sites

<script src="https://unpkg.com/@cross-deck/web@^1/dist/crossdeck.umd.min.js"></script>

The UMD bundle exposes window.Crossdeck.Crossdeck. Pin to the current major (@^1) — it tracks every 1.x release automatically but never a breaking 2.0. Avoid @latest, which ships every release to your customers, including breaking ones.

Step 3 · Initialise the SDK

Call Crossdeck.init(...) exactly once at boot — top of your provider tree, root of your app, or in <head> for plain HTML. The call is synchronous and returns immediately; the SDK fires its first heartbeat on the next tick.

Next.js (App Router)

Create a client component at the top of your provider tree — typically app/providers.tsx — and call init inside useEffect:

"use client";
import { useEffect } from "react";
import { Crossdeck } from "@cross-deck/web";

export function Providers({ children }) {
  useEffect(() => {
    Crossdeck.init({
      appId: "app_web_92b2d6a5728a4d",
      publicKey: "cd_pub_test_…",
      environment: "sandbox",
    });
  }, []);
  return children;
}

Then wrap your root layout in <Providers>.

Vite / Create React App / vanilla JS bundler

import { Crossdeck } from "@cross-deck/web";

Crossdeck.init({
  appId: "app_web_92b2d6a5728a4d",
  publicKey: "cd_pub_test_…",
  environment: "sandbox",
});

Put it in your entry file (src/main.tsx, src/index.js) above your app's render call.

Plain HTML / Webflow / Framer (no bundler)

<script src="https://unpkg.com/@cross-deck/web@^1/dist/crossdeck.umd.min.js"></script>
<script>
  window.Crossdeck.Crossdeck.init({
    appId: "app_web_92b2d6a5728a4d",
    publicKey: "cd_pub_test_…",
    environment: "sandbox",
  });
</script>

Drop both <script> blocks into the <head> of every page that should report telemetry. Webflow and Framer expose a "custom code" panel under site settings — that's where this goes.

The environment string must match the publishable-key prefix.

cd_pub_test_… pairs with "sandbox"; cd_pub_live_… pairs with "production". Mismatched values throw at init rather than silently routing events into the wrong warehouse.

Confirm your domain is on the Allowed origins list

Each Web app in Crossdeck has an Allowed origins list. The first origin to fire a heartbeat is added automatically, so for local development the SDK Just Works — but a production deploy from a brand-new domain will get a 403 origin_not_allowed on its first event.

To check or add an origin:

  1. Open the API keys page.
  2. Click the app's name (or the Edit link on the app card). The app's settings panel opens.
  3. Scroll to Allowed origins. You'll see your registered origins (https://yoursite.com, http://localhost:3000, etc.).
  4. Click + Add origin, paste the full scheme + host (no trailing slash, no path), and save.

An origin is scheme + host + port. https://acme.com, http://localhost:3000, and https://staging.acme.com are three different origins; subdomains and ports count. Wildcards aren't supported — for environments with many short-lived preview URLs (Vercel previews, Netlify branch deploys), add the base preview domain pattern via https://*.acme-preview.com by emailing support and we'll enable wildcard matching on the app.

Step 4 · Identify your user

Until you call identify(...), every event carries an anonymous ID minted on first page load and persisted in localStorage. The moment you know who the user is — after sign-in, in your auth callback — call identify with your app's user ID. The SDK rotates the anonymous events onto the identified person automatically.

// Anywhere you have a signed-in user — auth callback, useEffect on a session
Crossdeck.identify("user_847");

// When the user signs out
Crossdeck.reset();

The userId is whatever your app uses — the database primary key, the Firebase UID, the Auth0 sub. It should be stable for the lifetime of the account.

Want the People feed to show real names instead of anon_xxx? identify also accepts optional email and traits — see Identify users for the full signature.

React + auth library (Firebase, Clerk, Auth0, NextAuth)

"use client";
import { useEffect } from "react";
import { Crossdeck } from "@cross-deck/web";
import { useUser } from "@your-auth-library";

export function IdentityBridge() {
  const { user } = useUser();
  useEffect(() => {
    if (user) Crossdeck.identify(user.id);
    else Crossdeck.reset();
  }, [user?.id]);
  return null;
}

Mount <IdentityBridge /> anywhere inside your provider tree. It's a render-less component — single useEffect that mirrors auth state into the SDK.

Step 5 · Verify the heartbeat

Open your app in a fresh tab. The SDK fires a boot heartbeat the moment init resolves, then a stream of page.viewed, session.started, and element.clicked events as you interact with the page.

To confirm Crossdeck received them, open Developers → Heartbeat in the dashboard. The page shows a per-app SDK signal audit with three live tiles:

End-to-end latency is 3–8 seconds.

The SDK batches events (default flush at 20 events or 5 seconds) → ingest writes to Firestore → the dashboard's onSnapshot listener fans the update out. If you don't see anything after 15 seconds, jump to Troubleshooting.

If nothing shows up after 30 seconds

SymptomMost likely causeFix
Console: Crossdeck.init: invalid key prefix environment doesn't match the key (test key + production, or live key + sandbox). Set environment: "sandbox" for cd_pub_test_… keys; "production" for cd_pub_live_….
Console: POST /v1/events 401 The publishable key is for a different project than the appId. Re-copy both values from the same app card on API keys.
Console: POST /v1/events 403 origin not allowed Your domain isn't on the app's allowed-origins list (defaults to first observed origin). Open the app's settings in the dashboard and add your domain to Allowed origins.
No console errors, but Heartbeat shows nothing An ad-blocker, tracking-protection extension, or strict CSP is dropping the request before it leaves the browser. Open DevTools → Network, filter for v1/events. If the request never appears, an extension is blocking; allowlist api.cross-deck.com. If it appears with status 0 (blocked), your Content-Security-Policy needs connect-src https://api.cross-deck.com.
Heartbeat shows events but no page.viewed Your app uses a custom router that doesn't fire pushState / popstate. Call Crossdeck.page() manually inside your router's navigation handler.

What's next

Heartbeat green? The SDK is live. From here: