Publish & Share

Embed Chipp Insights Beacon

Add Chipp Insights to your website to track user presence, identify logged-in users, and monitor client-side errors.

| View as Markdown
Hunter Hodnett
Hunter Hodnett CPTO at Chipp
| 1 min read
# analytics # insights # deployment # telemetry # getting-started

Add Chipp Insights to any website to track anonymous and authenticated user presence, identify logged-in users after authentication, and automatically capture client-side errors. The beacon is lightweight (~1.5KB gzipped) and designed to be invisible — it never blocks your page or logs to the console.

What is Chipp Insights?

Chipp Insights helps you understand how visitors interact with your Chipp-powered app. It automatically:

  • Tracks page views — See which pages users visit and how they navigate
  • Identifies users — Link anonymous sessions to real users after login
  • Captures errors — Monitor client-side JavaScript errors in production
  • Respects privacy — Uses anonymous session IDs until you explicitly call identify()

Where You’ll See This Data

There isn’t a separate Chipp Insights dashboard yet. Today, the data this beacon collects surfaces inside Chipp Mail (your team’s shared inbox at email.chipp.ai), in two places:

  • Contact panel — open any email thread with someone, and if that person’s email shows up in your project’s telemetry, you’ll see a “Chipp Insights” section on their contact profile: which of your projects they’ve been active on, and when they were last seen.
  • Notifications feed — new activity from a known contact (an identify() call on one of your projects) shows up as a notification alongside your unread mail and Slack mentions.

This is a soft signal, not a verified fact — see “How It Works” below for why. If you’re not using Chipp Mail, the beacon still collects the data (so it’s there once you are), it just has no other place to show up today.


Quick Start

Add a single <script> tag before the closing </body> tag on your website, with your project key:

html
<script
  src="https://build.chipp.ai/i/beacon.js"
  data-project-key="tk_pub_YOUR_PROJECT_KEY"
></script>

The beacon automatically:

  1. Creates a random, persistent session ID on first load
  2. Sends a pageview ping on every page load and navigation
  3. Captures uncaught JavaScript errors and promise rejections

To identify a user after login, call:

javascript
chippInsights.identify("user@example.com");

That’s it. The beacon will include the user’s email on all subsequent pageviews and errors.


Getting Your Project Key

If your site was generated by Chipp (an Alchemist project), you don’t need to do anything. Every new Alchemist project ships with its own key already wired into the site’s shared layout — the beacon is active out of the box, with no manual step. The plaintext key lives in your project’s own repo at chipp-insights.json (root of the repo) if you ever need to reference it directly.

If you want to add the beacon to a different website (one Chipp didn’t generate for you, or a second site you want the same project tracked under), get the key from that file, or reach out via support if you don’t have repo access. There’s no separate “copy your key” page in the dashboard today — the key is meant to be read out of your project’s own source, the same way any other embedded config value would be.

⚠️

This is a public key. It’s safe to embed in your website — it only allows sending pageview and error data, not reading back data or accessing other projects.


JavaScript API

The beacon exposes a window.chippInsights object with methods to manually trigger events and control the beacon.

Identifying Users

Call identify() after a user logs in to link their session to their email address:

javascript
// After login
chippInsights.identify("jane@example.com");

What happens:

  • The email is stored in-memory and persisted to sessionStorage for a 30-minute sliding window
  • All subsequent pageviews and errors on this page load include the email
  • If the user does a full-page reload (not a client-side navigation), the email is reattached automatically during that window
  • After 30 minutes, the sessionStorage marker expires and the session becomes anonymous again

Best practice: Call identify() immediately after your authentication succeeds, before the user navigates:

javascript
async function handleLogin(email, password) {
  const result = await authenticateUser(email, password);
  if (result.success) {
    chippInsights.identify(email);
    // Then navigate
    window.location.href = "/dashboard";
  }
}

Manual Pageview Ping

The beacon automatically sends pageview pings on load and on client-side route changes (via pushState / replaceState hooks). If your app uses a navigation method not covered by these hooks, manually trigger a pageview:

javascript
// In a custom router or navigation handler
chippInsights.pageview();

When to use:

  • You have a custom client-side router that doesn’t use history.pushState or replaceState
  • You want to track navigation that’s not a traditional page view (e.g., modal opens, tab switches)

Full API Reference

