page()

The page() method records a page view event. You normally never call it: the collector script sends a page view when it loads and another on every single-page-app route change. Call page() yourself only when the pipeline’s Page tracking setting is None.

Syntax

datafly.page(properties?)

Parameters

ParameterTypeRequiredDescription
propertiesRecord<string, unknown>NoAdditional properties to include with the page view

Returns

void

Automatic page views

With Page tracking set to Standard (the default) in the pipeline’s Collector tab, the script tag is all you need:

<script src="https://collect.example.com/js/<pipeline_key>/df_example.js" defer></script>

The collector then:

  • Sends one page view after it initialises on each page load
  • Sends a page view on every history.pushState, history.replaceState or popstate that changes the URL, with the previous URL as context.page.referrer
  • Ignores History API calls that leave the URL unchanged (for example scroll restoration)

The SPA (History API) setting behaves exactly like Standard.

⚠️

Do not call datafly.page() on load or from your router while automatic page tracking is on. Each call sends an extra page view, so every load or route change is counted twice.

Manual page views

Set Page tracking to None and rebuild the collector when you want to decide when page views are sent (for example, after a view has rendered its final title). The collector then sends no page views on load or on route change, and you call page() for every view, including the first load:

datafly.page();

With properties

Pass additional properties to describe the page:

datafly.page({
  page_type: 'category',
  category: 'shoes',
});
⚠️

page() throws if it is called before the collector has initialised. Call it from your application or router code, not from an inline script placed after the script tag.

Router examples (Page tracking: None only)

React Router:

import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
 
function App() {
  const location = useLocation();
 
  useEffect(() => {
    datafly.page();
  }, [location]);
 
  return <Routes>{/* ... */}</Routes>;
}

Vue Router:

import { watch } from 'vue';
import { useRoute } from 'vue-router';
 
const route = useRoute();
 
watch(
  () => route.fullPath,
  () => {
    datafly.page();
  },
  { immediate: true }
);

Automatically collected data

Every page view (automatic or manual) carries the following page context, read from the browser when the event is built:

FieldSourceExample
context.page.urlwindow.location.hrefhttps://example.com/products?q=shoes
context.page.pathwindow.location.pathname/products
context.page.referrerThe previous URL after an SPA route change, otherwise document.referrerhttps://google.com/
context.page.titledocument.titleProducts - Example Store
context.page.searchwindow.location.search (the raw query string, not parsed)?q=shoes

When the landing URL has utm_* parameters, context.campaign carries them. Without UTMs, source and medium are derived from document.referrer (for example google / organic, or the referring domain with referral); direct traffic has no campaign.

FieldSource
context.campaign.sourceutm_source, or derived from the referrer
context.campaign.mediumutm_medium, or derived from the referrer
context.campaign.campaignutm_campaign
context.campaign.termutm_term
context.campaign.contentutm_content

Ad click identifiers found in the landing URL (gclid, fbclid, ttclid, msclkid and others) are sent at the top level of the event as clickIds.<param>.

Every event, including page views, also includes:

FieldSourceExample
context.screen.width / heightscreen.width / screen.height1920 / 1080
context.screen.viewport_width / viewport_heightwindow.innerWidth / window.innerHeight1440 / 900
context.screen.densitywindow.devicePixelRatio2
context.session.idStart time of the current session (Unix milliseconds)1740492000000
context.session.numberCount of sessions on this browser3
context.session.is_new / is_first_everFirst event of a new session / of the visitor’s first sessionfalse
context.session.engagement_timeMilliseconds of visible time since the previous event5230
context.localenavigator.languageen-US
context.timezoneIntl.DateTimeFormatAmerica/New_York
context.user_agentnavigator.userAgent (the gateway falls back to the request’s User-Agent header when it is missing)Mozilla/5.0 ...
context.library.nameConstant@datafly/collector
context.library.versionConstant0.1.0

Sessions are tracked by the collector in the browser’s localStorage: a new session starts after 30 minutes without an event. The window is fixed.

The collector also sends a camelCase context.userAgent copy for older integrations. The ingestion gateway does not keep it, so blueprints, filters and custom code must read context.user_agent.

Event payload

A page view is sent as a POST to /v1/p with type: "page":

{
  "type": "page",
  "event": "page",
  "anonymousId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "context": {
    "page": {
      "url": "https://example.com/products?utm_source=newsletter&utm_medium=email",
      "path": "/products",
      "referrer": "https://example.com/",
      "title": "Products - Example Store",
      "search": "?utm_source=newsletter&utm_medium=email"
    },
    "campaign": { "source": "newsletter", "medium": "email" },
    "screen": { "width": 1920, "height": 1080, "viewport_width": 1440, "viewport_height": 900, "density": 2 },
    "session": { "id": 1740492000000, "number": 3, "is_new": false, "is_first_ever": false, "engagement_time": 5230 },
    "locale": "en-US",
    "timezone": "America/New_York",
    "user_agent": "Mozilla/5.0 ...",
    "library": { "name": "@datafly/collector", "version": "0.1.0" }
  },
  "properties": {
    "page_type": "category"
  },
  "timestamp": "2026-02-25T10:30:00.000Z",
  "messageId": "df-a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
}

Custom context

datafly.context.set() adds custom keys to the context of every event the collector builds:

datafly.context.set('experiment_id', 'exp-42');
⚠️

The ingestion gateway only accepts its defined context fields (such as page, campaign, screen, session and consent), so custom context keys are dropped at ingestion and do not reach your pipeline today. Send values you need downstream as event properties instead. Automatic page views carry no properties, so to classify page views (for example with page_type) set Page tracking to None and pass the properties in your own page() calls.

See the Configuration reference for more on the context API.