Clicktag docs
Troubleshooting
Clicktag records nothing when the hostname is unregistered or unverified (and www is a separate hostname), or when an ad blocker, Do Not Track or your CSP stops the script. Setup check in site settings tests your tag and CSP for you.
Diagnostic checklist
If pageviews or events do not appear in your dashboard, check these common causes:
1. Verify hostname registration
The collector ignores unregistered hostnames and still returns HTTP 200. Register the hostname before testing. Collector instances can cache a missing hostname for up to 15 seconds.
Verify that the hostname configured in your script matches the hostname in /app:
- Hostnames are case-insensitive, but
www.example.comandexample.comare treated as distinct domains. Registration trims spaces and reduces a full URL to its hostname, and the collector normalizesdata-hostnamethe same way; a hostname with a port, an IP address orlocalhostnever matches a site. - To combine apex and
wwwtraffic, set the same explicitly registereddata-hostnameon both versions of your site. Without that setting, the script useslocation.host. - Also confirm the site is verified: traffic for unverified sites is discarded. Verification normally happens automatically when the first visit arrives after installing the tag, if the served homepage HTML contains the tag with
data-verify. In Site settings > Installation, Run setup check shows whether that HTML has a Clicktag tag and whether your CSP header allows it, and Check verification under Verify another way reports why the tag, DNS and file checks failed.
2. Verify script source
For new installations, load https://clicktag.io/latest.js. https://clicktag.app/latest.js and the existing Totallytics script hosts remain supported. A Simple Analytics script, from their CDN or a proxy of it, sends to Simple Analytics instead. A self-hosted copy of latest.js still reaches Clicktag, but automatic verification and the setup check only recognize tags loaded from Clicktag hosts.
3. Duplicate script guards
The default tracker sets window.tt_tt_loaded = true when executed, so a second copy of the Clicktag tag on the same page halts immediately; keep only one. A retained Simple Analytics tag does NOT block Clicktag (it guards on its own window.sa_loaded); both track independently. Clicktag events use tt_event; SA events use sa_event. Migrate preload queues as well as event calls, and do not assign both trackers the same custom namespace.
4. Ad blockers, DNT, and automated browsers
- Do Not Track: The script checks
navigator.doNotTrack. By default,"1"stops normal collection. The collector also drops hits sent with aDNT: 1header, even when the script's check is turned off. - Browser extensions: Content blockers may intercept
latest.jsorsimple.gif. - Headless automation: The script marks
navigator.webdriver = truetraffic as automated; matching user-agents are also classified as bots, and so are browsers on major cloud networks that report aUTCor unknown timezone. Bot rows do not appear in normal visitor and pageview totals.
Always test using a real, unblocked browser profile.
5. Content Security Policy (CSP)
Check your browser console for CSP violation notices. Ensure the tag's script host is in script-src (and script-src-elem when defined), and that https://clicktag.io is in img-src and connect-src; legacy Totallytics tags still need https://totallytics.com for their beacons. A policy without those directives falls back to default-src. Site settings > Installation > Run setup check reports which directive blocks what, with the exact fix, for your Content-Security-Policy response header; it does not read <meta> or report-only policies.
6. Processing delays
An HTTP 200 response from the collector signals successful receipt, not instantaneous persistence. Aggregated dashboard metrics update asynchronously. Check GET /api/sites/<hostname>/breakdown?dim=pages across an active date range rather than expecting zero-latency counters.
HTTP status codes
400 Bad Request
- Collector (
/simple.gif,/noscript.gif,/events,/append): Returns plain text errors:hostname is required,event name is requiredorunsupported type: <type>./eventsand/appendalso returninvalid JSONwhen the body is not a JSON object, andPOST requiredfor other methods./ranswers a non-GET request withGET required, as do/latest.js, the pixels and/healthzfor methods other than GET and HEAD. - API (
/api/*): Check the response'serrorfield. Invalid ranges, invalid hostnames on registration, and unknown breakdown dimensions return400; unknown query keys are generally ignored. Send valid JSON objects for writes: an unreadable site PATCH body returns400 invalid settings;display_namemust be a string andis_publicmust be a boolean. Statistics ranges are at most 400 days and use Unix seconds, not milliseconds. Import requests instead use date-only strings and their own range rules. Use one of the 10 supported dimensions. A breakdownlimitclamps to 1-100 and fractions round down; zero or non-numeric input uses the default 10.
401 Unauthorized
An owner-only or account endpoint lacks a valid Firebase ID token or management key in the Authorization: Bearer <TOKEN> header. A missing or expired ID token returns sign in required; an unknown or revoked management key returns invalid or revoked management key, on public reads as well. /api/live/* accepts only Firebase ID tokens. Refresh your token in /docs/authentication. For /api/ingest, use a site API key (tt_...) or a management key with the ingest scope instead; its error distinguishes a missing or malformed site key from an invalid or revoked one.
403 Forbidden
You own the site, but this operation requires domain verification. Follow Verify ownership. API-only sites can create ingestion keys and read request metrics before verification, but creating, changing or testing alerts still needs proof of ownership. Management keys also get 403: scope <scope> required when the key lacks a scope, and management keys cannot call this endpoint on routes that need you signed in; see Errors and limits.
404 Not Found
The requested site or import job does not exist or is not accessible to this account. Private metadata and web-statistics reads also return 404 unknown site for a missing or invalid Firebase ID token (an invalid management key returns 401), so check the owner token as well as the exact hostname. A signed-in non-owner gets the same response as an unknown site.
409 Conflict
Returned when attempting to add a hostname via POST /api/sites that another account already claimed (This site is already registered to another account); registering a hostname you already own returns 200 with your existing site. Check your site list via GET /api/sites before attempting registration. POST /api/sites/<hostname>/verify returns 409 (Site registration changed. Reload and try again.) when the site was deleted or registered again during the check. Imports also return 409 for an already-active import on that site, an invalid cancel/retry transition, or a retry after the job's API key was deleted; see Imports. Email reports, management keys, Search Console and Cloudflare crawler endpoints have their own 409 cases.
413 Payload Too Large
POST /events and POST /append take one JSON object of at most 64 KiB, and POST /api/ingest a batch of at most 4 MiB. Larger bodies return payload too large. Send one hit per collector request, and split API batches, each with a new batch_id.
422 Unprocessable Entity
POST /api/sites/<hostname>/verify returns 422 with verification not found yet when the tag, DNS and file checks all fail. The response's tag, dns and file objects each carry a detail saying what was found; fix one of them and try again.
429 Too Many Requests
A user may create at most 20 new import jobs in a rolling 24-hour window (too many imports today, try again tomorrow). Wait before creating more; do not submit duplicate jobs to retry existing work. Changes made with a management key (any method but GET) draw from a per-key budget of about 60 requests, refilled at about one per second: after rate limited, retry in <n>s, wait for the Retry-After header. Per-site caps also return 429: too many goals for this site, too many alerts for this site and too many recipients for this site, as do alert, report and digest tests repeated within 30 seconds (a test was just sent, try again in a moment) and too many open live-view tickets (too many live tickets). Verifying the same hostname again within about 10 seconds, or refreshing its setup check that soon, returns rate limited, retry in <n>s with Retry-After.
500 Internal Server Error
An unexpected server-side error occurred. Retry safe read requests with a short, bounded backoff. Do not blindly repeat event POSTs or site mutations after an ambiguous failure; inspect the current state first.
502 Bad Gateway and 503 Service Unavailable
A queue or upstream service was unavailable. Starting or retrying an import returns 502 with import queue unavailable, please try again; saving a Cloudflare token or starting crawler tracking returns 502 with Could not reach Cloudflare. Please try again. when Cloudflare fails; Search Console and Cloudflare crawler syncs return 503 when their queue is unavailable; /api/ingest returns 503 with ingest temporarily unavailable, retry the same batch. Retry with a short, bounded backoff.
Operational behavior
- Rate limiting: Statistics and collection have no documented request quota or rate-limit headers. Historical imports and management-key changes have the limits above. This is not an unlimited-throughput guarantee. Bound concurrency and handle upstream/network errors.
- Health check: The
/healthzendpoint confirms worker process responsiveness. It does not check database connectivity or collector readiness. - Overview vs breakdown: Both use exact requested timestamp boundaries. Overview uses hourly buckets for ranges up to four days and daily buckets for longer ranges in
tz. Visitors count distinct daily visitor hashes. See the Stats Reference for definitions. - Site capacity: Each account can register a maximum of 50 sites.
- Deleted sites: Deletion removes the site registration, not its historical rows. Verified site lookups can remain cached for up to two minutes; missing or unverified registrations for up to 15 seconds. See Sites.
- Discrepancies with Simple Analytics: Compare identical dates and timezones. Simple Analytics counts unique entries as visitors while Clicktag counts distinct daily visitors, so Clicktag visitors usually run lower outside imported days. Time on page uses eligible page-duration medians in both, but collection, bot filtering, and country mapping can still differ. See the Migration Guide.
Import completed with zero rows
Check the source hostname, including www, the selected UTC dates, and whether Simple Analytics returns data for that range. Inspect chunks_done, chunks_total, and rows_skipped; a completed status alone is not proof that expected history arrived.
Keep your Simple Analytics account and exports until actual report counts are verified. Record the job ID, requested range, and source hostname if the result is unexpected. Do not start repeated overlapping jobs as a diagnostic step: each counts toward the limit of 20 jobs per rolling 24 hours, and records already imported are skipped rather than duplicated.