invisit
All posts

By Miraç Berk15 min read

Bounce rate vs engagement rate: how GA4, Plausible and 7 others count

How GA4, Plausible, Fathom, Umami, Matomo, PostHog and three more define bounce rate, engaged sessions and time on page, with worked examples.

A soft 3D ball bouncing off an open browser window beside an hourglass and a page scroll bar, in violet dithered light and shadows.

In Google Analytics 4, bounce rate is the share of sessions that were not engaged, and engagement rate is the rest: a session is engaged when it lasts longer than 10 seconds, has a key event or has two or more page views. Universal Analytics, Plausible, Fathom, Umami and Matomo use an older rule, where a one-page visit with no event is a bounce however long it lasted, so a three-minute read is a bounce in one tool and engaged in the next.

This post sets the definitions of nine tools side by side, as each vendor documents them in November 2026, scores three sample visits with each, and shows what to measure instead. One of the nine is invisit, the analytics tool we build; its rules come from its source code, which we ran on the sample visits. Why tools disagree on the number of visitors and visits in the first place is a separate question, covered in why analytics tools show different numbers.

Bounce rate vs engagement rate: what is the difference?

Bounce rate is the share of visits that did nothing your tool counts as engagement, and engagement rate is the share that did. In GA4 the two always add up to 100%, because Google defines bounce rate as “the percentage of sessions that were not engaged” (Google).

What differs between tools is what counts as engagement. They fall into two families:

Simple Analytics sits outside both, because it reports no bounce rate at all. A bounce rate is only comparable with another bounce rate from the same tool, under the same rule.

How does GA4 define bounce rate and an engaged session?

GA4 counts a session as engaged when it “lasts longer than 10 seconds”, “has a key event” or “has 2 or more screen or page views”. Bounce rate is the share of sessions that meet none of the three, and engagement rate is engaged sessions divided by all sessions (engagement rate and bounce rate). The automatic first_visit, first_open and session_start events never make a session engaged, even when marked as key events.

Three details move the GA4 number:

How did Universal Analytics calculate bounce rate?

In Universal Analytics, a bounce was a session that sent “only a single request to the Analytics server”, and bounce rate was single-page sessions divided by all sessions (UA bounce rate). Any event ended the bounce unless it was sent with the non-interaction flag.

UA timed a session from its first hit to the first hit on the last page, or to the last engagement hit on that page if there was one (UA session duration). A bounce therefore lasted 0 seconds, and every bounce pulled average session duration toward zero. Time on page was “the difference between the initiation of successive pageviews” (UA sessions), so the last page of a visit got none. Standard UA properties stopped processing data on July 1, 2023, and the interface and API closed on July 1, 2024 (Google). Its page-count rule lives on in Plausible, Fathom, Umami and Matomo.

Bounce rate, visit duration and time on page in nine tools

As of November 2026, from each vendor’s documentation, or its source code where the docs are silent or out of date:

Tool A visit is a bounce when Time per visit Time per page
GA4 10 seconds or less (adjustable), no key event, under 2 page views Average session duration, plus engagement time counted only while in focus Engagement time, in focus only
Universal Analytics One request: one page, no interaction event First hit to the last page’s first or last engagement hit; a bounce is 0 s Gap between successive page views
Plausible One page and no custom event; interactive: false events don’t count Visit duration; one-page visits count as 0 s From engagement events; inactive tabs not counted
Fathom Exactly one page view in the visitor’s 24-hour window Time on site from departure pings; hidden tabs not counted From the same pings
Umami One page view and no custom event (v3.4.1 source) First to last page view of the visit; one-page visits 0 s None in its metric definitions
Matomo One page view, no event, download or goal conversion One-page visits 0 s unless the heartbeat timer is on Time on page; the last page needs the heartbeat timer to be timed
Simple Analytics No bounce rate None Median visible seconds; views under 5 s left out
PostHog One page view, no autocapture, under 10 seconds (adjustable) Last event minus first event of the session Through the previous page view duration property, in insights
invisit Under 10 s of active time, no custom event, under 2 page views First to last event of the visit; average active time in the API No report; scroll depth per page instead

How does Plausible calculate bounce rate?

Plausible marks a visit as a bounce unless the visitor “views more than one page” or “triggers a custom event” (metrics definitions). An event sent as plausible('Custom Event', {interactive: false}) is still recorded but leaves the bounce in place. Plausible’s visit duration counts one-page visits as 0 seconds, while its time on page comes from an engagement event sent whenever the visitor navigates or switches tabs, so a bounced reader still gets a time on page.

