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 reset() on route changes:
Basic SPA Pattern
// Initial page load
var webAddon = permutive . addon ( 'web' , {
page: getPageProperties ()
});
// On route change
function onRouteChange () {
webAddon . reset ({
page: getNewPageProperties ()
});
}
React Integration
import { useEffect } from 'react' ;
import { useLocation } from 'react-router-dom' ;
function PermutiveTracker () {
const location = useLocation ();
const webAddonRef = useRef ( null );
useEffect (() => {
// Initialize on first render
webAddonRef . current = permutive . addon ( 'web' , {
page: getPageProperties ( location )
});
}, []);
useEffect (() => {
// Reset on route change
if ( webAddonRef . current ) {
webAddonRef . current . reset ({
page: getPageProperties ( location )
});
}
}, [ location . pathname ]);
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' ;
let webAddon = null ;
router . afterEach (( to , from ) => {
if (! webAddon ) {
// First page load
webAddon = permutive . addon ( 'web' , {
page: getPageProperties ( to )
});
} else {
// Subsequent navigation
webAddon . reset ({
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 {
private webAddon : any ;
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 );
if (! this . webAddon ) {
this . webAddon = ( window as any ). permutive . addon ( 'web' , {
page: pageProps
});
} else {
this . webAddon . reset ({ 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:
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 webAddon.reset() on route change
Verify reset receives new page properties
Check that router events are firing
Store webAddon reference for reuse
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