MethodSignatureDescription
init(projectKey)(projectKey: string) => voidInitialize the beacon with your project key. Called automatically from data-project-key attribute — use this only if you need to initialize programmatically.
identify(email)(email: string) => voidLink the current session to a user’s email address. Called after successful login.
pageview()() => voidManually send a pageview ping. Use only if your app has custom navigation not covered by standard route hooks.

Script Tag Attributes

Customize the beacon’s behavior by adding attributes to the <script> tag:

html
<script
  src="https://build.chipp.ai/i/beacon.js"
  data-project-key="tk_pub_YOUR_PROJECT_KEY"
></script>
AttributeRequiredDescription
data-project-keyYesYour project’s public key. Starts with tk_pub_. Already filled in for you on an Alchemist-generated project (see “Getting Your Project Key” above).

How It Works

Session Tracking

The beacon creates a unique distinctId (a random UUID) on first load and persists it in localStorage under the key chippInsights:distinctId. This ID is:

  • Reused across page loads — the same device always has the same anonymous session ID
  • Anonymous by default — no personally identifiable information until you call identify()
  • Linked to a user on identify() — subsequent events include both the distinctId and the user’s email

A word on trust: identify(email) is exactly what it sounds like — whatever email your own code passes in, with nothing tying the browser making the call to the person that email actually belongs to. It’s the same trust level as any client-side analytics identify() call (PostHog’s works the same way). That’s a fine, normal level of confidence for “this looks like usage,” but it’s why Chipp Mail’s Contact panel phrases it as “activity recorded for X,” never “X used this” — treat the data the same way in your own reporting.

Automatic Pageview Pings

The beacon sends a pageview ping:

  • On page load — when the script first runs
  • On SPA navigation — when the user uses the browser back/forward buttons or clicks a link that uses history.pushState or replaceState
  • Manually — when you call chippInsights.pageview()

Each ping includes:

  • distinctId — the anonymous session ID
  • email (if identified) — only set after identify() is called
  • path — the current page’s pathname
  • timestamp — when the ping was sent

Error Tracking

The beacon automatically captures:

  • Uncaught exceptions — window.onerror
  • Unhandled promise rejections — window.addEventListener("unhandledrejection", ...)

Each error includes:

  • message — the error message
  • stack — the error stack trace (truncated at 8000 chars)
  • Rate limiting: max 5 errors per minute per page load; identical errors are deduplicated

Fail-Silent Design

The beacon is designed to be invisible if something goes wrong:

  • All errors are caught and never re-thrown
  • Network failures don’t block your page
  • No logs to the browser console in normal operation
  • Bundle size is tiny (~1.5KB gzipped), so page load impact is minimal

Data Payloads

The beacon sends three types of events to POST /api/public/telemetry/beacon (your Chipp instance):

Pageview Event

json
{
  "projectKey": "tk_pub_...",
  "distinctId": "550e8400-e29b-41d4-a716-446655440000",
  "email": "jane@example.com",
  "eventType": "pageview",
  "path": "/dashboard",
  "timestamp": "2025-01-15T12:34:56.789Z"
}

Identify Event

json
{
  "projectKey": "tk_pub_...",
  "distinctId": "550e8400-e29b-41d4-a716-446655440000",
  "email": "jane@example.com",
  "eventType": "identify",
  "timestamp": "2025-01-15T12:34:56.789Z"
}

Error Event

json
{
  "projectKey": "tk_pub_...",
  "distinctId": "550e8400-e29b-41d4-a716-446655440000",
  "email": "jane@example.com",
  "eventType": "error",
  "errorMessage": "Cannot read property 'foo' of undefined",
  "errorStack": "TypeError: Cannot read property 'foo' of undefined\n  at getUserData (main.js:123:45)\n  ...",
  "timestamp": "2025-01-15T12:34:56.789Z"
}

Examples

Basic Setup

Simplest integration — just add the script with your project key:

html
<!DOCTYPE html>
<html>
  <body>
    <!-- Your page content -->
    <script
      src="https://build.chipp.ai/i/beacon.js"
      data-project-key="tk_pub_abcdef1234567890"
    ></script>
  </body>
</html>

Login Tracking

Identify users after they log in:

html
<form id="login-form">
  <input type="email" id="email" placeholder="Email" />
  <input type="password" id="password" placeholder="Password" />
  <button type="submit">Log In</button>
</form>

<script
  src="https://build.chipp.ai/i/beacon.js"
  data-project-key="tk_pub_abcdef1234567890"
></script>

