Docs

Reference

What the numbers mean

This page defines every number and every dimension that misomoon reports, as the code computes them. The dashboard, the Stats API, and the MCP tools call the same functions in apps/api/src/stats.ts, which build their SQL in packages/core/src/queries.ts, so one number means the same thing everywhere. The API reference lists the parameters and response fields. Use the dashboard shows where each number appears.

Headline metrics

The KPI tiles, GET /api/v1/stats/aggregate, and every point of GET /api/v1/stats/timeseries return these nine metrics. A metric read from events counts the events whose time falls in the period. A metric read from visits counts the visits that started in the period.

Dashboard tileAPI nameRead fromDefinitionUnit
PeoplevisitorsEventsDistinct visitor ids among the pageviews and custom events. Engagement pings don't count, and neither do payments without a visit on their UTC day.Count
VisitsvisitsVisitsVisits that started in the period.Count
PageviewspageviewsEventspageview events.Count
Pages per visitviews_per_visitVisitsThe pageviews of the visits that started in the period, divided by visits.Rounded to 2 decimals
Left at oncebounce_rateVisitsBounced visits as a percent of visits. Bounces has the rule.Percent, 1 decimal
Time per visitvisit_durationVisitsSummed visit durations divided by visits. Visit duration and time on page has the rule.Whole seconds
NoneeventsEventsEvery event that is not a pageview or an engagement: custom events, the events the tracker sends by itself, and Payment and Refund events. Events sent with interactive: false count here too.Count
RevenuerevenueEventsThe sum of the amounts on events, net of refunds, in the site's currency.Site currency, 2 decimals
Noneaverage_revenueEventsrevenue divided by the number of events with an amount above zero. Refunds don't count in that number.Site currency, 2 decimals

pageviews and views_per_visit can disagree. pageviews counts views by their own time, and views_per_visit counts the views of visits that started in the period, even when a view happened after the period ended.

Each site has one reporting currency, USD unless you set another. revenue and average_revenue count the events in that currency and the events sent without a currency. They never add up amounts in different currencies. The amount on a tracker or SDK event is kept between 0 and 1,000,000,000. Refunds come from payment webhooks as negative amounts. Connect payments explains how a payment finds its visit.

Compare with an earlier period

With compare=previous the comparison period is the stretch of the same length right before the current one. With compare=year it is the same dates a year earlier. change holds one value per metric:

Metricchange
bounce_rateThe difference in percentage points, rounded to 1 decimal.
Every other metricThe percent change from the earlier period, rounded to 1 decimal. It is 0 when both periods are 0, and null when only the earlier period is 0.

A visitor id lasts one UTC day

misomoon sets no cookies and stores nothing on the device. To count people, the Worker hashes a random salt, the site id, the IP address, and the user agent with SHA-256, and keeps the first 16 hex characters as visitor_id (visitorId in packages/core/src/ingest.ts). Each UTC day has its own salt. The Worker makes it on first use and keeps it in the salts table of CONTROL. The hourly maintenance job deletes salts that are more than two days old. The IP address is never stored.

These rules follow from the daily salt:

  • The same person gets a new id at 00:00 UTC. A visitor count over several days is the sum of each UTC day's unique visitors. Someone who visits on 5 days of a month counts 5 times in that month's visitors.
  • The salt rotates at 00:00 UTC, not at the site's local midnight. A local day, a today period, or a 24h period that spans 00:00 UTC can count one person twice.
  • Two people behind one IP address with the same user agent share an id that day. One person on two devices, or with two browsers, has two ids.
  • Breakdown rows, funnels, paths, and page interaction reports count visitors by the same id.

Why is a visitor unique only for one day? gives the short answer.

Unique counts add up across shards

A site's data lives in ranges of whole UTC days, one shard per range (Sharding). A day never spans two shards, and an id never lasts past its day, so no visitor appears on two shards. misomoon counts distinct visitors on each shard and adds the counts. For a rate such as bounce_rate, it adds the numerators and the denominators of every shard first and divides once. It never averages a rate across shards.

A visit ends after 30 minutes without activity

