The web addon provides automatic pageview tracking, engagement measurement, and standard event capture. This is the recommended way to track user activity.
Web Addon
The web addon automatically tracks:
Pageview - When a page loads
PageviewEngagement - Periodic engagement signals
PageviewComplete - When user leaves the page
FormSubmission - When forms are submitted
LinkClick - When links are clicked
Basic Setup
permutive . addon ( 'web' , {
page: {
type: 'article'
}
});
This single call enables all automatic tracking features.
With Page Properties
permutive . addon ( 'web' , {
page: {
type: 'article' ,
article: {
title: 'Article Title' ,
categories: [ 'news' , 'technology' ],
authors: [ 'Jane Smith' ],
publishedAt: '2024-01-15T10:00:00Z'
}
}
});
Page Properties
Page properties provide context about the content and are included in Pageview events.
Standard Properties
Property Type Description page.typestring Page type (article, homepage, section, video) page.articleobject Article-specific metadata page.videoobject Video-specific metadata page.sectionobject Section/category metadata
Article Properties
permutive . addon ( 'web' , {
page: {
type: 'article' ,
article: {
// Identification
id: 'article-123' ,
title: 'Breaking News: Tech Advances' ,
// Categorization
categories: [ 'technology' , 'business' ],
tags: [ 'AI' , 'startups' , 'innovation' ],
section: 'Technology' ,
// Attribution
authors: [ 'Jane Smith' , 'John Doe' ],
publishedAt: '2024-01-15T10:00:00Z' ,
modifiedAt: '2024-01-15T14:30:00Z' ,
// Content attributes
wordCount: 1500 ,
readTime: 7 ,
premium: false ,
sponsored: false
}
}
});
Video Properties
permutive . addon ( 'web' , {
page: {
type: 'video' ,
video: {
id: 'video-456' ,
title: 'Product Demo' ,
duration: 180 ,
categories: [ 'product' , 'tutorial' ],
series: 'How-To Guides' ,
season: 1 ,
episode: 5
}
}
});
Homepage
permutive . addon ( 'web' , {
page: {
type: 'homepage'
}
});
Section Page
permutive . addon ( 'web' , {
page: {
type: 'section' ,
section: {
name: 'Technology' ,
path: '/technology' ,
level: 1
}
}
});
Automatic Events
Pageview Event
Fired immediately when addon('web') is called:
// Event structure
{
name : 'Pageview' ,
properties : {
type : 'article' ,
article : {
title : 'Article Title' ,
categories : [ 'news' ]
},
client : {
url : 'https://example.com/article' ,
referrer : 'https://google.com' ,
user_agent : '...'
}
}
}
PageviewEngagement Event
Fired periodically while the user is on the page:
// Event structure
{
name : 'PageviewEngagement' ,
properties : {
engaged_time : 30 , // seconds
completion : 0.5 // scroll depth (0-1)
}
}
PageviewComplete Event
Fired when the user leaves the page:
// Event structure
{
name : 'PageviewComplete' ,
properties : {
total_engaged_time : 120 ,
completion : 0.85
}
}
Fired when a form is submitted:
// Event structure
{
name : 'FormSubmission' ,
properties : {
form_id : 'newsletter-signup' ,
form_name : 'Newsletter' ,
// Form data (excluding sensitive fields)
}
}
Sensitive fields (password, credit card, etc.) are automatically excluded from FormSubmission events.
LinkClick Event
Fired for outbound link clicks:
// Event structure
{
name : 'LinkClick' ,
properties : {
href : 'https://external-site.com/page' ,
text : 'Click here'
}
}
Engagement Configuration
Engagement Interval
Control how often PageviewEngagement events fire:
permutive . addon ( 'web' , {
page: { type: 'article' },
eventInterval: 5000 // milliseconds (default: 5000)
});
Custom Engagement Detection
Override the default engagement detection:
permutive . addon ( 'web' , {
page: { type: 'article' },
addPageEngagementDetection : function ( callback ) {
// Custom engagement detection
// Call callback() when user is engaged
document . addEventListener ( 'mousemove' , callback );
document . addEventListener ( 'scroll' , callback );
document . addEventListener ( 'keypress' , callback );
// Return cleanup function
return function () {
document . removeEventListener ( 'mousemove' , callback );
document . removeEventListener ( 'scroll' , callback );
document . removeEventListener ( 'keypress' , callback );
};
}
});
Custom Completion Logic
Override the default scroll completion calculation:
permutive . addon ( 'web' , {
page: { type: 'article' },
getPageCompletion : function () {
// Custom completion calculation
var scrollTop = window . pageYOffset ;
var docHeight = document . documentElement . scrollHeight ;
var winHeight = window . innerHeight ;
return scrollTop / ( docHeight - winHeight );
}
});
Context Override
Override automatic context detection:
permutive . addon ( 'web' , {
context: {
url: 'https://example.com/canonical-url' ,
title: 'Custom Page Title' ,
referrer: 'https://custom-referrer.com'
},
page: { type: 'article' }
});
SPA Support
For Single Page Applications (React, Vue, Angular), call permutive.addon('web', {...}) on navigation to track a new Pageview:
Basic SPA Pattern
// Initial page load
permutive . addon ( 'web' , {
page: getPageProperties ()
});
// On navigation
function navigateToNewPage () {
permutive . addon ( 'web' , {
page: getNewPageProperties ()
});
}
React Integration
import { useEffect } from 'react' ;
import { useLocation } from 'react-router-dom' ;
function PermutiveTracker () {
const location = useLocation ();
useEffect (() => {
// Track pageview on initial load and route changes
permutive . addon ( 'web' , {
page: getPageProperties ( location )
});
}, [ location ]);
return null ;
}
function getPageProperties ( location ) {
return {
type: 'article' ,
article: {
title: document . title ,
// ... other properties
}
};
}
Vue Integration
// In router/index.js or main.js
import router from './router' ;
router . afterEach (( to , from ) => {
// Track pageview on every navigation
permutive . addon ( 'web' , {
page: getPageProperties ( to )
});
});
function getPageProperties ( route ) {
return {
type: route . meta . pageType || 'page' ,
// ... other properties
};
}
Angular Integration
// In app.component.ts
import { Router , NavigationEnd } from '@angular/router' ;
import { filter } from 'rxjs/operators' ;
@ Component ({...})
export class AppComponent {
constructor ( private router : Router ) {
this . router . events
. pipe ( filter ( event => event instanceof NavigationEnd ))
. subscribe (( event : NavigationEnd ) => {
this . trackPageview ( event . urlAfterRedirects );
});
}
private trackPageview ( url : string ): void {
const pageProps = this . getPageProperties ( url );
// Track pageview on every navigation
( window as any ). permutive . addon ( 'web' , {
page: pageProps
});
}
}
For infinite scroll pages, track additional content loads:
var webAddon = permutive . addon ( 'web' , {
page: { type: 'feed' },
dirtyEvents: [ 'contentLoaded' ] // Custom dirty events
});
// When new content loads
function onNewContentLoaded () {
// Mark page as "dirty" to trigger new engagement tracking
webAddon . markDirty ( 'contentLoaded' );
}
Filtering Events
Filter which events are tracked:
permutive . addon ( 'web' , {
page: { type: 'article' },
filterPermutiveEvent: {
// Only track form submissions with certain IDs
FormSubmission : function ( event ) {
return event . target . id !== 'search-form' ;
},
// Only track external links
LinkClick : function ( event ) {
var href = event . target . href ;
return href && ! href . includes ( window . location . hostname );
}
}
});
Debugging
Enable debug mode to see pageview tracking in action:
?__permutive.loggingEnabled=true
Console output:
[Permutive] Web addon initialized
[Permutive] Tracking: Pageview {type: "article", ...}
[Permutive] Event accepted: 1/1
[Permutive] Tracking: PageviewEngagement {engaged_time: 5}
Troubleshooting
Problem: No Pageview event in debug output.Solutions:
Verify permutive.addon('web', {...}) is called
Check that consent is granted (if consentRequired: true)
Ensure SDK is loaded before addon call
Look for JavaScript errors in console
Problem: No PageviewEngagement events.Solutions:
Check eventInterval isn’t set too high
Verify user is actively engaging (scroll, mouse move)
Ensure page stays open long enough
Test with debug mode enabled
SPA navigation not tracking
Problem: Only first pageview tracked in SPA.Solutions:
Call permutive.addon('web', { page: {...} }) on each route change
Verify the addon call receives updated page properties
Check that router events are firing correctly
Problem: Multiple Pageview events per page.Solutions:
Ensure addon('web') called only once
Check for multiple SDK initializations
Verify not calling both addon and track manually
Event Tracking Track custom events
Event Properties Structure event data
Contextual Data Page-based targeting
Video Tracking Track video content