Self-hosted customer journey analytics.
Lyraflow records what people do in your product, stitches anonymous visits to known accounts, and lets you ask who did what.
It runs on your own machine under Docker, and nothing leaves it.
About five minutes
Four steps to a running install, most of it waiting for Docker.
Two containers
Events go to ClickHouse and identity to Postgres. Old events expire on a schedule you set.
Every limit has a number
It is written down, in the documentation, and the ones with known slack say so.
Knowing who someone is
A visitor browses anonymously, signs up two weeks later, then uses your product from a phone. Lyraflow ties all of that to one person, and reads their history back stitched.
If two people share a device, each event is attributed to whoever was signed in at that moment — not to whoever used it last.
Asking who did what
Build a filter tree in the browser — traits, context, lifecycle
bounds, and behaviours with predicates of their own — and read it
back in plain English before you trust it. Clicking a person shows
what is known about them: where they are, what they arrived
through, and the traits identify() has set.
A saved segment's count is the server's cache from its last evaluation, shown with the instant it was taken and never passed off as current. Each run is a real scan, so nothing re-evaluates itself just because you opened a list.
Where people stop
A funnel is a list of events in order, over a window you choose: how many people reached each step, and how many did not go on. It is drawn as a flow rather than a bar chart, so the people who leave are a band that peels away and stays visible instead of a gap you have to infer.
A step can be marked optional, and the people who skipped it still count at every step after it — without that, one detour through a help page reads as a drop-off. The window is how long someone has to finish, and it is part of the funnel rather than part of the question you ask this time.
Whether they came back
Of the people who did one thing in a period, how many came back and did another in the periods after it. Both events are yours to pick, and each takes a condition — so on a site where every navigation is one event name, “viewed the home page, then came back and registered” is a question you can actually ask.
A period that had not finished when the grid ran shows a dash, never a zero, and the screen says how many cells are waiting. Reporting an unfinished week as nought draws a collapse in the newest cohorts, in exactly the corner a reader scans for a trend.
How a number splits
An event over time, broken down by a property it carries or by a column of the event itself. Events with no value there are kept as their own series rather than dropped, so the parts still add up to the whole and a number here can be checked against the feed.
Each value gets its own panel, and every panel is drawn on one shared scale — so a series ten times another’s size looks it. Ten at most; anything smaller is summed into one labelled series and the screen says how many values that was.
The event can be narrowed before it is split, with the same conditions a funnel step and a retention grid take. Without that, a site whose every navigation is one event name can only chart “a page was viewed”; with it, the registration page, by referrer is one chart. A half-written condition blocks the run rather than being quietly dropped, because a filter that silently disappears answers a wider question than the one on screen.
A report you can keep
A retention grid or a trend can be named and saved, the same way a funnel is, and reopened from a list that shows what each one asks rather than only what it is called.
What is saved is the question, never the window. “Signups by day, last week” and “signups by day, this month” are one report asked twice. The consequence is deliberate and visible: reopen a saved report into a range it cannot answer — a minute-by-minute chart across a year — and the screen says so and refuses, rather than quietly widening the definition you saved to fit the window you are in.
curl https://analytics.example.com/v1/trends \
-H "x-lyraflow-server-key: $LYRAFLOW_SERVER_KEY" One person, end to end
Every id ever bound to someone — the ids you sent and the devices they were seen on — with when they were first and last seen, what they have done, and the traits they carry. Reachable from a feed row, from a segment’s member list, and by searching when you have no id in hand at all.
It reads the same stitched identity every other screen reads, so a person who looks like two people here looks like two people in a funnel as well. That is the point of showing it: identity problems are much easier to see on one person than in an aggregate.
Deleting someone completely
Deleting a person erases the underlying rows, and every read path — segment counts, member lists, person reads, exports — is filtered from the instant the request is accepted, not when the purge finishes. A person deleted a second ago is already invisible.
curl -X DELETE https://analytics.example.com/v1/persons/user-42 \
-H "x-lyraflow-server-key: $LYRAFLOW_SERVER_KEY" Try it
Four steps. About five minutes, most of it waiting for Docker. You need Docker and Docker Compose v2.21.0 or newer. Nothing else.
git clone https://github.com/lyraflow/lyraflow.git
cd lyraflow
./install.sh
That generates passwords into .env, starts three
containers, and waits until the app answers on port 3000. Pass a
domain name instead and it serves HTTPS itself.
What is not there yet
v0.12 has no dashboards: every report is opened and read on its own screen, and there is no page that puts several of them side by side. Journeys and path analysis are still ahead.
There is no breakdown on a funnel, and no way to split a retention grid by anything — the split that trends have does not exist on either of the other two reports. Alerting, scheduled exports and any form of email digest are not there at all.
Hear about new versions
What shipped, what changed, and what is still missing. Only when there is a release — which, at this stage, is not often.
One address, kept for release notes and nothing else. Unsubscribe from any of them.
Read the source
Every claim on this page is in the README, with the numbers attached.