A visit, called a session in the code, is a run of events from one visitor id. The Worker assigns each event to a visit in assignSessions in packages/core/src/ingest.ts, with SESSION_GAP set to 30 minutes:

RuleEffect
An event comes within 30 minutes of the visit's last activityIt joins that visit. Engagement pings count as activity, so a visitor who reads one page for an hour keeps one visit.
An event comes more than 30 minutes after the last activityA pageview or a custom event starts a new visit. An engagement ping is dropped.
A visit is open at 00:00 UTCIn the first 30 minutes of a UTC day the Worker also computes the visitor's id under yesterday's salt, so the visit carries on. Each event keeps its own day's id. If the site moved to another shard at that midnight, the visit splits in two.
A later event in the visit has a new referrer or new UTM tagsIt stays in the visit and takes the visit's source, channel, referrer, and UTM values. A new campaign doesn't start a new visit.

A visit takes its source, channel, referrer, UTM tags, hostname, location, browser, operating system, device, screen, and language from its first event, and keeps them. Reports read these columns of the visit, which the Worker updates as events arrive:

ColumnMeaning
entry_pathThe path of the visit's first event. The entry_page dimension reads it.
exit_pathThe path of the visit's latest pageview. The exit_page dimension reads it.
pageviewsThe visit's pageviews.
eventsThe visit's interactive custom events, which is all that bounce rate needs.
duration_msThe time from the first event to the latest pageview or custom event.

Payments never change a visit. A Payment or Refund row joins the visit's visitor id only when the payment comes on the UTC day of the visit. Otherwise its visitor_id is empty and no visitor count includes it.

A bounce is a visit with one pageview and no interaction

A visit is a bounce when it has at most one pageview and no interactive custom event. The SQL test is pageviews <= 1 AND events = 0 on the visit's row.

Event in the visitEnds the bounce
A second pageviewYes
A custom eventYes
A custom event sent with interactive: false (i: false on the beacon)No
Outbound link, Download, Form sent, or 404 from the trackerYes, always. interactive: false has no effect on them.
engagement (engaged time, scroll, Web Vitals, clicks)No
Payment or Refund from a webhookNo

Under a page filter, bounce rate counts only the visits that entered on a matching page, in the numerator and in the denominator. A page row in a breakdown takes its bounce rate from the visits that entered on that page.

Imported history from Google has no bounces, so misomoon counts a session that Google didn't mark as engaged as a bounce.

Visit duration and time on page measure different things

Visit duration (visit_duration)Time on page (time_on_page)
Where it showsKPI tiles, and breakdown rows of visit dimensions, pages, and goalsPage breakdown rows
Measured fromThe visit's eventsThe engagement pings of each page
What countsThe time from the visit's first event to its latest pageview or custom eventEngaged time: the time the page is shown and the browser window has focus
Engagement pingsKeep the visit open, but don't make it longerCarry the time
A visit with one pageviewLasts 0 secondsHas the engaged time it sent
Average overEvery visit in the scope, bounces includedEach visit that sent engaged time for the page
UnitWhole secondsWhole seconds

m.js sends an engagement ping when the page is hidden or the route changes. It doesn't send one for under one second of engaged time, unless a feature, such as clicks or Web Vitals, has data to send. The Worker keeps at most 6 hours of engaged time per ping. A visit that opens the same page twice adds the engaged time of both views. Time on page divides the summed time of each page by the number of visits that sent time for it.

Scroll depth is the deepest point of each visit

The tracker records the lowest point of the page that came into view: the scroll position plus the window height, as a percent of the page height. The Worker keeps it between 0 and 100 and rounds it to a whole number. A page that fits in the window reports 100.

WhereValue
scroll_depth on a page rowThe average of each visit's deepest scroll on that page, as a whole percent.
The Scroll report, averageThe same average for the pages in scope.
The Scroll report, reachedFor each depth 0, 10, and up to 100, the visits whose deepest scroll is at least that depth, and their share of all visits that sent a scroll depth.

Scroll depth is always on. It needs no feature box.

Breakdown rows

