Goal. At month-end, each paying customer gets a short report that answers one question: did the funnel we run for you send people into your business? They keep the subscription because the number is something they could argue from their own books, not because a dashboard looks busy.
This is not website analytics. Google Analytics, Clarity, and PostHog are optional working tools. They are never the number on this report.
How every site must write the underlying events, including phone and map taps, and how to count only real people: https://projects.jbnx.io/framework/tracking-doctrine (directive v64 / R13).
A figure is allowed on the customer report only if all four are true:
If a number fails any test, it can live in an internal ops view. It does not go on the customer report.
/insights)These are not customers. Counting them is how we faked a call on a page that had just gone live.
curl / wget / python- / node-fetch127.0.0.1, localhost, private RFC1918)/insights itself, /collect, /api/, /go/, robots, health, *-probe/go/call and /go/map (not a real user navigation)verify, prodit, done, x)Do not verify a ship by curling /go/call. That 302s and must not increment the call number. Verify GET /insights → 200, host-scoped, and that a scripted tap does not move the number.
place=header and place=page are real UI. They are not test labels.
Nothing is reported until the product has this table filled (Marketing plan P0.5 — still open for CipherDeck and NodeDough North Stars).
| Stage | Plain name on the report | Source of truth | Example |
|---|---|---|---|
| 1 | People reached the page | First-party request log on their host (edge or app). Path allow-list agreed in writing. Real people only. | GET /book 200s from a browser |
| 2 | People started the action | Same host: form view, “start booking,” “create account” — one event, named. | POST /book/start or click on #start |
| 3 | People finished | Their database row, not a thank-you pixel. | Booking row status=confirmed; user created_at; payment paid |
| 4 | People came back / paid again | Same ledger, returning key (email/user_id/customer_id) seen in a prior month. | Second booking, renewal |
North Star = stage 3 (or 4 if the subscription is their subscription, not ours). Stage 1 and 2 exist only to show the pipe. The headline is finished outcomes.
Vanity that never appears as a headline: pageviews, uniques, bounce, time on site, heatmaps, recordings, “Direct traffic,” social likes.
Tagged (we claim). The visitor arrived with a UTM or click-id that we put on work we did this month or still in window (utm_source/utm_campaign from the agreed scheme). The finished outcome is joined to that first-hop tag, stored on their session or lead row when they landed — not guessed at checkout.
Unattributed (we show, we do not claim). Direct, bookmarks, stripped referrers, organic they already had, “someone typed the URL.” These go in a second column so the customer sees the whole business, and so we cannot be accused of hiding it — but we do not take credit.
Modeled / estimated (we never show as fact). Google’s consent-mode estimates, sampled explorations, “likely from Instagram.” If we only have a pixel and not their booking row, that conversion is omitted.
Join rule, printed every month:
A finished outcome is tagged only when the landing request that started that person’s visit carried our tag, or their record already stored that tag from an earlier landing in the attribution window (default 30 days). Otherwise it is unattributed.
That is last-touch on our tags only. It is weaker than a full multi-touch model and stronger than a screenshot. Customers can re-count it.
Delivered on the 1st for the previous calendar month, in the customer’s billing login (they already pay there) and as a file they can keep.
Page 1 — the argument
Appendix (optional, same file)
If finished outcomes are zero, the report still goes out. Empty is honest. A missing report is what kills trust.
You already have the bones. Do not add Google as the source of truth.
| Need | Already exists | Gap |
|---|---|---|
| Funnel stages + targets | marketing.funnels | North Stars not set (P0.5) |
| Period metrics | marketing.metrics | Need month-grain snapshot table |
| Hit / visit | First-party hits / events on each host + /insights | Beacon is geo only; funnel is the host log |
| Finished outcomes | Each product’s own DB (booking, users, payments) | Must be read into the report, not re-counted by a pixel |
| Customer delivery | bill.jbnx.io work log | No monthly proof PDF/page yet |
| UTM on every outbound | Marketing principle §2.1 | Not enforced on all sites |
Minimum trustworthy pipe:
their site, first real request → store host, path, utm_*, click id, sid
their app, finished row → copy sid/utm onto the lead/booking/payment
1st of month → freeze last month into report_snapshots
customer login → render that snapshot only
Third-party tools (GA4, Clarity, PostHog) may be installed for internal debugging. If their number disagrees with the snapshot, the snapshot wins and we say so.
That is how the report keeps the subscription: it is boring, repeatable, and checkable. A prettier chart that they cannot reconcile is how you lose them.
Marketing plan already said: first campaigns CipherDeck + NodeDough; FedM8 data permanently out of this system. Same here.
Until P0.5 names a North Star per product, there is nothing honest to put on page 1. The first CEO input is still one line each: what finished action is “a customer entered the business” this quarter.