Customer story · Analytics
Going blind was the wrong fix
An auditor found that livedot's private follow links could reach analytics as ordinary page paths. The first fix was to switch Crossdeck off on the pages that mattered most. That fix lasted about a day.
Read it yourself
livedot's Crossdeck bootstrap is served unminified at livedot.me/assets/livedot.js. Everything described below is in that file. You do not have to take our word for any of it, and that is the point of putting this story on our own site rather than a quote card.
One dot, four places it comes from
livedot is the live-tracking front door for two sports apps: Windline for cycling and RunFast for running. One account, one dot on the map, whether the rider is on web, iPhone, Android, or a Garmin watch — a single Connect IQ app covering 108 devices.
What makes it work socially is that the person watching needs nothing. No app, no account, no sign-up wall. A parent opens a link in a browser and sees their daughter moving, her pace, her projected finish, and the weather where she actually is. livedot is free for everyone, sponsored by ProLend.
Behind it is a very small team, which is the whole reason Crossdeck is there: one place to see web, server and app, instead of three consoles and a guess.
16 October: the follow link problem
A livedot follow link looks like livedot.me/f/<code>. The code is the secret.
Anyone holding it can watch; nobody else can. It is the mechanism the whole product rests on.
During an audit it became clear that those codes were reaching analytics as ordinary page paths. Nothing had leaked and nothing was exposed publicly, but a private code was travelling somewhere it had no business being, which is the kind of finding you fix the same day.
The first fix was the obvious one: turn Crossdeck off on the keyed pages. It worked. It also meant the team was now blind on the single most important surface in the product — the page every supporter actually lands on, on the morning of a race.
Never cut our own systems. Scrub the data and keep it on.
That call is why this story is worth telling. The instinct under pressure is to remove the instrumentation, because removing it is fast and feels responsible. What it actually does is trade a privacy problem for an operational blindness problem, on the day you can least afford one.
What they did instead
On keyed pages, livedot turns off automatic page tracking and sends the page view itself, with the sensitive part already removed:
if (KEYED) o.autoTrack = { pageViews: false };
C.init(o);
if (C.setErrorBeforeSend) C.setErrorBeforeSend(scrub);
if (KEYED) C.track('page.viewed', {
path: KEYED, // '/f/abc123' -> '/f'
url: location.origin + KEYED,
title: 'livedot',
referrer: document.referrer ? scrub(document.referrer) : undefined
});
Two details in there are worth more than the headline fix.
First, track itself is wrapped, so every event goes through scrub()
on its way out, not just the page view. An event added by a future developer is scrubbed by default
rather than by memory. Second, setErrorBeforeSend(scrub) puts error payloads through the
same filter, because a stack trace carrying a URL is just as leaky as a page path.
Follow codes become /f. Video identifiers become /v. Query strings are
masked. The site is served with Referrer-Policy: strict-origin-when-cross-origin, so the
code does not escape by the back door either. The follow code never leaves the browser, and the team
kept full analytics on the pages that matter most.
What is actually wired
Checked in code on 26 October 2026. This is the whole list, including the parts that are not done.
- livedot.me (web) —
@cross-deck/web1.14.2, publicly readable. - windline.tech and app.windline.tech —
@cross-deck/web, on every page. - Windline server —
@cross-deck/nodewrapping every Firebase Function. - Windline iPhone — the Swift SDK, identify on sign-in.
- Windline and RunFast Android — no Android SDK yet; the app batches to livedot's own API and the server forwards Crossdeck's part.
- RunFast web and iPhone — not wired yet.
- Trust — not integrated. Entitlements — not used; everything is free.
On the server the distinction that matters is which errors count. Real failures are captured; expected user errors are not. So when something breaks at six in the morning on a race day, the team gets the failure with its context attached rather than a wall of validation messages they have already decided are fine.
Identity is deliberately plain: identify(firebaseUid, { email, traits: { name } }) on web
and iPhone, and reset() only on a real sign-out — not on a page change, not on a token
refresh.
Consent, without a wall
Analytics are on by default. There is no interstitial asking a worried parent to make a cookie decision before they can find out where their child is on a mountain. Crossdeck's cookie panel opens from a "Cookie settings" link beside the Privacy link in every footer, and browsers sending Do Not Track or Global Privacy Control are left out automatically.
The numbers
Read out of Crossdeck for livedot's production environment, 26 September to 26 October 2026.
- 604 distinct visitors on livedot.me
- 5,807 events captured
- 108 Garmin devices supported by one Connect IQ app
Deliberately modest, pre-season numbers from a product whose busiest days are ahead of it. They are also the real ones, read out of Crossdeck for a stated window rather than rounded up for a case study.
What a small team gets from this
- One console for four surfaces. Web, server, iPhone and the Android forwarder report into the same place, so "is it the app or the API" is a question with an answer rather than an argument.
- Privacy that is legible. The scrubbing lives in a public file anyone can read, which is a stronger claim than a paragraph in a policy.
- Instrumentation that survived an audit. The pages under the most scrutiny are still the pages they can see.
Turning instrumentation off is a decision too
Most privacy fixes are a choice between seeing less and sending less. They are not the same thing, and only one of them costs you the morning of a race. Crossdeck is free until your app earns real money.