Skip to main content
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

PropertyTypeDescription
page.typestringPage type (article, homepage, section, video)
page.articleobjectArticle-specific metadata
page.videoobjectVideo-specific metadata
page.sectionobjectSection/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
  }
}

FormSubmission Event

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 });
    }
  }
}

Infinite Scroll

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_debug=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
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