How does Fathom calculate bounce rate?

Fathom’s bounce is “a visitor who views exactly one page during their visit”, judged within a 24-hour window: someone who reads one page in the morning and another in the afternoon is not a bounce (how Fathom measures). Since its March 2026 rebuild, Fathom’s script sends a departure ping when a page is left or hidden, so a one-page visit gets a real time on site. Hidden-tab time is not counted, a ping reports at most 30 minutes, and a ping never undoes a bounce (data journey).

How does Umami calculate bounce rate?

Umami’s docs define a bounce as a visit with “only 1 event” (metric definitions). The query in Umami v3.4.1, released October 23, 2026, counts a visit with one page view and any custom event as not a bounce (source). Umami’s visit duration runs from the visit’s first page view to its last, leaving out custom events, so a one-page visit adds 0 seconds.

How does Matomo calculate bounce rate?

Matomo counts a bounce when a visitor views one page and “triggers no other tracked interaction (such as an event, download, or goal conversion)”, and the rule cannot be changed (Matomo FAQ). One-page visits last 0 seconds unless you turn on the heartbeat timer with _paq.push(['enableHeartBeatTimer']). It sends a ping when the visitor leaves or hides the page, once at least 15 seconds have passed since the previous request by default (JavaScript guide). The ping updates the duration but creates no action, so a reader with the timer on is still a bounce, now with a real duration.

Does Simple Analytics show bounce rate?

Simple Analytics reports no bounce rate, and its Stats API has no bounce field. Its time on page is the median of the seconds a page was visible, from script version 12, and page views under 5 seconds are left out of it as bounced views (time on page). It also records how far each page view scrolled.

How does PostHog calculate bounce rate?

PostHog’s bounce is a session with “only one pageview, no autocaptures”, that “spent less than 10 seconds on the page”, and the 10 seconds can be changed in web analytics settings (dashboard docs). Session duration is the last event’s timestamp minus the first’s (source), so the $pageleave event the docs ask you to capture is what gives a one-page session its length; without it or another later event, the session lasts 0 seconds. Events you send with posthog.capture() are not part of the rule; only autocaptured interactions end a bounce. Time on page comes from the previous page view’s duration property, in insights (session metrics).

How does invisit calculate bounce rate?

invisit counts a visit as engaged when it has at least 10 seconds of active time, any custom event or conversion, or 2 or more page views. Every other visit is a bounce.

Active time is measured in the browser. The tracker counts time while the tab is visible and less than 5 seconds have passed since the last pointer press, key press, scroll, touch or mouse wheel movement, and reports each page’s total when the visitor leaves it or moves to another route in a single-page app. Moving the mouse alone does not count.

How one visit is scored by each definition

The same visit gets a different verdict in each tool. Three sample visits:

  1. The reader: arrives on a blog post from search, reads for 3 minutes, scrolling every 8 seconds or so, and closes the tab. One page view, no events.
  2. The quick click: lands on the home page, clicks Pricing after 3 seconds and leaves 4 seconds later. Two page views in 7 seconds.
  3. The app user: opens a one-address tool, such as a calculator or a single-page app screen whose URL never changes, and clicks and types in it for 2 minutes. One page view, no events sent.
Tool The reader (1 page, 3 min) The quick click (2 pages, 7 s) The app user (1 URL, 2 min)
GA4 Engaged Engaged Engaged
Universal Analytics Bounce, 0 s Not a bounce, 3 s Bounce, 0 s
Plausible Bounce, 0 s visit, about 3 min on the page Not a bounce Bounce, unless you send a custom event
Fathom Bounce, about 3 min time on site Not a bounce, about 7 s Bounce, about 2 min time on site
Umami Bounce, 0 s Not a bounce, 3 s Bounce, 0 s
Matomo Bounce, 0 s (about 3 min with heartbeat) Not a bounce, 3 s Bounce, 0 s (about 2 min with heartbeat)
Simple Analytics No bounce rate, 3 min in time on page No bounce rate, both pages under 5 s No bounce rate, 2 min in time on page
PostHog Not a bounce, with $pageleave captured Not a bounce Not a bounce, through autocaptured clicks
invisit Engaged, 3 min visit, 110 s active Engaged, 7 s visit Engaged, 2 min visit, 118 s active

The quick click passes in every tool that reports a bounce rate, while the reader, who stayed more than 25 times as long, is a bounce in five of those eight. That is the case against reading a page-count bounce rate on a blog or a docs site.

