How we count

Every metric with its definition and denominator, plus the rules that sort visits into channels.

These are definitions version 2026-10-05.1. When a definition changes, the version changes with it, so an old report can always be explained.

Headline metrics

MetricDefinition
ViewsRendered page navigations reported by the SDK. Not prefetches, not HTTP requests
SessionsJourney mode only. Consented tab sessions, 30 min idle, 24 h cap. Not people
Conversion rateJourney: converted sessions divided by sessions, so it never exceeds 100%. Aggregate: goal completions divided by views. The UI always names the denominator
Engaged rateEngaged sessions divided by sessions (journey), or engaged views divided by views (aggregate). A view counts once, however many $engage events it sends
Active timeMedian of $engage durations. Foreground plus recent interaction, not attention
Automated requestsEdge SDK and log drain observations not classified browser. Separate denominator from views, never summed with them

The Humans filter means actor_class = 'browser': clients that look like browsers. An automated client that passes as a browser is counted here too.

A number that can't be computed, like sessions in aggregate mode, shows as unavailable with the reason, never as zero.

Channels

Evaluated in order, first match wins. The rules follow the default channel group of Google Analytics 4, mapped onto Little Friend's eight channels. utm_medium and utm_source are compared trimmed and lowercased. A referrer on the project's domain or any subdomain of it is internal: the view is not a landing, carries no source and counts no entry, and UTM tags on such a link are ignored. Channel and source are decided at ingest, so these rules apply to data received after they shipped, and older rows keep the channel they were given.

  1. Paidutm_medium matches ^(.*cp.*|ppc|retargeting|paid.*)$ (cpc, cpm, paid_social), or is display, banner, expandable or interstitial
  2. Emailutm_medium or utm_source contains email or newsletter, or is e-mail, e_mail or e mail; or the referrer is a webmail host (below)
  3. AI assistantsreferrer is chatgpt.com, chat.openai.com, perplexity.ai, claude.ai, gemini.google.com, copilot.microsoft.com, you.com, phind.com (or a subdomain), or there is no referrer and utm_source names one of those hosts (assistants tag the links they show, for example utm_source=chatgpt.com)
  4. Searchreferrer is a known search engine; or utm_medium is organic; or utm_source is google, bing, duckduckgo, yahoo, ecosia, brave, yandex, baidu or kagi, or a search engine's host (google.com). Search engine hosts: google.<tld> and google.<sld>.<cc> such as google.co.uk (other Google hosts are not search), bing.com, duckduckgo.com and ecosia.org with their subdomains, yahoo.com, yahoo.co.jp, search.yahoo.com and search.yahoo.co.jp with an optional country prefix (uk.search.yahoo.com), search.brave.com, yandex.ru, yandex.com, yandex.com.tr, yandex.kz, yandex.by, yandex.ua, ya.ru, baidu.com, m.baidu.com, kagi.com
  5. Socialreferrer is a known social site; or utm_source is facebook, fb, instagram, ig, linkedin, x, twitter, reddit, youtube, tiktok, threads, bluesky, bsky, mastodon or pinterest, or a social site's host (facebook.com); or utm_medium is social, social-network, social-media, sm, social network or social media. Social hosts, each with its subdomains: x.com, twitter.com, t.co, facebook.com, fb.com, fb.me, instagram.com, linkedin.com, lnkd.in, reddit.com, redd.it, youtube.com, youtu.be, tiktok.com, pinterest.com, pin.it, threads.net, threads.com, bsky.app, news.ycombinator.com, the Mastodon hosts mastodon.social, mastodon.online, mas.to, mstdn.social, fosstodon.org, hachyderm.io, infosec.exchange, techhub.social, and any host starting with mastodon.
  6. Referralutm_medium is referral, app or link
  7. Campaignany other utm_source
  8. Referralany other external referrer
  9. Direct or unknownno referrer and no campaign. Labeled "Direct or unknown", because a browser often hides the referrer, so a visit with none may have come from a link

Webmail and email apps

Webmail hosts, each with its subdomains: mail.google.com, outlook.live.com, outlook.office.com, outlook.office365.com, mail.yahoo.com, mail.aol.com, mail.proton.me, app.fastmail.com, and Zoho Mail's regional hosts mail.zoho.com, mail.zoho.eu, mail.zoho.in, mail.zoho.com.au, mail.zoho.jp, mail.zoho.com.cn, mail.zoho.sa, mail.zoho.uk and mail.zohocloud.ca. Most email apps send no referrer, so a link in an email lands in Email when it carries a UTM tag such as utm_medium=email.