<script>
  document.getElementById("login-form").addEventListener("submit", async (e) => {
    e.preventDefault();
    const email = document.getElementById("email").value;
    const password = document.getElementById("password").value;

    try {
      const response = await fetch("/api/auth/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email, password }),
      });

      if (response.ok) {
        // Identify the user in Chipp Insights
        chippInsights.identify(email);
        // Redirect to dashboard
        window.location.href = "/dashboard";
      } else {
        alert("Login failed");
      }
    } catch (error) {
      console.error("Login error:", error);
    }
  });
</script>

React Integration

Load the beacon in a React app:

jsx
import { useEffect } from "react";

function App({ user }) {
  useEffect(() => {
    // Load the beacon script
    const script = document.createElement("script");
    script.src = "https://build.chipp.ai/i/beacon.js";
    script.dataset.projectKey = "tk_pub_abcdef1234567890";
    script.async = true;
    document.body.appendChild(script);

    return () => {
      script.remove();
    };
  }, []);

  // Identify user when logged in
  useEffect(() => {
    if (user?.email && window.chippInsights) {
      window.chippInsights.identify(user.email);
    }
  }, [user?.email]);

  return <div>Your app</div>;
}

Next.js Integration

Use Next’s built-in Script component:

jsx
"use client";

import Script from "next/script";

export default function RootLayout({ children, user }) {
  return (
    <>
      <Script
        src="https://build.chipp.ai/i/beacon.js"
        data-project-key="tk_pub_abcdef1234567890"
        strategy="afterInteractive"
      />
      <script
        dangerouslySetInnerHTML={{
          __html: `
            if (window.chippInsights && ${JSON.stringify(user?.email)}) {
              chippInsights.identify('${user.email}');
            }
          `,
        }}
      />
      {children}
    </>
  );
}

Custom Router Integration

If your app uses a custom router that doesn’t use history.pushState, manually trigger pageviews:

javascript
class CustomRouter {
  navigate(path) {
    this.currentPath = path;
    this.render();
    // Tell Chipp Insights about the navigation
    if (window.chippInsights) {
      chippInsights.pageview();
    }
  }
}

Conditional Loading

Only load the beacon for specific users or pages:

javascript
if (isProductionEnvironment() && user.hasAnalyticsEnabled) {
  const script = document.createElement("script");
  script.src = "https://build.chipp.ai/i/beacon.js";
  script.dataset.projectKey = "tk_pub_abcdef1234567890";
  document.body.appendChild(script);
}

Privacy & Compliance

Before you start

Chipp Insights is designed to be privacy-friendly:

  • Anonymous by default — no email or identifying info is sent until you explicitly call identify()
  • First-party — data is sent to your own Chipp instance, not a third-party service
  • No cookies by default — uses localStorage and sessionStorage for session tracking, not cookies

However, if your website or app has its own privacy policy or cookie consent banner:

  1. Check your privacy policy — Update it to mention that you use Chipp Insights for pageview and error tracking
  2. Cookie consent — If your site uses a cookie banner and classifies analytics as “marketing” or “analytics” cookies that require consent, you may want to wait for user consent before initializing the beacon
  3. Optional: Consent-aware initialization — You can defer the beacon’s initialization until consent is given:
javascript
// Wait for consent before initializing
if (userHasGivenAnalyticsConsent()) {
  const script = document.createElement("script");
  script.src = "https://build.chipp.ai/i/beacon.js";
  script.dataset.projectKey = "tk_pub_abcdef1234567890";
  document.body.appendChild(script);
}

What Chipp Insights sends

FieldPurposeWhen
projectKeyAuthenticationEvery event
distinctIdAnonymous session IDEvery event
emailUser identificationOnly if you call identify()
pathPage trackingPageview and error events
errorMessage / errorStackError monitoringError events only

Chipp Insights does not send:

  • Browser fingerprints
  • IP addresses (sent by your HTTP layer, not the beacon)
  • User-Agent or device info
  • Cookies (unless your site sets them separately)
  • Any personal data beyond the email you explicitly provide

Troubleshooting

The beacon script isn’t loading

  1. Check the URL — Make sure the script src is correct and matches your Chipp instance domain
  2. Check your project key — Verify data-project-key is set and starts with tk_pub_
  3. Check CORS — The beacon uses navigator.sendBeacon() which doesn’t require CORS headers, but check your browser’s Network tab for any errors
  4. Check Content Security Policy — If your site has a strict CSP, allow the beacon:
    plaintext
    script-src https://build.chipp.ai;
    connect-src https://build.chipp.ai;

