Plugins
Scroll Tracking
Overview
This plugin tracks user scroll depth in a Nuxt 3 application and logs virtual scroll events at specific milestones (10%, 25%, 50%, 75%, 90%).
Useful for measuring engagement and visibility of content, especially in analytics platforms.
Plugin Source
export default defineNuxtPlugin((nuxtApp) => {
let isTriggered = false;
let triggeredPercentages = [false, false, false, false, false];
function handleScrollLogEvent(percentage: number) {
logEvent({
options: {
eventAction: "scroll",
eventProperties: {
scroll_depth: percentage,
},
eventInteraction: true,
eventLabel: `scroll_depth:${percentage}%`,
eventName: "virtual_scroll",
},
});
}
const handleScroll = () => {
const scrollTop = window.scrollY || document.documentElement.scrollTop;
const windowHeight = window.innerHeight;
const documentHeight = document.documentElement.scrollHeight;
const scrolledPercentage =
(scrollTop / (documentHeight - windowHeight)) * 100;
if (scrolledPercentage >= 10 && !triggeredPercentages[0]) {
triggeredPercentages[0] = true;
handleScrollLogEvent(10);
}
if (scrolledPercentage >= 25 && !triggeredPercentages[1]) {
triggeredPercentages[1] = true;
handleScrollLogEvent(25);
}
if (scrolledPercentage >= 50 && !triggeredPercentages[2]) {
triggeredPercentages[2] = true;
handleScrollLogEvent(50);
}
if (scrolledPercentage >= 75 && !triggeredPercentages[3]) {
triggeredPercentages[3] = true;
handleScrollLogEvent(75);
}
if (scrolledPercentage >= 90 && !triggeredPercentages[4]) {
triggeredPercentages[4] = true;
handleScrollLogEvent(90);
}
};
// Attach scroll listener on app mount
nuxtApp.hook("app:mounted", () => {
window.addEventListener("scroll", handleScroll);
});
// Reset triggered flags on route change
nuxtApp.hook("page:finish", () => {
isTriggered = false;
triggeredPercentages = [false, false, false, false, false];
});
});
Scroll Depth Thresholds
The following scroll depths are tracked:
- 10%
- 25%
- 50%
- 75%
- 90%
Each threshold is logged only once per page view.
Event Logging Schema
Each event uses this structure:
| Field | Value |
|---|---|
eventName | "virtual_scroll" |
eventAction | "scroll" |
eventLabel | "scroll_depth:{percentage}%" |
eventProperties.scroll_depth | Number (10, 25, 50, etc.) |
eventInteraction | true |
Usage Notes
- Works on client side only
- Automatically resets scroll depth triggers after every route change
- No native hook exists for
app:unmountedorroute:changed, so scroll listener persists between pages (should not be an issue unless component-scoped)