Crossdeck Docs
Dashboard

Crossdeck for Framer — full setup guide

Setup Paste-in Custom Code snippet · identity, custom domain, revenue · ~5 min read · Updated August 4, 2026

Everything from install to identity to revenue. Paste one Custom Code snippet into your Framer site and it loads the Crossdeck web SDK on every page — so page analytics, journeys, and front-end error impact start flowing with no per-page work. The snippet is paste-in: you provision on Crossdeck, then edit two values in the snippet and publish. This doc covers each step, plus the parts that need a decision from you: best-effort identity, a custom domain, and connecting a payment rail for revenue.

No marketplace, no review — it's a documented snippet.

Framer has no site-script marketplace review. Third-party SDKs are added through Settings → Code — the same documented path GA / Fathom / Plausible use. Framer plugins are editor tools, not site-script injectors, so there is no app to submit and no approval email to wait on. Copy the snippet, fill in two values, publish.

TL;DR

What the connector does

Paste one Custom Code snippet and it loads the Crossdeck web SDK on every page of your Framer site — so page analytics, journeys, and front-end error impact start flowing with no per-page setup. Because Crossdeck joins identity, revenue, errors, and analytics on one identity graph, you can answer questions no single-layer tool can — for example, “which paying customers hit this error last week.”

The snippet holds only your publishable key (cd_pub_, ingest-only) plus your App ID. It loads @cross-deck/web from the CDN, calls init({ appId, publicKey, environment }), and makes a best-effort identify(). It is clean and safe by construction: an empty or wrong key is a silent no-op, an unreachable CDN is swallowed by onerror, and a page with no signed-in email simply stays anonymous.

Step 1 — Install

A. Provision on Crossdeck

  1. In the Crossdeck dashboard — or by running crossdeck init in the Crossdeck CLI — create a project + app.
  2. Copy your Publishable key (starts cd_pub_) and your App ID (starts app_).

B. Paste the snippet into Framer

  1. In the Framer editor, open the top-left menu → Settings (or press ⌥5).
  2. In the left sidebar under Site Settings, choose Code, then click Add Script.
  3. In Add Script: paste the snippet below into Code; set Placement to “End of <body> (or “End of <head> tag” — the loader is async, so either works), Page to All, and Run to Once. Click Add.
  4. Publish the site — custom code only runs on the published site, not the editor preview.
Framer editor top-left menu open, with Settings highlighted (shortcut Option-5).
1. Open the top-left menu and choose Settings (⌥5).
Framer Site Settings → Code panel, empty state, with an Add Script button.
2. Under Site Settings, open Code and click Add Script.
Framer Add Script dialog: Name, Placement End of body, Page All, Run Once, and the Crossdeck snippet pasted into the Code box.
3. Paste the snippet into Code; set Placement, Page = All, Run = Once, then Add.
Framer Code panel listing the added Crossdeck script, placement End of body, applied to All pages.
4. The script is now live on All pages. Hit Publish to push it to your published site.

C. Edit the two values

Framer has no field-substitution for custom code, so you edit two values directly in the snippet: set PUBLISHABLE_KEY to your cd_pub_… key and APP_ID to your app_… ID. That's the only edit.

<!--
  Crossdeck for Framer — site-wide custom code
  ============================================
  Paste this ENTIRE block into Framer:
      Settings  →  Code  →  Add Script  →  paste into "Code"  →  Add  →  Publish
      Placement: "End of <body>" (or "End of <head> tag" — async loader, either works)
      Page: All    Run: Once

  It loads the Crossdeck web SDK on every page of your Framer site and starts
  capturing page analytics, journeys, and front-end error impact — no per-page
  work. Framer has no field-substitution for custom code, so you fill in TWO
  values below (your Publishable key + App ID from the Crossdeck dashboard, or
  from `crossdeck init` in the CLI). That's the only edit.

  Environment is DERIVED from the key prefix (cd_pub_test_… = sandbox, anything
  else = production), so it can never disagree with the key.

  Clean + safe by construction:
    • only a PUBLISHABLE key (cd_pub_) is ever placed here — never a secret
    • not filled in / wrong key         → silent no-op, nothing loads
    • SDK CDN unreachable               → onerror swallows, no throw
    • identify has no logged-in email   → no-op (Framer sites are usually anon)
