Enhancement

DeferTracker

Load third-party trackers after the first interaction, described by inert JSON

Import
@parallelogram-js/core/components/DeferTracker
Selector
[data-defer-tracker]

Playground

Tracker block

This site registers a demonstration adapter named example that loads nothing. Click anywhere and the State panel shows the status move from pending to booted.

<script type="application/json" data-defer-tracker="example">
  { "id": "docs-site" }
</script>

About

Each tracker is a <script type="application/json"> block that is never executed. DeferTracker boots the named adapter on the first click, key press or touch, or once the page has loaded and been idle for five seconds, which keeps tracker cost out of page load and lab tests such as Lighthouse.

Register the adapters a site uses with registerTrackerAdapter(name, adapter) from the same module specifier the component loads from; adapters for GA4, Google Ads, Tag Manager, Meta, TikTok, Pinterest, LinkedIn, Bing, HubSpot, Hotjar, Clarity, Plausible and Fathom are in adapters/. Because blocks are markup, registerTrackerAdapter(name, adapter, { ids, origins }) limits what they load: with ids, a block whose tracker id isn't listed is marked error and its adapter isn't called, and a block's src loads only from the page's origin, the origins the adapter declares or those in origins. Register Tag Manager with ids. A second block for a tracker already on the page, such as a Google Ads conversion beside its remarketing tag, reaches adapters that handle one, and is otherwise marked duplicate. setTrackerConsent() holds back trackers whose block names a consent category until it is granted, and skips their page steps on later pages once it is withdrawn, though a vendor script that has loaded can't be unloaded, so also call the vendor's own consent update; and configureDeferTracker({ nonce }) passes a CSP nonce to the scripts adapters add. Blocks must sit inside the element the framework observes, not in <head>; blocks elsewhere never load, and the first tracker to start logs a warning listing them.

The Deferred trackers guide lists each adapter's config keys, such as id, events, conversion and consentDefault, the options configureDeferTracker() takes (events, idleTimeout and nonce), consent with setTrackerConsent(fn, { requireCategory }) and reevaluateTrackerConsent(), and the adapter API: boot(config, ctx) with optional boot.page(config, ctx, { url, mounted }) and boot.block(config, ctx) steps.

Usage

Register the component and the framework loads it the first time a page contains [data-defer-tracker].

import { Parallelogram } from '@parallelogram-js/core';

const app = Parallelogram.create();
app.components.add('[data-defer-tracker]', () => import('@parallelogram-js/core/components/DeferTracker'));
app.run();

The framework is optional. DeferTracker.enhanceAll() mounts the component on every matching element by itself, for a page that wants one enhancement rather than a framework:

import DeferTracker from '@parallelogram-js/core/components/DeferTracker';

DeferTracker.enhanceAll();

It takes a selector and the component's options, and returns the instance it mounted them with. What it leaves out is what the framework adds: loading a component only on the pages that use it, mounting again after a page swap, and ordering with dependsOn.

Attributes

NameTypeDefaultDescription
data-defer-trackerrequiredstringnoneThe registered adapter name, such as ga4 On a <script type="application/json"> block.
data-defer-tracker-statusset by the componentpending | awaiting-consent | loading | booted | duplicate | errornoneWhere the tracker is in loading

Events

NameDetailDescription
defer-tracker:booted{ name: string }The adapter's script loaded DOM event and event bus
defer-tracker:error{ name: string; error: unknown }The adapter failed or its script could not load DOM event and event bus