GET /api/v1/stats/breakdown?property=<name> returns one row per value. Each row has key, visitors, visits, pageviews, events, bounce_rate, and visit_duration. What those fields count depends on the kind of property:

PropertyvisitorsvisitspageviewsExtra fields
A visit dimension, such as source or countryDistinct visitor ids of the visits that started in the period with this valueVisits with this valuePageviews of those visitsrevenue and average_revenue when a row has revenue
entry_pageThe same, for visits that entered on the pageVisits that entered on the pagePageviews of those visitsNone
exit_pageThe same, for visits that ended on the pageVisits that ended on the pagePageviews of those visitsexit_rate
pageDistinct visitors with a pageview of the pageVisits that entered on the pagePageviews of the pagetime_on_page, scroll_depth
eventDistinct visitors who sent the event00conversion_rate, revenue, average_revenue
prop:<key> and propsDistinct visitors with an event that carries the value0Pageviews that carry the valueconversion_rate, revenue, average_revenue
goalDistinct visitors who reached the goalVisits that match the goalPageviews that match the goalkind, match, conversion_rate, revenue, average_revenue

bounce_rate and visit_duration on a row follow the rules for the headline metrics, over the row's visits. On a page row they describe the visits that entered on that page.

FieldDefinitionUnit
exit_rateVisits that ended on the page, divided by the page's pageviews in the period. The pageviews ignore any exit_page filter. At most 100. null when the page has no pageviews in the period.Percent, 1 decimal
conversion_rateThe row's visitors divided by the visitors of the period. Those visitors follow every filter except goal, event, and prop: filters.Percent, 1 decimal
revenueNet revenue of the row's events, in the site's currency. On a visit dimension, it comes from the events with an amount that carry the value. A payment carries its visit's values, so a renewal counts toward the source of its visit even when that source had no visit in the period.Site currency, 2 decimals
average_revenuerevenue divided by the row's events with an amount above zero.Site currency, 2 decimals

These rules hold for every breakdown:

  • A row with no value has the key (none). The dashboard shows it as Direct / none for source and referrer, (not set) for the UTM dimensions, and Unknown for the rest.
  • Rows sort by visitors, then by pageviews, then by key.
  • Each shard returns its top 500 values. When one shard reached that cap, the response has truncated: true, and rare values may be missing.
  • limit takes 1 to 200 rows, and has_more says whether another page exists.
  • search keeps the values that contain the text. The search runs on each shard, so it finds values outside the top 500.

Goals count visitors who reached them

A goal is an event name or a page path. Its row counts the visitors who sent the event or had a pageview or custom event on a matching page. For a page goal, events is the number of matching pageviews, and revenue is 0. Only event goals carry revenue. goal==<name> as a filter turns into the goal's event or page filter.

Goal rows read only the events misomoon collected. In a report without filters, the visitors that conversion_rate divides by include imported history, so the rate reads lower over a period with imported days. Conversion rate and Matching rules have the details.

Web Vitals

GET /api/v1/stats/vitals and Speed report five Web Vitals from real visits. They need the Web Vitals (vitals) feature (Choose what to track).

VitalAPI nameMeasuresUnitGoodPoor
Largest Contentful PaintlcpThe start time of the largest element paintedms2,500 or lessOver 4,000
Interaction to Next PaintinpThe 98th percentile of the page's interaction durations, counting interactions of 16 ms or morems200 or lessOver 500
Cumulative Layout ShiftclsThe largest burst of layout shifts that come within 1 second of each other, up to 5 seconds long. Shifts right after user input don't count.Score, 3 decimals0.1 or lessOver 0.25
First Contentful PaintfcpThe time of the first paint of text or an imagems1,800 or lessOver 3,000
Time to First BytettfbThe navigation's responseStartms800 or lessOver 1,800

A value is good at or under the good limit, poor over the poor limit, and needs_improvement in between. samples is the number of values.

The tracker sends one set of values per page load, with the page's first engagement ping. Route changes in a single-page app send none, and a vital the browser didn't measure is left out. The Worker keeps times between 0 and 60,000 ms and CLS between 0 and 10.

