Skip to content

Troubleshooting

POST /ingest always answers 204, whether an event was accepted or dropped, so there is no error to read in the Network tab. Start every “no data showing up” investigation with GET /v1/validate.

  1. data-domain doesn’t match any trusted domain (typo, or the domain was never added).
  2. Page origin doesn’t match a trusted domain. Usually a www. vs bare-domain mismatch, a staging subdomain nobody added, or file:///opaque origins.
  3. Local development without the project’s “Allow local origins” toggle or an explicit localhost domain. See Localhost & development.
  4. A Content-Security-Policy blocking the script or the API origin.
  5. An adblocker blocking cdn.analytics.canarycoders.es or api.analytics.canarycoders.es.
  6. The project’s daily event cap has been reached.

Causes 1 to 3 are exactly what /v1/validate catches. Causes 4 to 6 never reach the server, so see what /v1/validate can’t see.

Call it with the exact domain/origin pair a real visitor’s browser would send. Pull them off the actual page (location.hostname for domain, location.origin for origin) rather than guessing:

Terminal window
curl "https://api.analytics.canarycoders.es/v1/validate?domain=myapp.com&origin=https://staging.myapp.com" \
-H "Authorization: Bearer cly_live_5f3a9c2e1b7d4a80f6c3e9d2a1b4c7e0"
{
"domain": "myapp.com",
"origin": "https://staging.myapp.com",
"wouldAccept": true,
"checks": {
"domainOwnedByProject": true,
"originPresent": true,
"originParseable": true,
"originIsLocal": false,
"allowLocalOrigins": false,
"originTrusted": true
},
"reasons": []
}

Each checks field mirrors one step of the real /ingest logic:

Field Fails when
domainOwnedByProject domain doesn’t match any of this project’s trusted domains. Matching is on label boundaries, so evil-myapp.com never matches myapp.com.
originPresent No origin was supplied to the check. This mirrors a request with no Origin header, which is always dropped.
originParseable origin isn’t a valid URL (it should look like https://app.example.com).
originIsLocal Informational only. true when the origin’s host is localhost, 127.0.0.1, or *.localhost.
originTrusted The origin’s host doesn’t pass the trust rule for its kind: local origins need allowLocalOrigins (or localhost explicitly trusted); everything else needs a label-boundary match against a trusted domain.

wouldAccept is domainOwnedByProject && originTrusted. When it’s false, reasons spells out which checks failed in plain English, so you don’t have to reverse-engineer the table by hand.

It is a pure server-side check of the domain and Origin acceptance rules. It cannot tell you whether the request ever reached the server in the first place.

A CSP that doesn’t allow the snippet or the API blocks the request in the browser before it is sent, so nothing shows up server-side to validate against. Add both origins:

Content-Security-Policy: script-src 'self' https://cdn.analytics.canarycoders.es; connect-src 'self' https://api.analytics.canarycoders.es;

Ad and tracker blockers may block lytics.js itself or the /ingest request by URL pattern. This is also invisible to /v1/validate, since the check runs against a hypothetical request you provide rather than observing what actually left a real visitor’s browser.

Once a project’s daily event count exceeds its cap, further events are dropped silently: same 204, no signal to the client. Check current usage against the cap on the dashboard’s Settings page. This one isn’t exposed via /v1 or the SDK, only the dashboard UI.

Confirm GET /v1/validate with the exact domain/origin pair a real visitor’s browser would send. A mismatch there is the only failure mode this endpoint is guaranteed to catch. Everything else on this page fails client-side, before the server ever sees a request.