Get started
How ProductLense counts
The exact definitions behind every number ProductLense shows: visitors, sessions, channels, attribution, revenue, fees, profit, and where counts approximate.
This page defines every number in the dashboard and how it is computed. When a figure is approximate, the page says so and gives the error bound.
Visitors
A visitor is one browser on one site on one UTC day:
visitor_id = first 16 hex characters of sha256(site_id | ip | user_agent | daily_salt)The salt is 32 random bytes generated for each UTC day. The IP address is used for the hash and the country lookup, then dropped; it is never stored. The same browser on the next day gets a different, unlinkable id, so a person who visits on three days counts as three visitors until your code calls identify. See Cookieless visitor counting for the privacy side.
Sessions and bounce rate
A session is a run of events from one visitor with no gap longer than 30 minutes. Sessions are assigned in memory when events arrive.
bounce rate = bounced sessions / sessions × 100
average duration = mean of (last event time − first event time) per sessionBounce rate, duration, and entry and exit pages are pre-aggregated per day once a day is complete (90 minutes after UTC midnight). Days not yet rolled up are read live, so totals never miss sessions.
Signups
Signups are the visitors who called identify in the range. With a channel, source, medium, campaign or referrer filter, signups use the visitor's first touch, the same attribution as the channel table.
Channels
Every event is classified when it arrives. The first rule that matches wins:
| Order | Rule | Channel |
|---|---|---|
| 1 | URL has a gclid, fbclid or msclkid value | paid |
| 2 | utm_medium is cpc, ppc, paid, paidsocial or display | paid |
| 3 | utm_medium is email | email |
| 4 | Referrer is an AI assistant: chatgpt.com, chat.openai.com, perplexity.ai, claude.ai, gemini.google.com, copilot.microsoft.com, you.com, poe.com, meta.ai, grok.com, x.ai, mistral.ai (and their subdomains), or DuckDuckGo with ia=chat | ai_assistant |
| 5 | Referrer is a social network: twitter.com, x.com, t.co, facebook.com, instagram.com, linkedin.com, reddit.com, youtube.com, tiktok.com, threads.net, bsky.app, news.ycombinator.com, producthunt.com (and subdomains) | social |
| 6 | Referrer domain contains a search engine label: google, bing, duckduckgo, yahoo, baidu, yandex, ecosia, brave | organic_search |
| 7 | No referrer, but a source (utm_source, or ref, via or source when there is no utm_source) that names an AI assistant, social network or search engine by domain or by name, such as chatgpt.com, producthunt, twitter, hn or google | ai_assistant, social or organic_search, by the lists in rules 4 to 6 |
| 8 | No referrer and no source, utm_medium or utm_campaign | direct |
| 9 | Anything else | referral |
A referrer on your own hostname is treated as no referrer, so internal navigation never becomes referral. Rule 7 matters because browsers and apps often strip the referrer: ChatGPT, for example, adds utm_source=chatgpt.com to its links instead. UTM values for source and medium are lower-cased; campaign, term and content keep their case.
First touch
The first pageview of each visitor fixes its first touch: channel, utm_source, utm_medium, utm_campaign, referrer domain, landing path and country. It is kept for the life of the site, after raw events expire, so a payment months later can still be attributed.
Attribution
ProductLense uses first-touch attribution. When a payment is written, ProductLense looks for the paying customer's visitors in this order and stops at the first source whose visitors have a first touch:
- The user id on the customer (from metadata keys
pl_user_id,user_id,userIdoruid, or the provider's own field, such as Polar's external id) matched to youridentifycalls. - The customer email, matched to the
emailtrait sent withidentify, or to a user id that is that email (case-insensitive). - A ProductLense visitor id in the customer metadata (
pl_visitor_idorvisitor_id).
When one user has several visitors, the earliest first touch wins. The result is stored on the payment row. Payments that could not be matched are tried again every night for 90 days, so an identify that arrives after the payment still credits the right channel. Details: How payments are attributed.
Money metrics
Every money number in ProductLense uses one definition, the same in the dashboard, the API, Ask and these docs. All amounts are USD at the payment date's ECB rate (original currency stored too). Only payments with status succeeded count. A channel's numbers are attributed by first touch.
| Name | Definition |
|---|---|
| Revenue | Charges − refunds − chargebacks, before processor fees. |
| Fees | Processor and merchant-of-record fees on those charges, minus fees returned on refunds. Estimated for providers that do not report fees (fee_estimated_share says how much). |
| Net revenue | Revenue − Fees. |
| Ad spend | Ad spend rows for the range, prorated by day. |
| Profit | Net revenue − Ad spend, i.e. Revenue − Fees − Ad spend. |
| Customers | Distinct customers with a first succeeded charge in the range (new customers). |
| CAC | Ad spend ÷ customers, for the same channel and range. Null when customers = 0. |
| ROAS | Revenue ÷ Ad spend. Null when spend = 0. |
| Payback | CAC ÷ average first-month net revenue per new customer. |
| MRR | Sum over active, non-trial subscriptions of the period price normalised to a month and divided by interval_count. |
| LTV | Average net revenue per customer over the customer's lifetime to date. |
| ARPU | Net revenue in range ÷ customers with a succeeded payment in range. |
Where Revenue and Profit appear side by side, the difference is always Fees + Ad spend; where Fees are shown, Net revenue = Revenue − Fees. For example:
$2,407 revenue − $152 fees − $1,518 ad spend = $737 profitFees per payment
Every payment keeps its original amount and currency, plus a USD amount converted at the European Central Bank reference rate for its day. When a day has no rate, the nearest earlier day within 10 days is used. The fee is what the processor or merchant of record kept, as reported by the provider. Providers that do not report fees get an estimate you set on the connection (a percentage plus a fixed amount), marked as estimated. Each provider page states which case applies; see Refunds, fees and currencies.
Profit by channel
Ad spend joins revenue on channel, source, medium and campaign, and spend entered for a date range is spread evenly over its days. Rows without spend show no CAC, ROAS or payback. See Profit per channel and CAC, ROAS and payback.
Conversion rate
conversion rate = customers / visitors × 100Per channel, both sides use the channel of the visitor's first touch.
Where counts are approximate
Unique visitors and sessions are stored as fixed-size HyperLogLog states so that a 12-month range loads as fast as a day. The counts are exact for small sets and approximate for large ones:
| Report | Typical error |
|---|---|
| Site totals (Overview tiles and chart), countries, devices, browsers, operating systems | about 0.8% |
| Pages, sources, channels, campaigns, referrers, entry and exit pages | about 1.6% |
Below a few hundred to a few thousand uniques per row the count is exact. Pageviews, events, revenue, fees, spend and profit are always exact sums.
In breakdowns, ProductLense first picks the page of rows by pageviews and then counts unique visitors for those rows. A list ordered by visitors can therefore differ slightly at the cut-off from a list ordered purely by visitors over all keys; within the page, rows are sorted by visitors.