Skip to content

Funnels and retention without cookies: what actually works

What funnels and retention need, why anonymous conversion only works within a day, why retention needs identified people, and how to instrument it.

Published on 7 min read

A conversion funnel and a retention table ask the same thing of your data: is this the same person as before? A daily hash can only say yes for a few hours. Once you see that, it’s clear which questions a cookieless tool can answer on its own, and which need people to sign in.

How long “who” has to last

QuestionHow long the identity must holdAnonymous hashIdentified person
Pricing page to signup, in one sittingMinutesYesYes
Landing page in the morning, signup in the eveningHoursProbably, on the same network and side of midnight UTCFrom the half hour before sign-in
Ad on Monday, signup on ThursdayDaysNoNo, the Monday visit stays anonymous
Trial to paid in 14 daysWeeksNoYes
Still active after four weeksWeeksNoYes

A tool with a lasting device ID answers the third row too. That’s the real difference, and if that row is your business, you want a cookie and a consent banner. PostHog, in its normal mode, is built for that: it keeps a cookie to track users across sessions (checked November 2026).

Why anonymous conversion stops at a day

In Trailic, a funnel treats someone as their user ID if they have one, and as the day’s hash if they don’t. The hash changes at midnight UTC, and also when the address or the browser changes. So the funnel’s window, a week by default and up to 90 days, only means something for identified people. For anonymous visitors the chain breaks with the hash, and they stop counting at the step they’d reached.

Midnight UTC isn’t the middle of the night everywhere. In winter it’s 1am in Paris, 7pm in New York and 4pm in San Francisco. If most of your visitors are American, some funnels get cut during their evening. Expect anonymous conversion on a site like that to read a little low.

Why retention needs identified people

Retention asks whether someone from week one came back in week four. An anonymous hash can’t know, by design. So Trailic’s retention counts only people a site has identified. Cohorts are grouped by the Monday of the week someone was first identified, and each later week shows what share came back, by any activity or by an event you choose.

So the retention table describes your product’s users and says nothing about your marketing site’s visitors. If you’ve read PostHog’s cookieless docs, it’s the same trade from the other side: they advise against calling identify() in that mode, because a persistent ID is personal data.

The retention screen in Trailic: weekly cohorts in a shaded table, on made-up data for a company called Acme.

Instrumenting it

The library lives in the repo at packages/trailic and isn’t on npm yet. These calls are how it works once it’s in your project.

Page views count themselves:

// app/layout.tsx, inside <body>, once
import { Trailic } from "trailic";

<Trailic siteKey="site_…" endpoint="https://your-instance.example/api/e" />

Add events where something happens, and say who it is after sign-in:

import { identify, reset, track } from "trailic";

track("signup_started", { plan: "pro" }); // strings, numbers, booleans, 16 at most
identify("user_123", { plan: "pro" });    // after sign-in. Only now is anything kept in the browser
track("signup_completed");
reset();                                  // at sign-out

Send what only your server knows from a route handler:

import { trackServer } from "trailic/server";

await trackServer("payment", { amount: 49 }, { userId: "user_123" });

Pass that userId. A server has no visitor, so an event sent without it belongs to nobody, and it can’t appear in a funnel or in retention. Prefer an opaque ID to an email address.

Then describe the funnel, on the screen or through the MCP server, in two to eight steps. A line starting with a slash is a page, and a trailing * matches anything under it. Anything else is an event:

/pricing
signup_started
signup_completed
payment

The half hour that joins them

A funnel usually starts anonymous and ends signed in. When identify arrives, what the same hash did in the previous 30 minutes becomes that person’s. Follow one visit:

TimeWhat happensWho it counts as
09:50Views /pricinguser_123, after the join
09:58signup_starteduser_123, after the join
10:05identify("user_123")user_123
10:06signup_completeduser_123

If the same person had read /pricing at 09:00, that view would stay anonymous, and the funnel would start with signup_started for them. So put the first step close to the sign-in if you can, and don’t read too much into long anonymous runs.

The half hour is a limit I chose. A hash is shared by everyone behind an office’s address with the same browser, so two colleagues can be mixed up inside that window. Stretching it would mix up more.

Reading the numbers

A funnel shows how many reached each step, in order. Here’s the arithmetic with invented numbers:

StepPeopleShare of those who startedLost since the previous step
/pricing1,000100%
signup_started18018%82%
signup_completed909%50%
payment272.7%70%

The 82% looks worst, but a pricing page is meant to filter. The 50% is the one I’d look at first: those people had already decided to sign up, so something in the form stopped them.

For retention, again invented:

First identified, week ofPeopleWeek 0Week 1Week 2Week 3
2 Nov200100%32%22%19%
9 Nov150100%30%20%

Read across a row to see the curve, and down a column to see if newer cohorts do better. A curve that flattens means you’ve found people who stay. Choose a returning event that means real use, because “any activity” includes someone opening the page to cancel.

Both read raw events, so they only reach back as far as the site keeps them: 90 days by default, between 14 and 730 per site. The table goes up to 26 weeks, and for that you’d set retention to at least 182 days.

Anonymous mode, on by default, refuses identify: turn it off on the site’s page first. Calling it then writes the ID to localStorage and ties events to a person. Assume that’s personal data and that it takes you out of any consent exemption for anonymous statistics: see the cookie banner question. People can be erased from their page in the app, and you can hold everything back with the consent prop. All of this is listed on the features page.

Where Trailic stands

Funnels, retention and journeys work today on a test instance, with real browsers, a real assistant and five million synthetic events. Trailic hasn’t collected real traffic yet, its Vercel Queues buffer has only run against a stand-in for that service, its data model may change, and there’s no upgrade path between versions. There’s no hosted version. Automatic capture of clicks, session replay, heatmaps and A/B tests aren’t built, so you name each event yourself. Don’t make it your only analytics yet. The code and the spec are on GitHub, and issues are open.

Sources

Related articles

PostHog, Plausible CE, Umami, Matomo and Trailic compared by what you must run: services, databases, licence, stated minimums. Checked November 2026.