Client-side JavaScript details (V1)

Our JavaScript can be used to funnel entrances and page visitors without the need for redirect links. However, the two can and SHOULD be used in tandem.

In other words, its best that our JS is always on pages, no matter the scenario.

This is because the JS not only tracks page visits, but has several helper functions that improve the reliability of tracking.

Our JavaScript details are already documented here, which explains how to obtain data from the JS and the helper functions.

However, I will give a technical summary below.

JavaScript View Tracking

Our JS will digest the embedded attributes + URL parameters, which take priority if present, and POST a payload of data to our edge (via the user's custom domain):


Our edge will respond, if tracking was successful, with a standard payload that includes the visitor's ID (a VID), current node ID, and a hit ID, e.g.

    "error": "",
    "resolvedTokens": {
        "{hit}": "1wj7y5680dz26p1g9p0101",
        "{visitor}": "afdwb7QPV6Y59aTP3fQxZ3tX2ox",
        "{current-node-id}": "0XJbzUwQYEWa"
    "skv": "vid"

The visitor ID is a session-level identifier of a user. These session objects are stored in a centralised cache that is deployed in multiple datacentres alongside our edge. 

The VIDs have that edge location encoded into the ID, such that if users have a VID value present and change locations (or e.g. VPN), our edge can check the correct cache DB for the session object.

The Hit ID is a unique ID for the current page view. A single visitor will make a unique hit ID for every node they touch.

Current node ID is self-explanatory.

Embedded Attributes and Options

Firstly, note the JS attributes in our view tracking code:

lum.event('view', {
  'query': {
    'f': '0NEijfZTGYU4',
    'n': '1S1iAMoJhuOh',
    'p': '11J2nnR5gqw2',
    // 'ts': '{TRAFFICSOURCE-ID}',
    // 'c': '{COST}'
  'options': {
    'cookieAllowed': true,
    'urlRewrite': true,
    'timeOnPage': false,
    'resolveTokens': [],
  'onDone': function (response) {}

Here, the query object sets default values that will be used unless a URL parameter is available:

  • f = funnel ID
  • n = node ID -- must exist within the declared funnel ID or will cause an error
  • p = page ID, the ID of the lander or offer, which would be inside the page group node ID above. If none provided, we will use URL matching to determine the page. 
  • ts = optional traffic source ID
  • c = optional cost

These values will be used for any organic visits that did not come from an entrance link.

For an organic view to track, the minimum requirement is a funnel ID -- without that, there is no funnel to attribute a visit to.

The page ID can be determined automatically from page URL if neither node ID or page ID is specified. It is best practice to at the very least have a page ID present in addition to the funnel ID.

If a live website is being tracked where visitors arrive other than from direct campaigns, its best to create a new traffic source like "Organic Site Traffic" or "Direct Visits" and set this as the traffic source ID. 

If none set, it will default to "organic traffic" in our system, which is a system-level source that cannot be removed, and has no URL parameters logged. On the other hand, a manually created source like "Direct Visits" could specify some common URL params like utm_campaign that might appear in traffic directed to the page by third-parties.

The options object then has several items:

  • cookieAllowed: determines if our JS drops cookies. We don't rely on them.
  • urlRewrite: on successful POST response, our JS will rewrite the current URL to append:

This is so that in subsequent action link clicks, the referrer will contain the user session identifier as well as the current node ID, allowing for reliable tracking of repeat clicks and reduced reliance on cookies.

  • timeOnPage: not yet implemented
  • resolveTokens: accepts a comma-separated list of FunnelFlux tracking tokens as quote encapsulated strings, for example:
'resolveTokens': ['{country-name}','{isp}'],

If present, the POST response object will contain the resolved values in a resolvedTokens object (note the "d" added here), which can be accessed as detailed here.

Lastly, an onDone callback function.

This is the ideal place to execute JS that depends on items in our response like resolved tokens, examples in the URL earlier.

Helper Functions

These are detailed here.

This is why its important for our JS to be present on all pages.

Firstly, The JS will automatically add a meta referrer tag to the page, which overrides the browser default behaviour and passes full referrer to onward links. 

This makes the earlier urlRewrite useful, else the referrer passed by default (in Chrome at least) is hostname only

Secondly, <a> elements on the page are scanned for *action/* and if found, our JS will append:


This explicit declaration in the action link removes any reliance on referrer/cookies in a subsequent click as the user's session identifier AND the referring node ID are declared.

Note here that the urlRewrite function adds n=CURRENT_NODE_ID to the URL, whereas action links have the current node ID added as the "rn" or "referring node" parameter.

This is important due to our other functionality: if the attribute data-lum="action" is added to any <a> element, we also append the above data.

This is useful for when direct linking between pages without an action (redirection) link, but where a user still wants to ensure reliable tracking. An example of this can be seen on the homepage. Note the source code and how the link to the cloud option will update to include these URL params.

In this scenario, passing n=CURRENT_NODE_ID would load the next page, the JS would load, and the URL parameter would try to override the current page's node ID with that of the previous node, causing issues. Hence why "rn" is always used to reference the originating node in an action link.

Was this article helpful?