Skip to content
More languages coming soon

Reference

Web SDK reference ​

@analyticstrend/web. For ordinary websites.

init(options) ​

Call once per page load. Returns a client.

js
const analytics = init({ writeKey: "wk_..." });
OptionTypeDefaultNotes
writeKeystringrequiredFrom your dashboard's Settings screen. Public by design.
endpointstringhttps://analyticstrend.comA collector other than AnalyticsTrend's own.
appVersionstringnoneYour site's version, so you can compare releases.
onError(error) => voidnoneDiagnostic only. Deliberately has no default, because this runs in your page and we do not get to decide what lands in your console.
autoCapturebooleantrueRecords where the visit came from and which pages it moves between. See below.
engagementbooleantrueFrom 0.6.0. Records how long each page was visible, while autoCapture is on. See visible time.
respectGlobalPrivacyControlbooleantrueA browser sending Global Privacy Control sends nothing and stores nothing. Set false only on a considered legal position. See below.
clearDataOnGlobalPrivacyControlbooleanfalseAlso delete an identifier and queue stored before the signal appeared. Ignored when the signal is not respected.
pageViews"history"noneFrom 0.5.0. Sends a page_view now and each time the path changes, in-app navigation included. Leave it out if you send page_view yourself. See single-page applications.
outboundLinksbooleanfalseFrom 0.5.0. Sends outbound_click when a link to another site is followed. See link events.
fileDownloadsbooleanfalseFrom 0.5.0. Sends file_download when a file link is followed.
contactLinksbooleanfalseFrom 0.5.0. Sends email_click or phone_click when an email or phone link is followed.
formSubmissionsbooleanfalseFrom 0.7.0. Sends form_submit when a form is submitted, with the form's id or name only. See form submissions.

Returns { track, flush, enabled }. enabled is false when the browser sent Global Privacy Control and nothing is being counted.

init also registers handlers for pagehide and for the tab becoming hidden, and sends anything left over from a previous visit as soon as it starts.

The script tag ​

dist/script.js, for sites without a build step, is the same SDK in one file. The install guide has the exact tag. It reads these attributes from its own <script> element:

AttributeMeaning
data-write-keyRequired. Without it the script warns once in the console and does nothing.
data-endpointA collector other than AnalyticsTrend's own, as init({ endpoint }).
data-auto-capture="false"As init({ autoCapture: false }).
data-engagement="false"As init({ engagement: false }).
data-respect-gpc="false"As init({ respectGlobalPrivacyControl: false }).
data-clear-on-gpc="true"As init({ clearDataOnGlobalPrivacyControl: true }).
data-page-viewsFrom 0.5.0, a page_view on load and each time the path changes, as init({ pageViews: "history" }). "load" sends one when the page loads only, as 0.4 did; "false" sends none.
data-outbound-links="true"As init({ outboundLinks: true }).
data-file-downloads="true"As init({ fileDownloads: true }).
data-contact-links="true"As init({ contactLinks: true }).
data-form-submissions="true"From 0.7.0, as init({ formSubmissions: true }).

The client is window.analyticstrend, with the same track and flush as below. Loaded as type="module", the script cannot find its own tag and starts nothing, so use a plain <script>. One added later by a tag manager works, as long as it keeps the attributes.

Global Privacy Control ​

From 0.3.0, a browser that sends Global Privacy Control is not counted: init returns a client that sends nothing, stores nothing, and registers no listeners. The signal is read once per page load.

Your counts drop by the share of visitors who send it. No report can show how many, because showing it would mean collecting from them.

By default an identifier or queue stored before the signal appeared stays on the device, unsent. No privacy law requires deleting it, since the signal asks for no further processing. Set clearDataOnGlobalPrivacyControl: true to delete it anyway.

js
const analytics = init({
  writeKey: "wk_...",
  respectGlobalPrivacyControl: true, // the default
  clearDataOnGlobalPrivacyControl: true,
});

What is captured automatically ​

From 0.2.0, the SDK attaches a few properties of its own so that the Sources and Pages reports work without your writing any code. They are namespaced with a $ so they can never collide with a property of yours.

The collector adds a country (with a region in some countries), browser, OS and device families, and the browser's primary language of its own, worked out from the request rather than sent by the SDK: see what the collector works out from each request.

PropertyWhere it comes from
$referrerthe referring site's hostname, when it is not your own site
$utm_source, $utm_medium, $utm_campaign, $utm_content, $utm_termthe landing URL
$refthe ref parameter, or source if there is no ref
$click_idthe name of a gclid, msclkid or fbclid parameter, never its value
$paththe current path, on every event
$from_paththe previous path, on page views only
$engaged_mshow long a page was visible, in milliseconds, on page_engagement only (from 0.6.0)

Three things worth knowing about how this behaves:

  • Only those parameter names are read. The rest of the query string is never looked at. Query strings routinely carry email addresses and password-reset tokens, and a tool that swept them up could not honestly claim to collect nothing about who people are.
  • The source is resolved once per document. document.referrer does not change when a single-page app changes route, so re-reading it per event would credit every route change to the site the visit originally came from.
  • $from_path works in both kinds of site. In a single-page app the SDK remembers the previous path itself. On a full page load it falls back to a same-origin referrer, whose path survives where a cross-origin one would have been cut down to a hostname.

