Fix tracking that is not working
Symptom by symptom: no events, a domain that never turns green, a rejected request, missing revenue, an anonymous person, far more events than people, absent conversions.
Find your symptom, then follow the checks in order.
| Symptom | Go to |
|---|---|
| Nothing arrives at all | No events at all |
| A hostname you did not expect | Events from an unexpected hostname |
A domain stuck on Waiting for events | The install checklist never turns green |
Tracking domain will not verify | The tracking host stays unverified |
| Your backend gets an error | The events route rejects the request |
| Money accepted but not visible | Revenue is not showing |
Someone stays Anonymous | A person is not identified |
| Far more events than people | Far more events than people, or a funnel that empties out |
| Google shows no conversions | Google Ads conversions are not arriving |
No events at all
Live still says it is waiting for your first event.
- Is the snippet on the page you loaded? Open the page in a browser, view its source and look for the script tag. It has to be in the
<head>of the page you actually loaded, not only on the home page. - Did you deploy? A snippet pasted into a builder or a template does nothing until the site is published. This is the single most common cause.
- Is the snippet gated behind your own consent check? If your code only renders the tag after someone accepts, everybody who declines or never answers sends nothing. Load the tag unconditionally — the script handles consent itself.
- Is a content blocker stopping it? Try another browser, or one with no extensions. Blocked events never leave the page.
- Are you using the minimal variant with
lt(…)calls of your own? A call made before the script has loaded throws in your page and the event is lost. Use the loader snippet — see Install the tracking script.
Events from an unexpected hostname
Or: Also sending events shows a hostname you never registered.
- Compare the two spellings.
acme.comandwww.acme.comare two different hostnames, andwwwis never stripped. - Add the one visitors actually use with
Add to checklist, and remove the one that never sends events.
Registering a hostname changes no collection: events are stored from whatever host runs your script, listed or not. The checklist is a report, not a filter — see Register the domains you track.
The install checklist never turns green
A domain sits on Waiting for events.
- Load a page on that domain yourself. Verification is driven by real traffic; a site nobody visits never turns green.
- Check the spelling against
Also sending events, as above. - Check the snippet is on that domain’s pages, and that the site is deployed.
- Wait for the page to recheck. It refreshes about every ten seconds.
- Check how old the traffic is. A domain counts as seen if events arrived in the last 30 days. A domain that goes quiet for longer falls back to
Waiting for events— which is a true statement about your install.
One misconception worth clearing up. A visitor who declines consent does not stop a domain verifying. Their events still arrive — without cookies and without identifiers, but carrying the page address — so the hostname is seen. The only thing that sends nothing at all is a snippet your own code hid behind a consent check.
The tracking host stays unverified
The binding on Tracking domain reads Waiting for DNS to publish, or Verification failed.
- Publish the records exactly as shown, at your DNS provider, against the host you claimed.
- Press
Check nowas soon as your records are out, instead of waiting for the next automatic check. - Check what the host answers. The script is fetched over your host and JavaScript is required back. A redirect, a parked page, an error status or a holding page fails the check — a host that merely resolves is not enough.
- Read the reason on
Verification failed. It names what the last check got: a redirect, an HTTP status, a content type that was not JavaScript, or no answer. - Press
Retry. Automatic checks give up after 72 hours, and DNS changes can take that long by themselves, so failure often just means the two clocks did not line up. Retry as often as you like; the first check that passes flips the binding toActive.
After a binding goes active, copy the snippet again from Install. The script URL is inside the HTML you pasted.
The events route rejects the request
You call the Events API and get an error instead of an accounting.
The first three are decided at the edge, before the request reaches Tracking, and come back as { "error": { "code": …, "step": "public_key_check" } }. A key you have only just created can produce one of them for about 30 seconds, until the edge picks the key up — see Send events from your backend.
| What you get | What it means | Fix |
|---|---|---|
401 public_key_required | No key reached the edge | Send the key as Authorization: Bearer <your key>. X-Public-Key and the legacy X-Api-Key carry it too, but a request with none of them is refused. |
401 public_key_invalid | The key is not one of this product’s keys | Check you are not pointing a staging key at production. A revoked key reads the same way, as does a key revoked less than about 30 seconds ago being retried too soon. |
403 public_key_scope | The key is real, but its scope does not cover the Events API | Ask a product Owner or Admin to widen the key’s scope in Product → Settings → Public Access, or use a key that covers the tracking toolkit. |
503 public_config_unavailable | The edge has not loaded its key snapshot yet and fails closed | Retry. Nothing about your key or your request is wrong. |
400 request body must be { "events": [ … ] } | The envelope is wrong | Wrap your events in an events array. |
400 events batch exceeds the 500-event limit | Too many events | Split the batch. |
413 | The body is over 64 KiB | Send fewer events per request. |
A success carrying entries in rejected is not a failure of the request — the other events were stored. Read the reason on each entry: the usual ones are a payment or refund without amount_minor, an amount_minor without a currency, and a ts outside the writable window (more than 24 hours ahead or about 90 days back). See Send revenue from your backend and the Tracking API reference.
Revenue is not showing
The money is accepted but does not appear where you expect it.
- Check where you are looking. A
paymentshows in the person’s journey at once, but theLifetime valuetile is recomputed on a schedule and can take up to an hour. - Check the person is identified. Money reaches a person through the
email— or ananonymous_idyou captured in the browser — on the revenue event. With neither, the payment is stored but belongs to nobody: noCustomer, no lifetime value, and it lands inUnattributedin the reports. - Check the amount unit.
amount_minoris a whole number of minor units. A payment sent as49when you meant 49.00 EUR is stored as 0.49 EUR and reads as a plausible small number everywhere. - Check the currency. Nothing is ever summed across currencies, so revenue sent in a second currency appears as its own line rather than being added to the first.
- For the reports specifically, check the conversion.
Revenue by sourcecounts people whose first paid conversion falls in the date range, and a subscription only exists when you sendsubscription_startedwith asubscription_refinprops. Payments alone give a person money andCustomerstatus but no conversion for the cohort to select. - Check the date range. The range picks people by their first conversion, not payments by their date. A renewal from an older customer never appears in a recent range.
A person is not identified
They stay Anonymous on People when you expected an email address.
- Check that something told Tracking who they are. Identity comes from your own
lt('identify', …)call or from theemailon a backend event. It is never taken from the properties of atrackcall, and it is never taken from a form the visitor submitted — the script does not read forms. - Check that
identifyis actually called. Add the call where your code learns the visitor’s own email address: the submit handler of your sign-up or sign-in form, the callback of a social login, or every page load of a signed-in visitor. Nothing identifies a visitor for you. - Check that the call is not on the wrong form. Never call
identifyfrom a form that carries someone else’s address — inviting a colleague, sending a gift, referring a friend. That records the visitor as the other person, in silence: nothing errors, thePeoplepage is simply wrong, and removing the call later does not give back the visits already attributed to them. - Check the consent state. In cookieless mode an
identifycall is dropped whole. A declining visitor cannot become a person, by design. - Check the phone format. International form — a leading
+and 8 to 15 digits — is always accepted; other shapes may be ignored rather than risk merging two people. - Call
identifyagain on every page load where the visitor is signed in. Repeating a known identity costs nothing and repairs a lost cookie.
See Identify a visitor and What tracking does with a consent answer.
Far more events than people, or a funnel that empties out
The event totals look right, but People, the report rows and the funnel steps built on them are all smaller than you expect.
- Check whether your site asks for consent. If it does, this is the usual answer, and it is not a fault. A visitor who declines statistics still sends events — they are in the totals, in
Eventsand inLive— but those events carry no identifiers and are never resolved into a person. - Read the two layers apart. Event counts cover everyone. Person counts, revenue, attribution and funnels cover the visitors who consented. A funnel follows one person from step to step, so declining visitors are missing from every step of it, not only the later ones.
- Put a number on the gap. Paid tracking health on the
Google Adspage says how many of the paid clicks in its window were cookieless. That is the only place the share is measured, and it covers paid traffic. - Check the banner is not hiding the snippet. If the event totals are short as well, the declining visitors are missing from both layers and the gap is an install problem rather than consented coverage — see No events at all, step 3.
- Check identification for the rest. Consented visitors only become known people through your own
lt('identify', …)call or theemailon an event sent from your backend.
See What tracking does with a consent answer and Read the attribution reports.
Google Ads conversions are not arriving
You turned on conversion feedback but Google shows nothing.
- Check the connection.
Conversionsshows a connect screen instead of its settings whenever the account is not connected. - Check the master switch and the rules. Feedback is off by default, and a rule has to be enabled as well.
- Run one pass manually with
Run nowinstead of waiting for the daily run. - Read the funnel on
Upload status. It says how many conversions were considered, how many were tied to a click, how many were uploaded, and where the rest went.No click id foundandno value yetare the two usual answers, and neither is silent. - If it is no click id: check paid tracking health and auto-tagging. Without Google’s auto-tagging there is no
gclid, and without agclida conversion cannot be uploaded. Visitors who declined consent carry no click id either. - If it is no value yet: the money has not landed. A revenue-valued rule waits for the revenue; those rows are picked up by a later run.
- Give Google time. Offline conversions can take hours to appear on their side.
See Close the loop on Google Ads.
Nothing here matches
Two places show you the raw truth before any report does:
Live— the events as they arrive, with the page, the source and the visitor behind each one.Events— every event name your sites have ever sent, with counts. A typo shows up here as a near-duplicate row with a small count.
If Live shows what you expect and a report does not, the question is about attribution, not delivery.
Next steps
- Read the attribution reports: what each number in a report actually counts.
- Register the domains you track: the three domain lists and how each is verified.
- What tracking does with a consent answer: why a declining visitor never becomes a person.
- Look up a setting: every default and every limit in one place.