Posted by

Tracking Single-Page Apps and Virtual Pages with the HubSpot Tracking Code (_hsq)

The HubSpot tracking code records a page view when the page loads. That is exactly what you want on a classic website, but a single-page application (SPA) changes the URL and content without a full reload. Left alone, HubSpot sees only the first page. This article shows how to report virtual page views and identify visitors using the tracking code's JavaScript queue, _hsq.

How the _hsq queue works

The tracking code script defines a global array named _hsq. You push commands onto it as arrays: the first item is the command name, the rest are arguments. Because it is a queue, you can push commands before the tracking script has finished loading, and they run once it does.

var _hsq = window._hsq = window._hsq || [];
_hsq.push(['commandName', argument]);

Always use the window._hsq || [] pattern so your code works whether or not the tracking script has loaded yet.

Send a virtual page view

For a route change in an SPA, set the new path first, then ask for a page view:

function trackVirtualPage(path) {
  var _hsq = window._hsq = window._hsq || [];
  _hsq.push(['setPath', path]);
  _hsq.push(['trackPageView']);
}

// Example with a router event
router.afterEach(function (to) {
  trackVirtualPage(to.fullPath);
});

setPath tells the tracker which path to report. trackPageView sends the view. Call them in that order on every route change. Do not call trackPageView twice for the initial load: the tracking code already sent that one, so skip the first route event or guard against it.

Identify a visitor

If you know who the visitor is (for example after a login or a custom form submission), you can pass their email address so HubSpot can link the activity to a contact:

_hsq.push(['identify', {
  email: '[email protected]'
}]);
_hsq.push(['trackPageView']);

Note that identify only queues the identity. It is sent with the next tracked event or page view, so follow it with trackPageView. Only identify people who have given you their address, and never put personal data in the URL path you report.

Respect consent

If your site uses a cookie banner, do not start tracking until the visitor agrees. HubSpot's cookie banner settings control this for the standard tracking code. If you use your own consent tool, load the tracking script only after consent, or use the tracking code's consent options so that nothing is stored before it. Whatever you choose, test it in a private window and check the network tab to confirm nothing is sent before the visitor accepts.

Avoid these common mistakes

  • Forgetting setPath. Without it, every virtual page is reported under the original URL.
  • Double counting. Do not fire a page view for the first route if the tracking code already did.
  • Query strings with personal data. Strip emails, tokens and IDs from the path before you report it.
  • Tracking in development. Only run the tracking code on production hostnames, or you will pollute your reports.

Testing checklist

  1. Open the browser developer tools and the Network tab.
  2. Navigate between SPA routes and confirm one tracking request per route change.
  3. Check that the reported path matches the route you expect.
  4. In HubSpot, open the contact's activity timeline, or your page analytics, after a short delay to confirm the views appear.
  5. Repeat with consent denied and confirm nothing is sent.

Summary

For SPAs, push setPath followed by trackPageView on every route change, use identify only for visitors who gave you their email, and gate all of it behind consent. Check HubSpot's current developer documentation for the full list of tracking code commands before you ship.