For the other eight tools the cells apply each vendor’s documented rule; we did not run their scripts. For invisit, we fed the three visits to the tracker’s engagement code and to the sessionizer our backend runs, with a simulated clock, and the invisit row is what they returned. Then we checked the clock in a real browser: in headless Chrome 155, 26 seconds on a long page with a wheel scroll every 3 seconds reported 23 seconds of active time and a scroll depth of 100%.

Two more visits split the engagement-based tools:

The app user changes once its screens have their own addresses and your tool records client-side navigation as page views: every page-count rule then sees several pages and stops calling the visit a bounce. Whether yours does is covered in how single-page apps count page views.

What is a good bounce rate?

There is no single good bounce rate, because the number depends on the definition your tool uses, on what the page is for and on where its visitors came from. The reader above is a bounce in Plausible and engaged in GA4, so a blog full of readers shows a high bounce rate in one tool and a low one in the other.

The vendors’ own guidance says as much:

The only peer benchmark from a primary source we found is inside GA4. Its Benchmarking feature shows the median and the 25th to 75th percentile range of a peer group in your industry for metrics including bounce rate and engagement rate, with data from May 30, 2024 (benchmarking). It needs the “Modeling contributions & business insights” setting turned on (setup), it compares you only with other GA4 properties under GA4’s definition, and Google publishes no figures outside the product.

So compare a page with itself over time, one traffic source with another on the same page, and the weeks before an edit with the weeks after. Two readings deserve a look at the tracking before any conclusion. A site-wide rate close to 0% usually means a second page view or an event fires on load. A sudden 100% bounce from one city is usually automated traffic, as explained in our post on bot traffic.

How to measure real engagement instead of bounce rate

Measure what the visitor did on the page: how long they were there and active, how far down they got, and whether they did the one thing the page exists for. All three are a better signal than a bounce rate, and most tools offer them:

Measure What it tells you Where to read it
Active or focused time Whether the visitor stayed with the page GA4 average engagement time, Plausible and Fathom time on page, Simple Analytics median time on page, invisit active time in the API
Scroll depth How much of the page they reached GA4 scroll event at 90% depth, Plausible scroll depth, PostHog scroll depth per path, Simple Analytics scrolled percentage, invisit average depth and share of views reaching 25, 50, 75 and 100%
A meaningful event Whether the page did its job The events or goals report of any tool, for a signup, a download or a finished article

GA4’s scroll event fires the first time “a 90% vertical depth becomes visible”. invisit records the deepest point each page view reached, in 5% steps, and reports it per page in the API and on heatmaps.

Which events end a bounce?

Before you add an event, decide whether it should change your bounce rate, because each tool treats a custom event differently:

Tool Does a custom event end a bounce?
GA4 Only if it is marked as a key event
Universal Analytics Yes, unless sent as a non-interaction event
Plausible Yes, unless sent with interactive: false
Fathom No, a bounce counts page views only
Umami Yes, in v3.4.1
Matomo Yes: events, downloads and goal conversions
PostHog No, only autocaptured interactions
invisit Yes: every custom event and conversion, automatic outbound and download events too

Track a finished article

A read-to-the-end event is the meaningful event for a blog or docs page. This one fires once per page view, when the end of the article scrolls into view, and records how many seconds after load that happened:

src/read-to-end.ts
import { track } from '@invisitdev/web'

// Sends article_read once per page view, when the end of the article scrolls into view.
export function trackReadToEnd(article: Element): void {
  const end = document.createElement('div')
  article.append(end)
  const loadedAt = performance.now()
  const observer = new IntersectionObserver((entries) => {
    if (!entries.some((entry) => entry.isIntersecting)) return
    observer.disconnect()
    const seconds = Math.round((performance.now() - loadedAt) / 1000)
    track('article_read', { seconds })
  })
  observer.observe(end)
}

Pass it your article element on each page load, and again after each route change in a single-page app. We ran it in headless Chrome 155 against a local invisit collector: on a page 3,600 pixels tall, article_read fired once, 12 seconds in, with seconds: 12, as the end came into view. The seconds property lets you separate readers from visitors who jumped straight to the bottom. Details on events are in custom events.

In GA4 the same event is gtag('event', 'article_read', { seconds }), and it only makes sessions engaged once you mark it as a key event. In Plausible, plausible('Article read', { props: { seconds } }) ends the bounce unless you add interactive: false. Google’s GA4 guide advises against generic keep-alive pings that hold a session open, because inflating session metrics “distorts user behavior data” and makes sessions look engaged; it suggests user-initiated progress events instead (GA4 sessions guide).

Checklist before you report a bounce rate