Chrome on Android reports a link opened from an app by the app's package name. A known app is stored as the web host its links come from, so the rules above apply.

PackageStored referrerChannel
com.google.android.gmmail.google.comEmail
com.microsoft.office.outlookoutlook.live.comEmail
com.yahoo.mobile.client.android.mailmail.yahoo.comEmail
ch.protonmail.androidmail.proton.meEmail
com.openai.chatgptchatgpt.comAI assistants
ai.perplexity.app.androidperplexity.aiAI assistants
com.anthropic.claudeclaude.aiAI assistants
com.google.android.apps.bardgemini.google.comAI assistants
com.microsoft.copilotcopilot.microsoft.comAI assistants
com.google.android.googlequicksearchboxgoogle.comSearch
com.linkedin.androidlinkedin.comSocial
com.facebook.katana, com.facebook.orca, com.facebook.litefacebook.comSocial
com.instagram.androidinstagram.comSocial
com.instagram.barcelonathreads.netSocial
com.twitter.androidx.comSocial
com.reddit.frontpagereddit.comSocial
com.google.android.youtubeyoutube.comSocial
com.zhiliaoapp.musicallytiktok.comSocial
xyz.blueskyweb.appbsky.appSocial
com.pinterestpinterest.comSocial
com.slackslack.comReferral
com.discorddiscord.comReferral
org.telegram.messengert.meReferral
com.whatsappwhatsapp.comReferral

Known limits

  • UTM tags in the URL fragment (#utm_source=x) are not read. The script reads the query string only.
  • Apps on iOS send no referrer. A link opened from an iOS app is Direct or unknown unless it carries UTM tags.
  • An unknown Android app is stored under its package name, such as com.example.reader or com.example_reader, in Referral.
  • The Swift SDK sends no referrer: iOS and macOS do not tell an app which app opened its link, so a link without UTM tags that opens an app lands as Direct or unknown.
  • App events carry the device's time. On a device whose clock runs more than 10 minutes ahead, or more than 24 hours behind, the collector refuses them as clock_skew, and they are lost.
  • An app sends its queued events with the app block of the version that sends them, so events queued before an app update are stored under the new version.
  • A server goal that arrives before the app event carrying its correlation id counts as web, since no session holds that id yet. A flush right after the app event sends it at once.
  • An app event keeps at most 8 properties: the SDKs read its keys in ascending order, since a native map has no order of its own, and keep the first 8 valid ones. A page keeps the first 8 in the order it wrote them.

Apps

An iOS, macOS or Android app sends to POST /v1/e with the same WireBatch as lf.js, plus one block, a, that names the app. A batch with that block is an app batch. A batch without it is a web batch, and nothing in this section changes for it.

Devices

An app's user agent is its HTTP library, so the collector reads the device from the app block and the families from its platform, never from the user agent. The actor class is always browser: a person using the app, counted under Humans.

PlatformDeviceDevice classOS familyBrowser family
iosmobilemobileiOSiOS app
iostablettabletiPadOSiOS app
iosdesktopdesktopiOSiOS app
macosanythe devicemacOSmacOS app
androidanythe deviceAndroidAndroid app

Refused app batches

An app batch passes the same rate limits, quotas, clock window and event rules as any /v1/e batch. Allowed origins do not apply to it. These checks take their place, in this order. Each refusal is counted in rejects_daily under the browser source and shows on the data health strip.

ReasonStatusCheck
bad_app400The app block is well formed: an app id that passes its rule, a platform of ios, macos or android, a device of mobile, tablet or desktop, and a version that passes its rule with no part that looks like personal data. Otherwise the whole batch is refused, and nothing in it is stored
app_from_browser403The request carries no Origin header. Browsers send one and app SDKs do not, so an app batch with one is a web page posing as an app. It is refused before Allowed apps is read, so a listed app id does not let it through
app_not_allowed403The app id is on the project's Allowed apps, compared without regard to case. An empty list admits no app. Each refusal is also counted per app id, and the data health strip names the app until it is listed

Endpoints

EndpointAuthBody
POST /v1/epublic site key inside the bodyWireBatch, sent as text/plain JSON (no CORS preflight, beacon compatible)
POST /v1/serverAuthorization: Bearer lfs_...ServerBatch JSON
POST /v1/edgeAuthorization: Bearer lfe_...EdgeBatch JSON
POST /v1/rpublic site key inside the bodyWireReplayChunk, gzip or plain JSON, sent as text/plain. See Session replay below
GET /v1/r/config?k=lf_...public site key in the queryAnswers ReplayClientConfig, public, cacheable for 15 s, Vary: Origin. Off for a page on an origin the project does not allow