identify() isn’t working

  1. Check timing — Make sure the beacon script has loaded before calling identify(). If you’re loading the script asynchronously, wait a moment:
    javascript
    setTimeout(() => {
      if (window.chippInsights) {
        chippInsights.identify("user@example.com");
      }
    }, 100);
  2. Check email validity — The email must be a non-empty string. Pass the actual email, not null or undefined.
  3. Check browser console — The beacon never logs errors to the console (fail-silent design), but your app’s own code might be throwing. Check for any errors in the browser DevTools.

Not seeing activity in Chipp Mail

  1. Check the project key — Make sure you’re using the right project key for your Chipp app. Each project has its own key.
  2. Check network activity — Open your browser’s Network tab and look for requests to /api/public/telemetry/beacon. If you don’t see any, the beacon script isn’t loading or your project key is wrong.
  3. Check beacon initialization — The beacon runs automatically on page load. If the script is on the page, it should be sending data.
  4. Check the endpoint — The beacon sends to POST /api/public/telemetry/beacon. A non-2xx response there (rare — the route almost always returns 200 even on bad input, to avoid retry storms) points at a real problem; contact support with the failing response.
  5. Remember there’s no dashboard yet — data only surfaces today when it matches an email you already have an open thread with in Chipp Mail (see “Where You’ll See This Data” above). No matching contact means nothing will visibly show up, even if events are landing correctly.

High error rates in Chipp Insights

If you’re seeing a lot of errors reported:

  1. Check for tight error loops — If your app has a bug that throws repeatedly, the beacon caps errors at 5 per minute per page load and silently drops the rest. Fix the underlying bug.
  2. Check third-party scripts — Scripts you don’t control (ads, tracking, etc.) can throw errors. These are captured by the beacon. Check your browser console to see what’s throwing.
  3. Check for typos — Undefined variables, null reference errors, etc. are the most common. Use a linter or TypeScript to catch these before production.

The beacon is slowing down my page

The beacon is designed to be non-blocking:

  • Bundle size is ~1.5KB gzipped — negligible impact on page load
  • All network requests use navigator.sendBeacon() which is fire-and-forget — doesn’t block the page
  • Errors are caught and never re-thrown — won’t break your app

If you’re noticing performance issues:

  1. Check network conditions — Slow networks can make any request take longer. The beacon won’t block your page, but it may take time to send.
  2. Check your own code — If your page is slow, it’s likely your own JavaScript, not the beacon.
  3. Disable the beacon — If you want to test, don’t include the script tag. The beacon is completely optional.

Content Security Policy (CSP)

If your website uses a Content Security Policy, allow the beacon’s script and network requests:

plaintext
script-src https://build.chipp.ai;
connect-src https://build.chipp.ai;

If you’re using a nonce-based CSP, add the nonce to the script tag:

html
<script
  nonce="YOUR_NONCE"
  src="https://build.chipp.ai/i/beacon.js"
  data-project-key="tk_pub_YOUR_PROJECT_KEY"
></script>

FAQ

Q: Is the beacon GDPR compliant?

The beacon itself is privacy-friendly (anonymous by default, minimal data collection), but your use of it must comply with your privacy policy and applicable laws. If your site is subject to GDPR, CCPA, or similar regulations:

  1. Update your privacy policy to mention Chipp Insights
  2. If required by your jurisdiction, get consent before sending data
  3. Provide a way for users to opt out (e.g., respect Do Not Track)

Q: Can I disable the beacon for certain users?

Yes. Only add the script tag for users who consent, or use the conditional-loading pattern shown in the examples above.

Q: Can the beacon read cookies or localStorage?

No. The beacon only writes to localStorage (for the distinctId) and sessionStorage (for the email marker). It doesn’t read your app’s data.

Q: What happens if Chipp Insights is down?

The beacon uses navigator.sendBeacon() which is fire-and-forget. If the endpoint is unreachable, the request fails silently and doesn’t block your page. Once Chipp is back online, new requests will go through.

Q: Can I use the beacon on multiple websites?

Yes. Use the same project key on all your websites — events from all of them land in the same project’s data, there’s no per-domain separation today.

Q: How long is data retained?

There’s currently no automatic expiration — events aren’t deleted on a timer. This may change as the feature matures; if you need a specific record removed sooner (e.g. someone asked to be forgotten), contact support.