Web analytics

Count visitors without cookies, track custom events with properties and see which signed-in users come back, with one script tag.

The Logdash tracker counts visitors, pageviews and sessions, where visitors come from and what they browse with, without cookies. Track the actions that matter as custom events, break them down by properties, and identify signed-in users to see who comes back.

Add the script

In Logdash, open your domain, go to Analytics, enter your website address and press Start tracking. Paste the snippet it shows into the <head> of every page. The site ID in it is public and safe to ship in your HTML.

<script
  defer
  src="https://logdash.io/sdk/web.js"
  data-site="your-site-id"
  data-endpoint="https://api.logdash.io/web_events"
></script>

From then on, the tracker sends:

  • a pageview on load and whenever the path changes through pushState, replaceState, back and forward, or a page restored from the back-forward cache. Single-page apps need no extra code.
  • a pageleave when the visitor leaves the page, for session time and exit pages.
  • a browser_error for uncaught errors and unhandled promise rejections, without the error message or stack trace.
  • the custom events you track, described below.

Events are sent in small batches about a second after they happen, and right away when the page is hidden. The tracker exposes its API as window.logdash. Call it with ?., because the object does not exist before the deferred script has loaded or in browsers where the tracker does not start.

Serve it from your own domain

Ad blockers often block analytics served from another domain. Serve the script and the events from your own domain instead, with two routes that forward to Logdash:

  • GET /_ld/script.js forwards to https://logdash.io/sdk/web.js. Serve it as application/javascript and cache successful responses.
  • POST /_ld/events forwards to https://api.logdash.io/web_events and passes the status code back. Accept JSON bodies of up to 32 KB, and do not cache the responses.

On the events route, forward the browser's Origin and User-Agent headers, and set x-logdash-client-ip to the visitor's IP address. Without an Origin the API answers 403. Without the IP address every visitor shares your server's address, and visitors are undercounted. Never forward cookies, authorization headers or ingest keys on either route, and keep the target URLs fixed so the routes cannot become an open proxy.

<script
  defer
  src="/_ld/script.js"
  data-site="your-site-id"
  data-endpoint="/_ld/events"
></script>

Prefer not to write the routes yourself? The AI prompt tab of the setup gives your coding agent a prompt that adds both routes and the script tag to your codebase, and checks them end to end.

Track custom events

Call track for the actions you want to count, such as signup_completed. Event names match [a-z][a-z0-9_]{0,63}. To break an event down in the dashboard, pass a flat object of properties as the second argument.

window.logdash?.track('video_played', {
  quality: '1080p',
  autoplay: true,
  chapter: 2,
});
  • An event carries at most 10 properties. Keys match [a-z][a-z0-9_]{0,39}.
  • Values are strings, numbers or booleans. They are stored as strings, trimmed and cut to 100 characters, so 2 and true become "2" and "true".
  • A value that contains @ or a control character is dropped, so an email address is never stored by mistake.
  • Invalid properties are dropped with one console warning per page load, and the event is still sent. The API checks every request against the same rules.
  • Only custom events carry properties. pageview, pageleave and browser_error never do.
  • Each property keeps up to 500 distinct values per site within your retention period, and later values are counted as (other). A site can use up to 50 property keys, and properties with further keys are dropped.

Never put emails, names, user IDs, purchase details or other personal data in event names or properties. Properties describe what happened, such as a quality, a theme or a variant, never who did it. Use identify for the signed-in user.

Custom events appear in the Goals card of the dashboard. Click one to see its trend in the main chart, with completions, visitors, people and a breakdown by each property, while the rest of the dashboard stays in place with the same date range and filters. Clicking a property value keeps only the events with that value, and narrows the other reports to the visitors who sent it.

Track events from your apps

Your apps, servers and desktop clients send events to the same dashboard with your domain's ingest key, which you copy from the domain's settings. Name the app with app, the same name the SDK sends with logs and metrics. App events follow the same rules for names and properties as the website, and show up in the Goals card next to them.

