Debugging

Events not showing up? Work down three checks, in order: is the tracker running, are requests going out, did they arrive. Most problems show up at the first one.

Updated

1. Is the tracker running?

Open your site on one of its listed domains, then the browser’s developer console:

console
// In the browser console, on your site
typeof window.clickclacks?.optOut
// 'function'  → the tracker is running
// 'undefined' → it hasn't started (see below)

window.clickclacks?.q
// An array    → your queue stub is there, but c.js hasn't started yet

localStorage.getItem('cco')
// '1'         → this browser opted out; run clickclacks('optIn') to undo

If it hasn’t started, one of these is true:

  • The script didn’t load. An ad blocker, a privacy extension or your Content Security Policy blocked c.js. Check the Network tab for it.
  • The hostname isn’t listed. The page’s hostname must match an entry in data-domains exactly: www.acme.com and acme.com are different.
  • data-key is missing, or was stripped by whatever inserted the tag. Compare the tag in the Elements panel with the one on the source’s page.
  • Storage is blocked. The tracker needs local and session storage, and stays off quietly where the browser refuses them.

2. Are requests going out?

In the Network tab, filter for ingest (or /e on a custom domain). Events are batched, so a request goes out every 5 seconds, as soon as 25 events are waiting, and when you switch tab.

request
POST https://app.clickclacks.io/api/ingest?key=pk_live_3f9a1c7e5b2d4f6a8c0e1b3d
Content-Type: text/plain

HTTP/1.1 202 Accepted
{"accepted": 3}
ResponseWhat it means
202 {"accepted": n}Received. n can be 0 when every event was filtered out: a known bot’s user agent, or clicks with click autocapture off.
403Refused. The page’s origin isn’t in the source’s saved domains, or the key is wrong. Check the hostname in the address bar against the source’s domains.
400The request body wasn’t valid. The tracker never sends one; look for a second, modified copy of it.
410Your custom domain has been live for more than 30 days, and this page still loads c.js from app.clickclacks.io. Update its snippet.
503Temporarily unavailable. The tracker keeps the events and retries with the next batch.

3. Did they arrive?

  • Realtime shows who is on your site now and every event as it arrives, over the last 30 minutes. Filter it to one source.
  • Events, under Data, lists every event with its properties. Search for a custom event by its exact name.
  • Sources shows each source’s health: Waiting for events until the first one, Receiving when the last event was under 30 minutes ago, Quiet after that, and Stopped sending after 24 hours without one.

Reports such as Overview and Insights fill in as traffic arrives, usually within a minute.

Common problems

Nothing from my own browser

Usually an ad blocker or privacy extension. Try a private window with extensions off. If you opted out while testing a consent banner, that choice is remembered: run clickclacks('optIn') or clear the site’s data.

Nothing from localhost

localhost isn’t one of your listed domains, so the tracker stays off there, which also keeps development traffic out of your data. Test on a deployed preview whose hostname you’ve added to the source.

Pageviews arrive but no clicks

Check Autocapture clicks is on in the source’s settings. The tracker also turns click capture off for a page when it can’t reach ClickClacks for its settings, which a Content Security Policy without app.clickclacks.io in connect-src causes.

A custom event never arrives

Invalid calls are ignored without an error. Check that the name is 1 to 128 characters and doesn’t start with $, and that properties are a plain object (not null, an array or a class instance). If the call runs before c.js loads, add the queue stub or it is skipped. An event whose properties are over 2 KB arrives without them.

Every pageview counted twice

The tag is on the page twice: in the HTML and again from a tag manager, a plugin or a component. Keep one.

Every page shows the same path

Your app routes with the URL hash (/#/settings), which is never sent. See hash routers.

One person shows up as several

Call identify on every domain where they’re signed in, use the same ID everywhere (including your backend), and call reset on sign-out. Links between your domains carry identity only when both hostnames are listed; the carry-over rate on Sources › Identity tells you how often it works.

Server-side events

Send the batch with ?validate=true: the response shows every item exactly as it would be stored, with every error, and nothing is stored. Error responses carry a stable code and a link to its explanation. See dry runs and errors.

Next steps