Documentation
Coming from another tool
Reading the reports
Count what matters
Machine access
When something looks wrong.
Symptom, cause, and fix, for the situations that actually happen: nothing arrives, an event vanishes, an order is refused, or a number looks impossible.
Nothing arrives
The panel's Install screen is the first stop: it watches the last minutes of traffic, names the hosts events came from, and lists refusals with reasons. If it says nothing has arrived at all:
| Cause | Fix |
|---|---|
| You are looking at a preview, not the live site | A local preview of the site sends nothing, on purpose, so building pages never fills your reports. Open the published site and check again |
| The code was copied into another script or a bundle | The snippet reads its settings off the tag it arrived on, so it has to load as its own script element. A tag manager that inserts one is fine |
| A content security policy | The collector host must be in script-src and connect-src both. With one of the two, the tag either never loads or never sends, silently |
| A referrer policy of no-referrer | An event that arrives with no origin, no referrer, and no fetch metadata cannot prove which page it came from and is refused. Use a policy that keeps at least the origin |
| An ad blocker on your own browser | Open the site in a private window without extensions before concluding anything |
The collector turned events away
A site can be receiving and refusing at the same time, which is exactly the case that costs an afternoon: the numbers look fine and a third of the events are gone. The Install screen lists each refusal with its count. What the reasons mean:
| Refusal | What to change |
|---|---|
| unknown or missing site | The script URL carries an unknown or missing site ID, or an older tag has an invalid data-site attribute. Copy the snippet again from the Install screen |
| wrong hostname | The event came from a host the site does not own: a staging copy, or a domain missing from additional domains on the Site screen |
| blocked by a rule | Your own Settings, Rules working as configured. Check them before suspecting the product |
| too large | An event's properties passed the size the collector accepts. Shorten them |
| bad payload | Usually a full URL where a path belongs, from something other than the snippet posting to the collector |
| too many from one address | One address sent more than 6,000 events to this site in a minute, and the rest of that minute was refused. An office or a mobile carrier behind one address can reach it during a launch. A script in a loop reaches it at once. If it was real traffic, write to hello@kehai.io |
A custom event never shows up
- Called before the script loaded. window.kehai is not queued. A call that runs before the deferred script throws. Guard early code with window.kehai?.(...).
- A property was not a string. A number, boolean, or object in properties drops the whole event rather than sending part of it. Stringify what you send.
- Something looked like a person. An email address, a phone-shaped number, or a network address inside the name or inside a value drops the event in the browser, silently and on purpose, and so does a property key that names a person's field, like email or phone. A name that merely mentions the word is fine: email_signup, click_phone, and session_start all arrive. Send categories, never people.
- Too many or too long. Properties cap at 24 entries and 255 characters per key or value.
An order answers 422
The commerce endpoint answers with the reason spelled out, so read the body first: it names the field and what to send instead. The frequent ones:
- The old field names. amount, tax, shipping, discount, and the old item names are refused with the GA4 replacement named. See refused, by name.
- Items do not reconcile. Price times quantity less discounts must land within a cent per line of net_amount. If the error names a gap of about your VAT rate, a gross total went into the net field.
- An identifier. order_id, customer_id, email, or an address-shaped value in a coupon or item field refuses the whole order. These checks cannot detect every identifying value, so your integration must minimize the payload.
- Mixed signs. A refund is negative in every money field, not in some.
A number looks wrong
| Looks like | Usually is |
|---|---|
| Traffic collapsed today | A partial day beside whole days. Kehai refuses to compare a range ending today, and the picker says why. The rule |
| Fewer visitors than the old tool showed for a month | Visitor days are not monthly uniques, and the honest sum reads differently. Where monthly uniques went |
| Less traffic than the server logs | Bots. Declared crawlers are removed before every human metric, and the Bots screen shows exactly what was taken and by which rule |
| A report answering 404 over the API | Its module is off for that site, so for that site it does not exist. Settings, Modules |
| A filtered report refusing instead of answering | The filter names a dimension those rows do not carry, and Kehai will not show an unfiltered total under a filtered heading. Clear the named filter |
| Imported days ignoring an exclusion rule | Said on the screen: rules cannot reach a vendor's daily aggregates, and the methodology line admits it rather than pretending |
Still stuck? The status page answers whether the service itself is the problem, and contact reaches the operator. We aim to reply within one business day. Human email support is included on every plan. The Terms of Use describe the target and business hours.