-->
<script>
  (function () {
    "use strict";

    // ── FILL IN THESE TWO VALUES ─────────────────────────────────────────────
    var PUBLISHABLE_KEY = "cd_pub_XXXXXXXXXXXXXXXXXXXXXXXX"; // from your Crossdeck dashboard
    var APP_ID          = "app_XXXXXXXXXXXX";                // from your Crossdeck dashboard
    // ─────────────────────────────────────────────────────────────────────────

    // Not configured, or a non-publishable key was pasted: do nothing at all.
    if (!PUBLISHABLE_KEY || !APP_ID || PUBLISHABLE_KEY.indexOf("cd_pub_") !== 0) return;

    var environment = PUBLISHABLE_KEY.indexOf("cd_pub_test_") === 0 ? "sandbox" : "production";

    function init() {
      try {
        if (window.Crossdeck && window.Crossdeck.Crossdeck) {
          window.Crossdeck.Crossdeck.init({
            appId: APP_ID,
            publicKey: PUBLISHABLE_KEY,
            environment: environment
          });
          identifyIfPossible();
        }
      } catch (e) { /* never surface to the console */ }
    }

    // Best-effort identity. Framer published sites have no server-side user, so
    // — like the Webflow connector — we look for an element that carries the
    // signed-in person's email: add the attribute `data-crossdeck-identify-email`
    // to an element (e.g. inside a members-only area) whose text/value is the
    // email. Absent that (a normal marketing site), this is a silent no-op and
    // analytics simply stays anonymous.
    function identifyIfPossible() {
      try {
        var el = document.querySelector("[data-crossdeck-identify-email]");
        if (!el) return;
        var email = (el.getAttribute("data-crossdeck-identify-email") || el.textContent || "").trim();
        var CD = window.Crossdeck && window.Crossdeck.Crossdeck;
        if (email && CD && typeof CD.identify === "function") {
          CD.identify(email, { email: email });
        }
      } catch (e) { /* swallow */ }
    }

    if (window.Crossdeck && window.Crossdeck.Crossdeck) { init(); return; }
    var s = document.createElement("script");
    s.src = "https://unpkg.com/@cross-deck/web@1/dist/crossdeck.umd.min.js";
    s.async = true;
    s.onload = init;
    s.onerror = function () { /* CDN unreachable — fail silent, keep console clean */ };
    (document.head || document.documentElement).appendChild(s);
  })();
</script>
No environment field — it's derived from the key.

There is deliberately no environment setting. The environment is read from the key prefix (cd_pub_test_… = sandbox, anything else = production), so it can never disagree with the key. Until PUBLISHABLE_KEY holds a valid cd_pub_ key and APP_ID is set, the snippet loads nothing — zero cost and a clean console.

Publishable key only.

The snippet holds only your publishable, ingest-only key (cd_pub_) — it cannot read or change your Crossdeck account. Never paste a secret or workspace key (cd_sk_ / cd_wk_). Provisioning happens on the Crossdeck engine, never in the Framer site.

Step 2 — Verify it's working

Publish the site (Custom Code doesn't run in the editor preview), open it, and click around. Crossdeck's first heartbeat auto-learns your site's origin. Then open the Crossdeck dashboard → Overview / People — you'll see a live visitor with geo, and the pages they viewed. (Data begins from the first real visit — that first heartbeat also locks your Allowed Origins to that domain.)

Nothing showing yet?

Check that you edited both PUBLISHABLE_KEY (cd_pub_…) and APP_ID (app_…) in the snippet, that you published the site (not just previewed the editor), and that the environment you're viewing in the dashboard matches the app/key. The first heartbeat can take a few moments.

Step 3 — Custom domain

When you move to or add a custom domain, add it to your Allowed Origins — 20 seconds, and it pulls you into the dashboard:

Add a domain to your Allowed Origins

The origin lock happens on the first heartbeat — then it locks.

A Framer site first served on *.framer.app (or *.framer.website) learns that origin on its first heartbeat. It will not auto-learn a custom domain you add later — you must add the custom domain to your Allowed Origins yourself, or traffic from it won't be accepted.

Step 4 — Identity (best-effort on Framer)

Analytics works anonymously out of the box. Framer published sites have no server-side user — and a Framer site is usually a marketing site — so identity is best-effort, not automatic. This is the honest difference from WordPress, where a server-side login hook resolves users for you. Don't expect automatic identity on Framer; anonymous analytics is the default and often exactly right.

If your site does have a members / gated area that renders the signed-in person's email, you can turn those visitors into known people — the same mechanism the Webflow connector uses:

  1. Find the element that displays the signed-in person's email (for example, inside a members-only area).
  2. Add the attribute data-crossdeck-identify-email to that element — either carrying the email as its value, or wrapping the element whose text is the email.
  3. Publish. On each page load the snippet looks for that attribute and, if it finds an email, calls identify(email) automatically.

Absent that attribute (a normal marketing site), identify() is a clean no-op and analytics simply stays anonymous — nothing to configure and nothing that errors.

Why email is the anchor.

Crossdeck keys identity on email — the no-backend join rail — so the email you expose via data-crossdeck-identify-email is what joins this visitor to the same person across revenue, errors, and analytics. (See How identity works for the full model.)

Step 5 — Revenue (connect a payment rail)

To join revenue to those people:

  1. In the Crossdeck dashboard, open Developers → Rails (Payment rails).
  2. Connect Stripe (or Apple / Google) in one click — Crossdeck never asks for a raw secret key.
  3. Stamp the Crossdeck reference onto your checkout / subscription events so each payment threads back to the right person. See Rails → Stripe in the dashboard for the exact one-liner.

Once a rail is connected, revenue and entitlements join the same identity graph as your analytics and errors. (Sending revenue events is done from your Crossdeck account setup — not from the Framer snippet.)

How this differs from the other connectors

Every connector loads the same Crossdeck SDK and feeds the same dashboard — only the install + identity binding differ per platform.


Crossdeck for Framer — paste-in Custom Code snippet via Settings → Code (edit Publishable key + App ID), SDK loaded on every page, environment derived from the key prefix, custom-domain add via Allowed Origins, best-effort identity via data-crossdeck-identify-email, and revenue on a connected rail (August 4, 2026). Related: Identify users, Connect Stripe.

Using an AI assistant? Read this page as clean markdown — index.md — or the whole docs index at /docs/llms.txt.