curl -X POST https://api.logdash.io/events \
  -H "project-api-key: $LOGDASH_INGEST_KEY" \
  -H "content-type: application/json" \
  -d '{"name": "agent_run", "app": "desktop", "props": {"model": "opus"}, "userId": "42"}'
  • userId is the signed-in user's internal ID, never an email address. Logdash stores only the same hash identify sends from the website, so one user is one person across your website and every app.
  • Without userId, the event counts toward an anonymous visitor of that app whose ID changes every week, like an anonymous website visitor. From a server, always pass userId: otherwise every event from that server counts as one visitor.
  • id is an optional UUID. Send the same one when you retry a request, so the event is stored once.
  • The API answers 202 once the event is queued, 400 for an invalid event, 401 for an unknown key and 429 when the hourly limit of your plan is reached.

Once more than one app sends events, the Goals card gets an Apps tab with the visitors and people of each app, the website by its host name. Clicking an app keeps the visitors who used it, so the Apps tab then shows how many of them also use your other apps. People who are signed in on both sides are the only ones Logdash can connect, because anonymous IDs are never shared between apps.

Visitors and people

Logdash gives each anonymous visitor a new ID every week, on Monday at 00:00 UTC. Within a week, a visitor counts once however many days they come back, and a range that spans several weeks counts them once in each week. The ID also changes when the IP address or browser does, for example on another network or after a browser update.

People counts the signed-in users you identify, each once over the whole range, however long it is. To count people, call identify on your website and pass userId from your apps.

Identify signed-in users

Anonymous visitors get a new ID every week, so retention and returning visitors are measured for identified users only. Once your app knows who is signed in, pass their user ID to identify. The identity lives in memory only, so call it on every page load, and call it with null when the user signs out.

On every page load, once the user is known
window.logdash?.identify(user.id);
On sign-out
window.logdash?.identify(null);

The script is deferred, so your app can know the user before it has loaded. If window.logdash is still undefined at that point, call identify from the load event of the script element.

  • id is a string or a number. null, undefined or an empty string clears the identity, and events tracked after that are sent without a user ID.
  • A value that contains @ or is longer than 256 characters is ignored with a console warning and leaves the identity as it was, so an email address is never sent by mistake.
  • The tracker hashes the ID in the browser, so the raw ID never leaves it. Hashing needs crypto.subtle, which browsers offer only in secure contexts such as HTTPS pages. Without it, identify does nothing.
  • Events of the page load that are still waiting to be sent when the hash is ready get the user ID too, so the first pageview is attributed when identify follows within about a second.

Pass a stable internal ID, never an email address or a name.

Let visitors opt out

The tracker does not start in automated browsers that set navigator.webdriver. If your site has privacy settings, add an analytics toggle that calls optOut and optIn:

window.logdash?.optOut();
window.logdash?.optIn();
  • optOut() stops tracking at once: it drops queued events and removes its timers, listeners and history hooks. It writes localStorage['logdash:opt-out'] = '1' so the choice survives reloads.
  • optIn() removes that flag and starts tracking again with a fresh pageview. window.logdash exists while a visitor is opted out, so optIn() stays reachable.
  • stop() still works as an alias of optOut().

The tracker counts browsers that send Do Not Track or Global Privacy Control like any other. To keep it from starting in them, add data-respect-dnt to the script tag:

<script
  defer
  src="/_ld/script.js"
  data-site="your-site-id"
  data-endpoint="/_ld/events"
  data-respect-dnt
></script>

Plan limits

Your plan sets how long events are kept, counted from the time of each event.

Web analytics retention

HobbyBuilderPro
90 days180 days365 days

Privacy

The tracker sets no cookies, IP addresses are never stored, and anonymous visitors are counted with an ID that changes every week. Web analytics privacy describes what Logdash stores and for how long, and gives you text for your privacy policy.