To turn all of it off:

js
const analytics = init({ writeKey: "wk_...", autoCapture: false });

The $ namespace is reserved. Sending a $-prefixed property of your own is rejected, so that nothing of yours is ever mistaken for something we captured.

Visible time ​

From 0.6.0, with auto-capture on, the SDK records how long a page was visible. When the page is hidden or closed, or a single-page app moves to another path, it sends a page_engagement event whose $engaged_ms says how long the page was visible since the last one. Time in a background tab is not counted. Under a second is not sent, and waits for the next one; one event says at most 30 minutes, so a tab left open overnight cannot stretch a visit.

That is what visit duration and bounce rate are counted from. It carries no identity beyond the random identifier every event has, and appears nowhere else in your reports.

It is a new kind of collection that is on by default, so check that your own privacy wording covers how long pages are viewed. Turn it off on its own with init({ engagement: false }) or data-engagement="false"; autoCapture: false turns it off with the rest. The name page_engagement is reserved: an event of your own with that name is read as one of these.

From 0.5.0, three options record what visitors follow on your pages. Each is off until you turn it on, because each is a kind of collection your own privacy wording should mention first.

OptionEventProperties
outboundLinksoutbound_click$host: the other site's hostname, never its path or query
fileDownloadsfile_download$file: the file's name, such as guide.pdf, and $host when the file is on another site
contactLinksemail_click, phone_clicknone: the email address or phone number is never read

A download is a link with a download attribute, or one whose name ends in a common file extension: pdf, zip, rar, 7z, gz, dmg, exe, msi, pkg, apk, doc, docx, xls, xlsx, ppt, pptx, csv, txt, epub, mp3, wav, mp4, mov or webm. A link to the same site with or without www. is not outbound. Middle clicks count; the click itself is never delayed or stopped, and a click that leaves the page is sent as the page unloads.

Each event also carries the page it happened on, $path, like every event.

If you turn one on, say so where you describe what your site measures. For example:

  • Outbound links: "When you follow a link to another site, we record that site's name, not the address of the page."
  • Downloads: "When you download a file, we record the file's name."
  • Email and phone links: "When you tap an email or phone link, we record that you did, never the address or number."

Form submissions ​

From 0.7.0, formSubmissions: true sends form_submit each time a form on the page is submitted. It is off until you turn it on, because it is a kind of collection your own privacy wording should mention first.

OptionEventProperties
formSubmissionsform_submit$form: the form's id, or its name when it has no id, up to 64 characters; none when it has neither

It never reads a field, a value or the address the form is sent to. A form the browser refuses as invalid fires no submit, so it is not counted, and the submit is never stopped or delayed: one that leaves the page is sent as the page unloads. Give each form you want to tell apart an id, such as <form id="newsletter">, and make a goal of form_submit where $form is newsletter.

If you turn it on, say so where you describe what your site measures. For example: "When you send a form, we record which form it was, never what you typed."

client.track(name, props?) ​

Queues an event.

js
analytics.track("page_view", { path: location.pathname });

The name must match ^[a-z0-9_]{1,64}$. An invalid name is reported through onError and never enters the queue.

client.flush() ​

Sends everything queued. Always resolves, never rejects.

You rarely need it: the unload handlers cover leaving the page, and the queue sends itself at 50 events.

Single-page applications ​

A single-page app changes the address without loading a new document. From 0.5.0, init({ pageViews: "history" }) sends a page_view when it starts and each time the path changes, through history.pushState, history.replaceState or the back and forward buttons. Only a new path counts: a change to the query string or the hash alone is the same page, and a router replacing the starting address with itself, as most do on load, is not a second view. The script tag does this by default.

Without the option, track route changes yourself, or your page-view numbers count first loads only. See the install guide. With the option on, a page_view you send yourself for the page just counted is not sent again, so a site that already tracks its routes does not count each page twice.

Running more than one instance on a page ​

Supported. A tag manager and a hardcoded snippet can coexist, and each write key gets its own queue, so one product's events are never billed to another.

Storage that refuses to work ​

Safari's private browsing, a blocked third-party frame, and a site over quota all make browser storage throw — in some cases on the property access itself, before any read. The SDK falls back to an in-memory queue. Events still send during that visit; they do not survive a reload. Your page is never taken down by this script.

Sending as the page unloads ​

The final send uses the browser's keep-alive mechanism so it survives the page going away. Browsers cap those requests at 64 KB, so an unusually large queue omits the guarantee for that one send rather than failing: the events stay queued and go out on the next page load.

What the SDK guarantees ​

  • Nothing is lost to a reload. Events are persisted before any send.
  • Nothing is sent twice. Progress is recorded after every batch.
  • The queue is bounded at 500 events, dropping the oldest first.
  • Retries back off 30 seconds after a failure, so an offline visitor does not make one request per event.