p75 is the 75th percentile, read from a histogram that every shard fills:

VitalBin widthValues that share the last bin
lcp50 ms20,000 ms or more
inp8 ms2,000 ms or more
cls0.00510
fcp50 ms20,000 ms or more
ttfb25 ms10,000 ms or more

misomoon adds the bins of every shard, finds the bin where three quarters of the values are reached, and reports the middle of that bin. p75 is null without samples. The dashboard rates a tile by its p75 with the limits above.

Channels

classify in packages/core/src/channel.ts gives each visit one of 11 channels. It reads the visit's first event: the referrer host, the UTM tags, and the page URL. The rules run in this order, and the first rule that matches wins:

OrderChannelRule
1AI AssistantsThe referrer is a known AI assistant, or utm_source contains chatgpt, openai, perplexity, claude, gemini, or copilot, in any case.
2Emailutm_medium is email or newsletter, or the referrer is a known webmail host.
3Affiliatesutm_medium is affiliate.
4Displayutm_medium is display, banner, or interstitial.
5Paid Search or Organic SearchThe referrer is a known search engine, or utm_medium contains search. It is Paid Search when the visit has a paid signal.
6Paid Social or Organic SocialThe referrer is a known social site, or utm_medium is social, sm, socialmedia, social-media, social_media, social media, or the same forms with network. It is Paid Social when the visit has a paid signal.
7VideoThe referrer is a known video site, or utm_medium is video.
8Paid SearchThe visit has a paid signal and no rule above matched.
9ReferralThe visit has a referrer host or a utm_source.
10DirectNothing above matched.

utm_medium is compared in lower case. A visit has a paid signal when its page URL has a gclid or msclkid parameter, or utm_medium is cpc, ppc, paidsearch, paid_search, cpm, cpv, or cpa, or starts with paid.

Sources and referrers

The referrer dimension is the host of document.referrer, with a leading www. and then a leading m. removed. A referrer from the page's own host, compared without www., is no referrer, so moving between pages of the site is never a referral. A link from another subdomain of your site is a referral.

The source dimension is the first of these that has a value:

  1. The name of a known referrer host, from the table below.
  2. utm_source, tidied. A value equal to the first part of a known host takes that source's name, so google becomes Google. Other values of 3 characters or fewer become upper case, and longer values get a capital first letter.
  3. The referrer host.
  4. Direct.

utm_source reads the utm_source parameter of the landing URL, then ref, then source. A known referrer wins over utm_source. An unknown referrer loses to it, and the referrer dimension still holds the host.

Hosts without a trailing dot match the host itself and its subdomains. Hosts with a trailing dot, such as google., match any host that starts with it or contains it after a dot, such as google.de and google.co.uk. Exact hosts are checked first, so gemini.google.com is Gemini and mail.google.com is Gmail.

KindSource names and hosts
SearchGoogle (google.), Bing (bing.com), DuckDuckGo (duckduckgo.com), Yahoo (search.yahoo.), Yandex (yandex.), Baidu (baidu.com), Ecosia (ecosia.org), Brave Search (search.brave.com), Naver (naver.com), Kagi (kagi.com)
AI assistantChatGPT (chatgpt.com, chat.openai.com), Perplexity (perplexity.ai), Claude (claude.ai), Gemini (gemini.google.com), Copilot (copilot.microsoft.com), DeepSeek (chat.deepseek.com), You.com (you.com), Phind (phind.com), Meta AI (meta.ai), Grok (grok.com)
SocialX (t.co, x.com, twitter.com), Facebook (facebook.com, fb.me), Instagram (instagram.com), LinkedIn (linkedin.com, lnkd.in), Reddit (reddit.com), Threads (threads.net), Bluesky (bsky.app), Hacker News (news.ycombinator.com), Pinterest (pinterest.), TikTok (tiktok.com), Product Hunt (producthunt.com), Mastodon (mastodon.), Discord (discord.com), GitHub (github.com)
VideoYouTube (youtube.com, youtu.be), Vimeo (vimeo.com), Twitch (twitch.tv)
WebmailGmail (mail.google.com), Outlook (outlook.live.com), Yahoo Mail (mail.yahoo.com)

