Title: Dynamic Tracking: Setup and configuration
Author: joshua
Published: August 1, 2022
Last modified: July 20, 2026

---

 1. [Installation resources](https://docs.parse.ly/installation-resources/)
 2. [Parse.ly Integration](https://docs.parse.ly/installation-resources/parsely-integration/)
 3. [Tracking code](https://docs.parse.ly/installation-resources/parsely-integration/tracking-code-setup/)
 4. Dynamic Tracking: Setup and configuration

#  Dynamic Tracking: Setup and configuration

The standard Parse.ly tracking code is useful for most situations. However, there
are times when you want more control over the behavior of this code. Perhaps you
don’t want to trigger a pageview automatically. Or, you may want to trigger multiple
page views, at different times, on the same page (not to be confused with [single-page applications](https://docs.parse.ly/single-page-application/)).
We recommend that you implement Dynamic Tracking for cases such as the following:

 * Infinite scroll
 * Image carousels
 * Sending custom events
 * Tracking downloadable files

## Overview

Here is a full example that we will then break into functional parts:

    ```lang-php
    <script>
      window.PARSELY = window.PARSELY || {
        onload: function() {
          // will be called once PARSELY tracking code is loaded

          // bind pageview tracking for all "next" links.
          // example event listener; set your own based
          // on your site design
          jQuery("a.next").on("click", function() {
            var url = this.href,
              urlref = location.href;

            PARSELY.beacon.trackPageView({
              url: url,
              urlref: urlref,
              js: 1
            });
            return true;
          });
        }
      };
    </script>

    <!-- START Parse.ly Include -->
    <!-- ...insert the parsely tracker code here... -->
    <!-- END Parse.ly Include -->
    ```

**Note**

The dynamic tracking code must be placed _before_ the standard Parsely tracking 
snippet.

The code above waits until the Parse.ly tracking code has finished loading, and 
then using jQuery attaches to all click events for links with class `next`. On click,
a request to the analytics server is sent. The `url` of the tracking event is set
to the link that was clicked, whereas the `urlref` is set to the current URL (before
the event is sent and before a page transition happens).

This preserves the “internal referrer” (page-to-page tracking) for Parse.ly, while
still allowing you to load the next piece of content dynamically, without incurring
the cost of a full page refresh.

Note that `url` and `urlref` values are required to be absolute paths. This means
that relative paths are not accepted (e.g. `"/article"` as opposed to `"http://www.
example.com/article"`); they must be full URLs. They should also resolve or redirect
to an actual page on your site that has crawlable metadata (see [Providing Metadata for Dynamic Content](https://docs.parse.ly/installation-resources/parsely-integration/tracking-code-setup/dynamic-tracking?output_format=md#h-providing-metadata-for-dynamic-content)
below).

## The onload handler

Parse.ly’s tracker code loads asynchronously, so the only way to reliably interact
with its API is to set a handler for an `onload` event that the API exposes.

Define a `PARSELY` object **before** the tracking code like this:

    ```lang-php
    <script>
      window.PARSELY = window.PARSELY || {
        onload: function() {
          console.log("Parse.ly code has loaded");
          // add your event listeners here
        }
      };
    </script>

    <!-- START Parse.ly Include -->
    <!-- ...insert the parse.ly tracker code here... -->
    <!-- END Parse.ly Include -->
    ```

## Adding an event listener

Find the appropriate selector and attach an event listener to use as the trigger
for when to send the dynamic tracking call. You can use jQuery (as in the example
below) or vanilla JavaScript with an [`addEventListener()` method](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener).

The below example imagines a site that has an `<a>` tag with a class value of `next`(`
<a class="next" href="...">`) that will trigger when it is clicked. **Your event
listener will be different**.

    ```lang-php
    jQuery("a.next").on("click", function() {
      var url = this.href,
      urlref = location.href;

      //dynamically send tracking call

      return true;
    });
    ```

## Providing Metadata for Dynamic Content

When your site loads a new piece of content, it’s important to update your [metadata](https://docs.parse.ly/metadata/)
before making additional tracking calls.

While you can fire pageviews dynamically, Parse.ly’s [web crawler](https://docs.parse.ly/crawler/),
which extracts your metadata, can’t execute JavaScript. It must be able to access
the metadata tag from the results of a single GET request. That means your metadata
has to be included directly in the page source.

To configure metadata for dynamic content, just make sure that any content loaded
dynamically can also be accessed at a standalone, static URL. For example, perhaps
you have an article `http://example.com/article1`, and when a reader reaches the
bottom of the page, you load a new article via infinite scroll, firing a pageview
for `http://example.com/article2`. Parse.ly’s crawler can pick up that new article’s
metadata just fine, provided that `http://example.com/article2` is publicly accessible,
with the desired metadata included in the page source.

This also means that any URLs sent as part of a dynamic tracking call should resolve
to a page on your site that hosts metadata as described above. In the case of a 
photo gallery that loads with qsargs, hash URLs, Javascript, or scroll, you can 
use a dedicated `qsarg` in the URL that’s sent to Parse.ly (example: a photo gallery
that takes place on `example.com/base` would have `/base?slide=1`, `/base?slide=
2`, etc.). The key here is to ensure that the [canonical URL](https://docs.parse.ly/the-parsely-canonical-url/)
is always the same as it will be our source for the metadata on the page.

## Dynamically sending a tracking call

To send a tracking request to the analytics server use `PARSELY.beacon.trackPageView`.
It takes a single JavaScript object (dictionary) with keys and values that will 
be beaconed to Parse.ly’s servers.

Note that the function is available only after the tracker code has finished loading.

    ```lang-php
    PARSELY.beacon.trackPageView({
      url: url,      // URL to be tracked
      urlref: urlref,   // Referring URL
      js: 1        // flag indicating this is dynamic
    });
    ```

We used this object to demonstrate how to [Track Files](https://docs.parse.ly/track-files/).

## Disabling on-load tracking

The default behavior of the tracking code is to report an event as soon as the script
has finished loading. You can prevent the behavior, by setting `PARSELY.autotrack`
to `false` _before_ the include.

    ```lang-php
    <script>
      window.PARSELY = window.PARSELY || {
        autotrack: false,
        onload: function() {
          // add event listeners or other dynamic tracking logic, such as:
          // PARSELY.beacon.trackPageView({ ... })
        }
      };
    </script>
    <!-- START Parse.ly Include -->
    <!-- ... as above ... -->
    <!-- END Parse.ly Include -->
    ```

Subsequent events could then be tracked using dynamic tracking.

If your account supports [engaged time tracking](https://docs.parse.ly/engaged-time/),
heartbeat events will be sent on every page by default, even when `PARSELY.autotrack`
is set to `false`. If you plan to use dynamic tracking for pageview events, this
behavior ensures that the tracker captures the full engagement. But if you need 
to disable both pageviews and heartbeat events, additionally set `PARSELY.config.
heartbeat_should_honor_autotrack` to `true`, as in the example below.

    ```lang-php
    <script>
      window.PARSELY = window.PARSELY || {
        autotrack: false,
        config: {
          heartbeat_should_honor_autotrack: true
        },
        onload: function() {
          // add event listeners or other dynamic tracking logic, such as:
          // PARSELY.beacon.trackPageView({ ... })
        }
      };
    </script>
    <!-- START Parse.ly Include -->
    <!-- ... as above ... -->
    <!-- END Parse.ly Include -->
    ```

> This option is only supported in tracker versions above 1.0.3. If you’re unsure
> of your tracker version, contact [Parse.ly Support](https://support.parse.ly/hc/en-us)

## Sending custom events

Parse.ly instruments `pageview` events by default. This helps us track views and
visitors. We also instrument `heartbeat` events for customers who have accounts 
with support for [engaged time](https://docs.parse.ly/engaged-time/).

In addition, our video tracker instruments two events, `videostart` and `vheartbeat`.
The former tracks video start events and video visitors, while the latter tracks
engaged time while watching videos.

However, you can send other custom events to Parse.ly by changing the `action` attribute
in your dynamic tracking calls.

To guarantee you don’t use a Parse.ly reserved name, we recommend you prefix custom
events with an underscore, e.g. `_subscribe` to track an e-mail newsletter subscription
event, or `_share` to track a share button click event. Here is an example of tracking
a custom social share event from your pages:

    ```lang-php
    PARSELY.beacon.trackPageView({
      url: url,
      urlref: urlref,
      action: "_share"    // custom event type
    });
    ```

These custom events will be ignored by Parse.ly’s dashboard and live APIs, but will
be accessible to you via Parse.ly’s [Raw Data Pipeline](https://docs.parse.ly/data-pipeline/).

## Sending custom data with events

Arbitrary data can be included in the `trackPageView` call by including a `data`
attribute in the argument object. This could be used to track a custom per-page 
or per-user data, such as identifiers or internal web application data.

Note that the `data` object cannot include the keys `parsely_uuid` or `parsely_site_uuid`.
Again, we recommend you use a leading underscore to avoid collision with reserved
Parse.ly names. So, for example, to track a custom “scroll” event that also includes
the current [scroll depth](https://docs.parse.ly/scroll-depth-tracking/), you could
send the following:

    ```lang-php
    PARSELY.beacon.trackPageView({
      url: url,
      urlref: urlref,
      action: "_scroll",   // custom event type
      data: {
        _y: window.scrollY // custom event attribute
      }
    });
    ```

Again, this custom scroll event will be ignored by Parse.ly’s dashboard and APIs,
but you can use it to do scroll depth calculations via Parse.ly’s [Raw Data Pipeline](https://docs.parse.ly/data-pipeline/).
In that case, it would show up as events where `action` is `_scroll` and `extra_data.
_y` is set to an integer in the JSON object of your raw records.

When debugging custom events, you can filter on that action name in the network 
tab of your browser development tools: `_scroll` for the event above.

You can also use `updateDefaults` to set persistent custom data that will be sent
along with each event regardless of whether you’re using dynamic tracking.

    ```lang-php
    window.PARSELY = window.PARSELY || {
      onload: function() {
        PARSELY.updateDefaults({data: {_y: window.scrollY}});
      }
    };
    ```

Calling `updateDefaults` in `onload` will cause the passed parameters to be sent
with all pixel requests from the tracker, including the initial pageload, video 
and engagement events, and and dynamic tracking calls. Any default `data` properties
set this way can still be overridden in a `PARSELY.beacon()` call. As above, fields
nested in a `data` object will appear in the Raw Data Pipeline as attributes on `
extra_data`.

## Queueing events before onload

When loading the Parse.ly JavaScript tracker asynchronously (the default behavior),
it is possible that you’ll want to track events before the tracker has finished 
loading. This situation can arise when using an infinite-scroll layout, for example.

To handle this situation, you can queue events that occur before `PARSELY.onload`
is called and flush that queue during `onload`. The following example code demonstrates
this technique.

    ```lang-php
    var parselyPreload = {eventQueue: [], loaded: false};

    // run this when you would fire an event
    function fireParselyEvent() {
      var event = {
        url: location.href,
        urlref: document.referrer,
        js: 1
      };
      if (parselyPreload.loaded) {
        PARSELY.beacon.trackPageView(event);
      } else {
        parselyPreload.eventQueue.push(event);
      }
    }

    // when Parse.ly is done loading, flush the queue
    window.PARSELY = window.PARSELY || {
      autotrack: false,
      onload: function() {
        parselyPreload.loaded = true;
        for (var i = 0; i < parselyPreload.eventQueue.length; i++) {
          PARSELY.beacon.trackPageView(parselyPreload.eventQueue[i]);
        }
      }
    };
    ```

## Example use cases

The following examples are necessarily simplified for illustration purposes, and
are not meant to be used as-is. Any dynamic tracking logic should be customized 
and tailored to your specific site.

### Transforming non-standard campaign parameters to supported parameters

The Parse.ly dashboard can display detailed campaign data when you use [supported parameters](https://docs.parse.ly/setting-up-campaign-tracking-parsely//).
If you’re already using non-supported parameters to track campaigns in other systems,
it’s possible to re-format those before sending a Parse.ly pageview.

***Example:** Convert `src` parameters to `utm_source` before sending a Parse.ly
pageview (so the values will be collected under the “Campaign Source” in the dashboard):*

    ```lang-php
    window.PARSELY = window.PARSELY || {
      // disable automatic tracking
      autotrack: false,
      onload: function() {
        // will be called once, when the tracker loads
        function renameParams(rawUrl, oldParam, newParam) {
          // modify or replace this function as necessary
          // a regex replacement is sufficient in this scenario,
          // but more complicated situations might require
          // parsing parameters or further transforming their values
          var re = new RegExp("(.*?[&?])(" + oldParam + ")(?==)")
          return rawUrl.replace(re, "$1" + newParam);
        }
        // dynamically send a pageview with a modified url
        window.PARSELY.beacon.trackPageView({
          url: renameParams(location.href, "src", "utm_source"),
          urlref: document.referrer,
          js: 1
        });
      }
    };

    // insert the parsely tracker code here...
    ```

## Using GTM

Built into the Parse.ly GTM tag template is the ability to configure a [dynamic tracking tag](https://docs.parse.ly/google-tag-manager/#h-dynamic-tracking).
This allows you to leverage the tools of your GTM container to configure when you
want to trigger the dynamic pageview.

You can use the GTM dynamic tracking tag even if you have implemented the Parse.
ly tracker via another method (e.g. the [WordPress plugin](https://docs.parse.ly/wordpress-plugin-setup/)
or [hardcoded](https://docs.parse.ly/tracking-code-setup/)). You just need to ensure
the `PARSELY` object has been loaded _before_ triggering the tag.

Last updated: July 20, 2026