Analytics and the funnel¶
Outcome¶
You will know what product analytics Threadory collects, how a signed-in user's events are joined without storing who they are, and where platform operators read the visit-to-payment funnel.
What is collected¶
Threadory counts its own use in its own database. No third-party analytics script and no analytics cookie is involved, and nothing is sent to an analytics vendor.
- Page views and sign-up steps. Which page or step, the site the visitor arrived from (domain only), campaign parameters from the link, and a random identifier kept in the browser's session storage for one visit. On its own, the identifier is connected to no account.
- A salted user hash. While a user is signed in, every event their browser reports (and the trial-start
event the server records) also carries a hash of their user id. The one
exception is a contact-form submission (
lead_submitted): it is stored without the hash, the visit identifier, the referrer or campaign parameters. The hash is the first 32 characters ofsha256(salt + user id). The salt is a secret that exists only in the deployment environment (PRODUCT_EVENT_HASH_SALT), so the database alone cannot be turned back into user ids or identities. It exists to tell that the person who signed up is the same person who later connected a tool. Without a salt configured, no hash is written at all. - Server-side events. A trial starting, a trial ending, a project's first posted review, and a plan change made through self-serve billing (written by the Stripe webhook, with the old and the new plan and nothing else) are written by the server. They carry no user name or e-mail address, and only the trial start carries the user hash. The first-review row carries the internal project id, which is also what keeps it to one row per project.
Never stored: IP addresses, browser user agents, names, e-mail addresses,
and the full address of the page that linked here. Rows are deleted after 180
days (PRODUCT_EVENT_RETENTION_DAYS).
Read the funnel¶
Platform operators open /admin/funnel. It shows, for a UTC date range (default: the last 30 days):
- a count per day for each step from landing-page visit to checkout (the browser-reported steps up to and including the first connector count distinct visits per day; later steps count events), and the conversion ratio from each step to the previous one;
- the top referrer sites and campaign sources of landing-page visits.
Steps that nothing emits yet show zero: today that is e-mail verified. Plan
limits, checkout started and checkout completed are reported once self-serve
billing is on (ADR-0053); without the Stripe settings they, and plan changes,
stay at zero. Landing call-to-action clicks come from the landing and also from
/pricing, the pages for each job, the two comparison pages and /changelog,
while the landing-visits step and the source tables count only the landing root
and its language versions, so the clicks step can exceed the visits step. Only
the trial start, first review and plan change are written by the server; the
other steps are reported by the visitor's browser through a public endpoint, so
treat those counts as indicative, not audited.
Allow an operator¶
Set OPS_ADMIN_EMAILS on the API to a comma-separated list of operator e-mail
addresses. The caller's e-mail must be verified. With the variable empty,
GET /admin/funnel answers 403 to everyone, including organization owners, and
the page shows an access-denied message.
Set PRODUCT_EVENT_HASH_SALT to the same value on the web service and the API. Changing it later stops new events from joining to older ones.