Clickport
Start free trial

Engagement

Clickport measures engagement beyond simple pageviews. The tracker automatically records how far visitors scroll and how long they actively spend on each page. These signals combine into a unified engagement score that appears across dashboard panels.

Scroll depth

Scroll depth is the maximum vertical scroll position a visitor reaches on a page, expressed as a percentage from 0 to 100. The tracker calculates this by dividing the current scroll position by the total scrollable height of the document.

For each page a visitor views, Clickport records the furthest point they scrolled to. The value only increases. If a visitor scrolls to 78% of a blog post, that 78% is stored. If they scroll back up, the maximum remains 78%.

How it works

The tracker listens for scroll events and computes the percentage on every scroll. A ResizeObserver monitors the document body so that the scrollable height is recalculated when the page layout changes. This keeps percentages accurate on responsive pages or single-page applications where content loads dynamically.

Scroll depth progression (per page)
Visitor opens blog post 0%
Reads first paragraph 12%
Continues reading midway 48%
Scrolls back up to re-read intro still 48%
Reaches end of article 92%
Recorded scroll depth 92%

Per-page vs session averages

Scroll depth is tracked per page, not per session. If a visitor views three pages with scroll depths of 60%, 80%, and 40%, those individual values are stored separately. The Pages panel shows per-page scroll, while the KPI bar and Sources panel show session-level averages.

Session duration

Duration measures how long a visitor actively spends on your site. It is calculated from the first event to the last event in each session, but only counts time when the page is actually visible.

Visibility-aware timing

The tracker uses a start-stop timer. When the page loads, the timer starts. When the visitor switches to a different tab or minimizes the browser window, the timer pauses. When they return, it resumes. This prevents inflated durations from abandoned tabs.

Pausing is triggered by two signals:

Duration tracking with visibility detection
Page loads, timer starts 0:00
Visitor reads content 2:15
Switches to another tab paused at 2:15
Returns 10 minutes later resumed at 2:15
Continues reading for 1 more minute 3:15
Recorded duration 3:15

How engagement data is sent

When the visitor navigates away or closes the tab, the tracker sends a final engagement update. This is triggered by both pagehide and beforeunload events for maximum browser coverage. The data is sent using fetch with the keepalive flag, which allows the request to complete even after the page has unloaded.

The tracker also sends incremental updates while the visitor is active. An update is only sent when duration changes by at least 3 seconds or the maximum scroll depth increases. This avoids unnecessary network requests.

30-minute session cap

Individual sessions are capped at 30 minutes (1,800 seconds) when calculating averages. This prevents a single outlier session from skewing your numbers. The cap applies to the KPI averages and panel aggregations. Individual session records in the Sessions panel still show the actual duration.

Engagement score

The engagement score is a 0-100 metric that combines scroll depth and duration into a single number. It appears as a colored percentage in the Sources, Pages, Countries, and other panels.

The formula

The engagement score averages two components, each normalized to a 0-100 scale:

Engagement Score Formula
engagement = ( avg_scroll + min(100, avg_duration / 6) ) / 2

avg_scroll Average max scroll depth across sessions (already 0-100)
avg_duration Average session duration in seconds, capped at 1,800s (30 min)
/ 6 Converts seconds to 0-100 scale. 600 seconds (10 min) = 100
min(100, ...) Duration score is capped at 100

Worked examples

A long blog post averaging 82% scroll and 240 seconds (4 minutes) duration:

A product page averaging 95% scroll and 720 seconds (12 minutes) duration:

A landing page averaging 18% scroll and 8 seconds duration:

Color thresholds

Engagement scores are color-coded in dashboard panels to indicate quality at a glance:

Pages Sessions Goals
Pages Entry Pages Exit Pages
Page Visitors%Eng
/blog/complete-guide 842 38% 82%
/pricing 523 24% 58%
/about 291 13% 34%
/blog/short-update 187 8% 12%
Tip: A page with high traffic but a red engagement score often indicates a mismatch between what the visitor expected (from the search result or link) and what the page actually offers.

Bounce rate

Engagement metrics directly influence bounce rate. Clickport defines a bounce as a session meeting all four of these criteria:

Bounce conditions (all must be true)
1 or fewer pageviews
No outbound link clicks
Scroll depth under 25%
Duration under 15 seconds

A visitor who reads an entire blog post (high scroll) but only views one page is not counted as a bounce.

This multi-criteria approach is more forgiving than traditional bounce rate, which only checks whether the visitor viewed a single page. For more details, see the KPIs documentation.

Copy detection

Clickport also tracks when visitors copy text from your pages. When a visitor selects and copies content, the tracker captures the event along with the first 200 characters of the copied text. This appears in the Sessions panel when you drill into individual sessions.

Copy events are a useful engagement signal. They often indicate that a visitor found your content valuable enough to save or share.

Data flow

Engagement data follows this path from the visitor's browser to your dashboard:

  1. Tracker monitors activity: The engagement module tracks scroll position and accumulated visible time in real-time as the visitor interacts with the page.
  2. Incremental updates: The tracker sends updates only when duration changes by at least 3 seconds or the maximum scroll depth increases. This keeps network overhead low.
  3. Pageleave event: When the visitor navigates away or closes the tab, a final pageleave event carries the total duration (in milliseconds) and maximum scroll depth (0-100).
  4. Session update: The API receives the event and updates the session record. max_scroll_depth is set to the highest value seen across all pages in the session. duration is calculated as the time between the session start and the latest event.
  5. Bounce recalculation: On every session update, the bounce flag is recalculated using the four criteria above.
  6. Dashboard queries: Panels aggregate scroll depth and duration across sessions, apply the engagement formula, and display the color-coded result.
Browser note: The tracker uses both pagehide and beforeunload events to maximize reliability across browsers. Data is sent with fetch and keepalive: true, which allows the request to complete after the page begins unloading.