misomoon also stores the referrer URL without its query string. No report breaks it down.

Dimensions

Every breakdown and filter takes one of these 26 dimensions (DIMENSIONS in packages/core/src/filters.ts). GET /api/v1/meta/dimensions returns them with their labels. The label is what the dashboard's filter bar shows.

Each dimension has a scope. An event dimension is a value of each event. A visit dimension is stored on the visit and on each of its events. An entry or exit dimension exists only on the visit. A visit matches an event filter when any of its events match, and an event matches an entry or exit filter when its visit does.

API nameLabelScopeMeaning
pagePageEventThe page path, without the query string and without a trailing slash, except for /. A hash route (#/pricing or #!/pricing) is part of the path. A path part that looks like an email address becomes :email, and a part of 20 or more mixed letters and digits becomes :token. Up to 500 characters.
entry_pageEntry pageEntry or exitThe path of the visit's first event.
exit_pageExit pageEntry or exitThe path of the visit's latest pageview.
hostnameHostnameVisitThe page's host, without www.. Always the site's domain or a subdomain of it.
eventEventEventThe event name: pageview, engagement, a custom name, a built-in event, Payment, or Refund. The event breakdown lists only custom, built-in, and payment events.
sourceSourceVisitWhere the visit came from, by the rules in Sources and referrers.
referrerReferrerVisitThe referrer host.
channelChannelVisitOne of the 11 channels.
utm_sourceUTM sourceVisitThe utm_source parameter of the landing URL, else ref, else source. Up to 200 characters.
utm_mediumUTM mediumVisitThe utm_medium parameter of the landing URL. Up to 200 characters.
utm_campaignUTM campaignVisitThe utm_campaign parameter of the landing URL. Up to 200 characters.
utm_termUTM termVisitThe utm_term parameter of the landing URL. Up to 200 characters.
utm_contentUTM contentVisitThe utm_content parameter of the landing URL. Up to 200 characters.
countryCountryVisitThe two-letter ISO 3166-1 country code from Cloudflare. The dashboard shows the country's name.
regionRegionVisitThe region name from Cloudflare.
cityCityVisitThe city name from Cloudflare.
continentContinentVisitThe two-letter continent code from Cloudflare.
timezoneTimezoneVisitThe visitor's IANA time zone from Cloudflare. It is not the site's time zone.
networkNetworkVisitThe name of the organization that runs the visitor's network (the AS organization).
browserBrowserVisitThe browser from the user agent: Edge, Opera, Samsung Internet, Yandex, Vivaldi, Brave, DuckDuckGo, Arc, Facebook, Instagram, Line, Firefox, Chrome, Safari, or Unknown. For an app that uses the SDK, the app's name.
browser_versionBrowser versionVisitThe browser and its major version, such as Chrome 141.
osOSVisitWindows, iOS, Android, ChromeOS, macOS, Linux, or Unknown.
os_versionOS versionVisitThe operating system and the first two numbers of its version, such as iOS 17.4 or macOS 10.15. Windows NT 10.0 shows as Windows 10/11.
deviceDeviceVisitDesktop, Mobile, or Tablet, from the user agent.
screenScreenVisitThe screen width as a class: Mobile under 576 pixels, Tablet under 992, Laptop under 1,440, and Desktop from 1,440.
languageLanguageVisitThe first language tag from the SDK's beacon or, for m.js, from the request's Accept-Language header, such as en-US. Up to 16 characters.

These names work in some places only:

NameWhereMeaning
prop:<key>Breakdowns and filtersThe value of one custom property. A key is 1 to 64 letters, digits, _, ., or -. An event keeps up to 30 properties, and a text value keeps its first 300 characters.
goalBreakdowns and filtersA breakdown lists every goal. A filter takes goal names and becomes the goal's event or page filter. One filter can't mix page goals and event goals.
propsBreakdownsEvery custom property at once, as key: value rows.
search_termBreakdownsGoogle searches that led to the site, read live from Google Search Console. See Search terms.

A filter value of (none) matches events or visits without a value. Filters has the operators and limits.

Other reports

Live

GET /api/v1/stats/realtime and Live ignore the period and apply the filters.

FieldDefinition
visitorsDistinct visitors with a pageview or custom event in the last 5 minutes.
pageviewsPageviews in the last 5 minutes.
minutesFor each minute from 30 minutes ago to the current minute, its pageviews and distinct visitors.
pages, sources, countriesThe top 8 of each in the last 5 minutes, by distinct visitors.
feedThe latest 40 events of the last 30 minutes, engagement pings left out.

Each window runs one minute past the current time, so an event from a browser whose clock runs a little fast still shows.

Funnels and paths

A funnel step counts the visitors who reached it, and conversion is that count as a percent of the first step's visitors, to 1 decimal. dropoff is the previous step's visitors minus this step's, and never below 0. entered counts the distinct visitors with a pageview or custom event in the period. A visitor id lasts one UTC day, so a visitor's steps must happen on one UTC day. Paths count pageviews in visit order, with reloads of the same page folded into one, and each row's share is a percent of the visitors who followed the path. Funnel modes and Paths have the rules.

Page interactions

GET /api/v1/stats/behavior reads the counts that engagement pings carry. Every count on a ping is the change since the previous ping, so the sums are exact.

ReportFieldDefinition
clicksclicks, rage, deadClicks, rage clicks, and dead clicks, summed per element and page
clickspageviews, visitorsPageviews and distinct visitors of the pages in scope, to divide the clicks by
scrollvisits, average, reachedSee Scroll depth
searchsearchesPageviews with a site search term
searchvisitors, total_visitorsVisitors who searched, and every visitor in scope
errorscount, last_seenTimes an error happened, and when it last did
formsstarts, submissionsPage views where someone started the form, and submissions
formsconversionsubmissions divided by starts, as a percent, at most 100
formsinteractions, dropoffsPer field: page views that focused it, and page views that left the form at it without a submit
mediaplays, reachedPlays, and the percent of plays that reached 25%, 50%, 75%, and the end (95%)
contentimpressions, clicks, ctrTimes tagged content was seen and clicked, and clicks as a percent of impressions, at most 100

Each report's visitors counts distinct visitors per row, such as the visitors who hit an error. See what people do on a page says what the tracker collects for each report.

Search terms come from Google

The search_term breakdown asks Google Search Console for the period when you request it, and caches the answer for ten minutes. Its numbers come from Google, so they cover only the days Google has processed, usually up to two or three days ago.

FieldDefinition
clicksClicks from Google search. The row's visitors repeats it.
impressionsTimes the site appeared in Google results for the query
ctrClicks as a percent of impressions, 1 decimal
positionThe average position in the results, 1 decimal. 1 is the top.

Google can filter only by page and device. source==Google and channel==Organic Search change nothing, because every row is Google search traffic. Any other filter returns 400.

Periods follow the site's time zone

Each site has an IANA time zone. An unknown zone name falls back to UTC. misomoon looks up the zone's offset for each instant, so a day starts at local midnight on both sides of a daylight saving change (time.ts in packages/core/src/time.ts).

periodWindowDefault interval
realtimeThe last 30 minutesminute
todayLocal midnight until nowhour
yesterdayThe local day before todayhour
24hThe last 24 hourshour
7dToday and the 6 local days before itday
28dToday and the 27 local days before itday
30dToday and the 29 local days before it. The default period.day
90dToday and the 89 local days before itday
mtdThe first of this month until nowday
lastmonthThe whole of last monthday
ytdJanuary 1 until nowweek
6moThis month and the 5 months before itmonth
12moThis month and the 11 months before itmonth
allLocal midnight of the site's first visit, or of the day the site was added when that is earlier, until nowBy length
customfrom to to, both whole local days, at most 400 daysBy length

A period that ends now runs one minute past the current time. A custom period ends at that point too when to is today.

The default interval for all and custom depends on the period's length:

LengthInterval
Up to 2 hoursminute
Up to 3 dayshour
Up to 120 daysday
Up to 400 daysweek
Longermonth

interval picks another interval. Minute buckets start on UTC minutes. Hour buckets start on local hours. Day buckets start at local midnight, week buckets on Monday at local midnight, and month buckets on the first of the month at local midnight. A series holds at most 1,500 buckets. A longer series returns 400 with the number of buckets and asks for a coarser interval. Buckets without data come back as zeros.

Imported history joins unfiltered reports

History imported from Google or from CSV files lands in each shard's imported table as daily totals per dimension and value (packages/core/src/imported.ts). misomoon adds it to a report only when the report has no filters. imported=0 leaves it out. Bring your history shows how to import.

ReportUses imported history
Headline metrics and the time seriesYes. A day lands in the bucket of its local midnight, so minute and hour charts show it at midnight.
Breakdowns of the dimensions in the next tableYes
Goal rowsNo. The visitors that conversion_rate divides by include imported visitors.
Revenue, Web Vitals, live, funnels, paths, page interactions, and other dimensionsNo

Imported visitors are each day's unique visitors, so adding days matches how misomoon counts its own visitors.

DimensionFrom a CSV exportFrom Google
channelDerived from the source and UTM tags by the channel rulesGoogle's channel group, with Organic Video and Paid Video as Video, Organic Shopping as Referral, and Paid Shopping as Paid Search. Other groups go through the channel rules.
sourceYesYes
referrerWhen the row has a referrerWhen the source contains a dot
utm_source, utm_medium, utm_campaign, utm_content, utm_termWhen setutm_source is the session source, utm_medium the medium, utm_campaign the campaign, utm_content the ad content, and utm_term the ad keyword
pageWith time on page and scroll depthWith time on page, no scroll depth
entry_pageYesYes
exit_pageYesNo
country, regionYesYes
cityNoYes
browserYesYes
browser_versionYesNo
os, os_versionYesYes
deviceYesYes
eventYesYes, without Google's own page_view, session_start, first_visit, user_engagement, and scroll

Google reports name metrics differently. misomoon reads them this way:

misomoonFrom Google
VisitorsTotal users
VisitsSessions
PageviewsViews
BouncesSessions minus engaged sessions
Visit durationUser engagement duration
Time on pageUser engagement duration of the page, divided by its sessions
EventsEvent count

What misomoon drops

These events never reach a report:

WhatRuleWhere
Your own visitsA misomoon_ignore key in the browser's local storage stops m.js from sending anything. Exclude yourself shows how to set it.m.js
Automated browsersm.js sends nothing when navigator.webdriver is true.m.js
The overlay tabA page opened with #misomoon-overlay sends nothing.m.js
Verified botsCloudflare marks the request as a verified bot.Worker
Low bot scoresCloudflare's bot score is below 10, when the request has one.Worker
Bot user agentsThe user agent is missing, shorter than 20 characters, or matches BOT_UA in packages/core/src/ua.ts. The pattern covers, among others, search and AI crawlers, link previews, headless and automated browsers, page speed tools, uptime monitors, and HTTP libraries.Worker
Bad beaconsThe body is over 16 KB or isn't JSON. The site id or the URL is missing. The URL isn't http or https. The event name is empty, over 120 characters, or holds a control character, ;, or ``.
Foreign pagesThe site doesn't exist, or the page's host isn't the site's domain or a subdomain of it.Worker
Excluded pathsA pageview or engagement ping on a page that the site's path rules leave out. Custom events on that page still count. Choose what to track explains the rules.Worker
Events past the daily capEvents after the site's cap for the UTC day. Daily ingest cap explains the cap.Worker and queue consumer
Late engagement pingsAn engagement ping that comes more than 30 minutes after its visit's last activity.Queue consumer
RepeatsAn event whose id is already stored.Queue consumer

An event whose client timestamp is more than 5 minutes from the server's clock keeps the event and takes the server's time instead. Why are my numbers lower than in Google Analytics? lists other reasons why counts differ between tools.

Search every page and heading. ↑ ↓ to move, enter to open.