Nothing is showing up
Four checks, in the order that rules out the most at each step.
Work through these in order
Almost every case of no data is one of four things, and they are worth checking in this order because each one rules out more than the next.
1. Is the script actually on the page?
Open your live site, view the page source, and search for the path in your snippet, either t.js or pulse.js. If it is not there, the snippet is in your code but not in what your visitors receive.
- 1The build did not include itConfirm the change is on the branch you deployed, and that the deploy finished after the change landed.
- 2It is in a layout that this page does not useSome frameworks have more than one root layout. Check the one this page actually renders through.
- 3A framework stripped itNext.js Pages Router needs it in _document.tsx, not in _app.tsx. Astro needs it in the shared layout, not in a component that renders client side.
2. Does the console say violates?
Press F12 and read the Console. A message containing the word violates, naming script-src or connect-src, is a Content Security Policy refusing the request. The Ad blockers and CSP page has the fix.
If it names script-src, the script itself never loaded. If it names connect-src, the script loaded fine and the events are being blocked on the way back. The second one is easy to miss because the page looks completely normal.
3. Does the request appear in the Network tab?
Open the Network tab, filter for batch, and reload the page. What you see tells you which problem you have.
| What you see | What it means |
|---|---|
| No request at all | An ad blocker dropped it before it was sent. Serve the script from your own domain. |
| Status 200 | Events are arriving. The problem is on the reading side, not the sending side. |
| Status 401 | The key is wrong or was revoked. Copy it again from Tracking setup. |
| Status 403 | The domain sending events is not on your allowed list. Add it in project settings. |
| Status 422 | The event was rejected as malformed. The response names the field that failed. |
| Status 429 | Too many events too quickly. The tracker retries on its own, so this resolves itself. |
| Returns HTML, not JSON | Your catch-all route swallowed the rewrite. Move the two rewrites above it. |
4. Is the domain on your allowed list?
Your project only accepts events from domains you have listed, which is what stops somebody else pasting your public key into their own site. If you are testing from localhost or a preview deployment, that hostname needs to be on the list too.
Add it under project settings, in Domains. Preview deployments on Vercel get a new hostname for every deploy, so it is usually easier to test against your production domain.
Data is arriving, but it looks wrong
| Symptom | Cause |
|---|---|
| Every page view counted twice | The snippet is on the page twice, or you added a router hook as well. The tracker detects navigation on its own, so it needs no hook. |
| Single page app only records the first page | The snippet is inside a component that mounts once. Move it to the document head. |
| Browser and system panels are empty | Those are read from the user agent at ingestion, so they only appear on events received after you installed. Older events stay blank. |
| Bounce rate is 100 per cent | Only one page view is being recorded per visit, which usually means navigation is not being detected. Check for the double counting fix in reverse. |
| Region and city are empty | Some networks, VPNs and corporate proxies do not resolve past the country. The country is still correct. |
| Referrers all say direct | Links from apps and from https to http pages arrive without a referrer. Tag your own campaign links with UTM parameters so they can be told apart. |
Still stuck
Every response from our ingestion endpoint includes a requestId. Copy it from the response body in the Network tab and send it to us, and we can look up precisely what arrived and what we did with it. It is far faster than describing the symptom.