lytics

Docs

Everything lytics does, and how to use it from an app.

Want to see the result first? Explore a sample dashboard — a made-up app with illustrative numbers, a database panel, and 7- and 30-day ranges. No account needed.

Install

Add an app on Your apps and copy its snippet into the <head> of every page. The first line queues calls made before the script has loaded; the second loads it without blocking the page.

<script>window.lytics=window.lytics||function(){(lytics.q=lytics.q||[]).push(arguments)};</script>
<script defer src="https://lytics.lp-data.cloud/api/t/lyt_your_site_key.js"></script>

On an Astro site, add is:inline to both tags — Add analytics to an Astro website walks through it, client-side navigation included, up to the first pageview.

Using Next.js App Router? Add analytics to a Next.js App Router app covers the root layout, client navigation and a button event.

Until an app's first pageview arrives, its page opens on a short setup: the allowed domains, the snippet, and aCheck for pageview button that waits for one and says when it was collected, and on which path. Only a pageview confirms it — a login, a tagged event or copying the snippet does not — and the setup stays on every visit until one does.

A pageview is sent on load and on every history.pushState, replaceState and back or forward navigation, so single-page apps need nothing more. Events are sent with navigator.sendBeacon and carry no cookies.

List the app's domains on its page. Events from any other host are dropped. A domain of*.example.com allows every subdomain and example.com itself. With no domains listed, any host is accepted — fine for trying it out, not for staying that way.

To count visits rather than pageviews, add data-track="visits" to the second tag. Each pageview is still sent, but only the one that starts a visit — or the first in a visit to carry a signed-in user — is kept, so Visits, Visitors, Users and Logins are unchanged while Pageviews becomes about one per visit and the pages list shows mostly where visits began. An identify with a new id sends one such pageview, so a user identified after the page loaded is still counted. Other events are kept as usual.

<script defer data-track="visits" src="https://lytics.lp-data.cloud/api/t/lyt_your_site_key.js"></script>

Apps built on lp-data.cloud are added by its scaffolder, which calls PUT /api/provision/propertieswith the deployment's provisioning token. It creates the app on the superuser's account, or adds missing domains to the one already there, and returns the site key.

Users and events

// Who is signed in. Call it on every page while they are; events after it
// carry the id. Send your own opaque id, not an email address.
lytics('identify', 'u_8f2c')

// A successful sign-in. Counts as a login and identifies the user.
lytics('login', 'u_8f2c')

// Signing out: later events are anonymous again.
lytics('logout')

// Anything else worth counting. Up to 20 properties: strings, numbers, booleans.
lytics('event', 'report_exported', { format: 'csv', rows: 1200 })

// A pageview by hand, for routers that do not use history.pushState.
lytics('page')

Event names are letters, digits, spaces and _ . : - $, up to 64 characters. User ids are up to 128 characters. Events from crawlers and headless browsers are dropped by their user agent.

Not sure which events to send? The event tracking plan builder starts from a sample plan, checks names and properties against these limits and writes the calls for you.

The numbers

PageviewsEvery pageview event.
VisitsEvents that start a visit: the first from a visitor in thirty minutes.
VisitorsDistinct visitors, counted per UTC day. A visitor is a hash of the day, the app, the IP address and the browser, so the same person on two days is two visitors, and over a range this is the sum of each day's visitors. That is the price of not storing anything on their device.
UsersDistinct ids sent with identify or login: your app's own signed-in accounts.
Loginslogin events. Each user's last login and last activity are listed on the dashboard.
LiveDistinct visitors in the last five minutes.

Days are UTC. Only the path of each page is stored — never the query string or the fragment. Referrers are kept as a hostname. Raw events are kept for 400 days.Cookieless web analytics explains the visitor hash, its daily salt and its trade-offs step by step.

Tags

A tag turns something that happens on the page into a named event, without changing the app:

Each can be limited to paths starting with a prefix. Tags are delivered with the script, which browsers cache for five minutes. A tag can only send an event: there is no way to add code to the page from lytics.

First tag? Track button clicks and form submissions walks through a signup-link click and a form submit on a sample landing page, with the exact settings and the events to look for.

Embeds

On an app's page, make an embed with a label, the sites that will show it (as https:// origins) and a range of 7, 30 or 90 days. You get a link once — keep it, because only a hash of it is stored.

<iframe src="https://lytics.lp-data.cloud/api/embed/…" title="Usage"
        style="width:100%;height:900px;border:0" loading="lazy"></iframe>

The embedded page shows the app's numbers and the database panels pinned to the app. It can only be framed by the sites you listed, contains no scripts, and never shows user ids. Deleting the embed stops the link working at once.

The link is a bearer secret: anyone who has it can open it directly, and the listed sites only limit which pages may frame it. Embed a web analytics dashboard in your app walks through an embed on a sample team portal — sizing for phones, what it shows, who can read it and how to revoke and replace it. Create your dashboard.

Databases

On Databases, connect a Postgres database and add panels: a title, a query, and how to draw it — a number (the first cell), a table, or columns or a line (the first column labels the points, the first numeric column after it is the value). Pin a panel to an app to put it on that app's dashboard and embeds.

Connect with a user that can only read:

CREATE ROLE lytics_reader LOGIN PASSWORD '…';
GRANT CONNECT ON DATABASE app TO lytics_reader;
GRANT USAGE ON SCHEMA public TO lytics_reader;
GRANT SELECT ON users, login_logs TO lytics_reader;   -- only what you chart

And lytics adds its own limits: each query runs as a single statement inside a read-only transaction that is rolled back, for at most fifteen seconds, returning at most 1,000 rows. Panels refresh on their own schedule (every hour unless you change it); dashboards and embeds show the last result and never run the query themselves. Addresses on private networks are refused.

New to panels? Build a Postgres signup dashboard walks through it end to end — sample table, read-only user, a total and a daily chart — andcreating an account takes you straight to Databases.

For an app built on lp-data.cloud, Add the lp-data.cloud panels creates four panels from the user tables every such app has — accounts, new accounts and sign-ins per day, and the latest sign-ins. The last one lists email addresses, so it is not pinned to the app or its embeds unless you pin it.