1. Separate three different stages
You installed the snippet, opened your website, and saw tracker.js return 200 in the Network panel. The Visitors page is still empty. That response proves the browser downloaded a file. It does not prove the script initialized, collection was permitted, or the server accepted an event.
WhoVisited follows a short request chain: tracker.js loads; the browser requests a temporary ingestion token from /api/v1/bootstrap; then it posts a batch to /api/v1/events. Start by finding the earliest missing stage instead of reinstalling everything.
- Open Developer Tools on the actual deployed website and select Network before reloading.
- Filter for tracker.js, bootstrap and events. Look at the request method, status and response body for each.
- Keep the Console open for blocked requests and runtime errors. Do not publish screenshots containing tokens or customer data.
These checks describe the current WhoVisited tracker. If you proxy requests through a custom data-api-url, examine that configured endpoint as well. A local preview and the public HTTPS website may have different origins and collection permissions.
2. If only tracker.js appears, check initialization
A downloaded script can exit before it sends anything. The tracker reads its own script element, requires a UUID-shaped data-site-id, and needs crypto.randomUUID. Copy the complete snippet from the correct website card in Settings. Do not substitute the workspace ID, remove its attributes, or paste a stale site ID.
// Read-only checks in your own website's browser console.
const scripts = Array.from(document.scripts).filter(script =>
script.src.includes("/tracker.js")
);
console.table(scripts.map(script => ({
src: script.src,
siteId: script.getAttribute("data-site-id"),
consentMode: script.getAttribute("data-consent"),
})));
console.log({
origin: location.origin,
secureContext: window.isSecureContext,
randomUUIDAvailable: typeof window.crypto?.randomUUID === "function",
trackerInitialized: typeof window.whovisited?.track === "function",
});Run the diagnostic after the script has loaded, then compare the site ID privately with Settings. It changes nothing and sends no test event. One matching script is the expected setup. If several copies exist, remove duplicate installations from page templates or tag-manager containers. The tracker refuses to initialize a second copy when window.whovisited already exists, which can leave the first site ID in control.
If the API exists but requests do not, check consent next. If it does not exist, inspect script attributes, console errors and browser support. Use the real deployed HTTPS website for the final verification.
3. Check whether collection is allowed in this browser
With data-consent="required", the tracker exposes its API but waits for approval before creating a page-view event. Your consent manager must call window.whovisited.consent(true) after both approval and tracker readiness. If approval happens before the script loads, coordinate those states rather than assuming a call to an absent API was saved.
The tracker also respects Do Not Track and Global Privacy Control. Those signals can prevent collection even when the consent API is called. Read the browser state during diagnosis; do not bypass a visitor’s preference to make the dashboard look populated.
console.log({
doNotTrack: navigator.doNotTrack,
globalPrivacyControl: navigator.globalPrivacyControl,
});A user rejecting collection is an expected missing event, not a broken integration. Test the approved-consent path using your own browser and actual consent interface. Also check whether another part of your application calls whovisited.stop(): that stops the current tracker instance.
4. If bootstrap fails, read its response code
The bootstrap POST sends the site ID and obtains a short-lived token. The server checks the website’s allowed origin and current collection entitlement before issuing it. An Origin identifies the scheme, hostname and port; it is not the full page URL. https://example.com and https://app.example.com are different origins.
In Settings, an allowed main HTTPS address also accepts its www version. Other subdomains still require their own entry. Save changes and compare the configured address with location.origin on the page you are testing. Do not add every possible domain just to suppress a rejection.
- origin_denied (403): the actual page origin is not allowed for this site.
- site_disabled or tracking_disabled (403): collection is disabled at the website or workspace level.
- subscription_inactive (403): the workspace is not currently entitled to collect; check Billing rather than editing the snippet.
- site_unavailable (403): the site cannot be used in this request; verify its ID and workspace.
- quota_exceeded or rate_limited (429): collection is constrained by usage or request limits; repeated reloads will not fix that.
A bootstrap 403 stops the tracker and clears its queued events for this page. After correcting the underlying setting, reload the page to initialize a fresh instance. Other bootstrap failures enter a cooldown rather than sending requests continuously.
5. Distinguish a policy block from an application rejection
If a request never reaches an HTTP response, inspect the Console and Network error text. A content blocker, a connection failure, a Content Security Policy violation and a CORS failure can look similar from application JavaScript.
A policy that permits the external script can still block its fetch requests. Review script-src for script loading and connect-src for requests to the collection endpoint. Merge narrowly scoped permissions into your existing policy; do not replace your application’s entire policy or disable it.
WhoVisited’s cross-origin JSON requests may have OPTIONS preflight entries. An OPTIONS response is permission to attempt the request, not proof of accepted events. Inspect the following POST too. Browser CORS failures require Console diagnostics; adding no-cors to a custom fetch is not a reliable integration fix.
The official MDN references below explain these browser policies. When sharing a support report, include the error wording, URL path and status, but omit Authorization headers, ingestion tokens and full request payloads.
6. If events are sent, confirm they were accepted
A successful event POST returns 202 with an accepted count and a duplicates count. accepted greater than zero confirms newly stored events in that batch. A response made entirely of duplicates means those event IDs were already present; it is not another new visit.
- 401: the tracker clears its token and requeues the batch so it can request a fresh token. Repeated failures deserve investigation; never hardcode the temporary token.
- 403: collection stops. The server rechecks entitlement during ingestion, so an earlier bootstrap success does not guarantee later acceptance.
- 429 or a server error: the batch is requeued with a cooldown. Check limits or service health instead of hammering reload.
- Other invalid-payload 4xx responses: the tracker discards the batch rather than retrying indefinitely. Inspect the error and your custom integration.
Custom event names must start with a letter and contain only letters, numbers or underscores, with a maximum of 64 characters. For example, signup_completed is valid; signup-completed is rejected by the browser tracker before it becomes a request. The public track API reserves page_view for automatic page tracking.
First prove that an ordinary page view is accepted. Then diagnose your custom event. This separates a transport problem from an event-name or handler-timing problem. Do not send names, email addresses or form contents as test properties.
7. Reconcile accepted events with the dashboard
After a successful test, select the matching website and clear unrelated filters in Visitors. A returning browser can update an existing visitor row rather than create a new one. Page views, sessions and visitors are different counts, so refreshing the page is not a dependable way to create a fresh visitor.
Refresh the dashboard and open the visitor journey to check the page path. In Settings, Verify installation can confirm that a tracking event arrived, but it is not a guarantee that every route, consent state or custom goal works. Test the particular flow you intend to measure.
For a support request, record the time and timezone, website name, tested origin, failing request path, status and response error code. State whether you saw a successful events response. This evidence makes it possible to distinguish browser blocking, permission rejection and dashboard interpretation without exposing a token.
A useful stopping point is one accepted page view visible under the correct website, followed by one confirmed custom action if you use goals. Once those work, investigate individual missing sessions as gaps in observable activity rather than assuming analytics can capture every visitor.