Get started
Installation
One script tag is enough. It loads asynchronously, it never blocks rendering, and it cannot break the page it is installed on.
1. Create the website
Sign in and press Add a website. Give it a name, the domain that will send the events, and the timezone your calendar days are counted in. The website is created with a public tracking id, and the tracking script starts accepting events immediately.
The tracking id looks like abk_xxxxxxxxxxxxxxxx. It is public, it is safe to put in a page, and it is not the same thing as an API key.
2. Add the snippet
Paste this into the page, as high in the document as you can. The script is async, so it does not delay the rest of the page.
<script async src="https://abackanalytics.com/track.js" data-website-id="abk_xxxxxxxxxxxxxxxx"></script>Plain HTML
Put the script tag before the closing body tag of every page you want to measure. The same id is used everywhere, and the script only initialises once per page load.
<script async src="https://abackanalytics.com/track.js" data-website-id="abk_xxxxxxxxxxxxxxxx"></script>Next.js, App Router
Use the next/script component with the afterInteractive strategy in the root layout. The tracker is not needed for the server rendered HTML, so it is not worth blocking the first paint on it.
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://abackanalytics.com/track.js"
strategy="afterInteractive"
data-website-id="abk_xxxxxxxxxxxxxxxx"
/>
</body>
</html>
);
}React
Mount the script once, close to the root of the application. The component returns nothing and renders no markup.
import { useEffect } from "react";
const WEBSITE_ID = "abk_xxxxxxxxxxxxxxxx";
export function AbackAnalytics() {
useEffect(() => {
const existing = document.querySelector(`script[data-website-id]`);
if (existing) return;
const script = document.createElement("script");
script.async = true;
script.src = "https://abackanalytics.com/track.js";
script.setAttribute("data-website-id", WEBSITE_ID);
document.head.appendChild(script);
return () => {
script.remove();
};
}, []);
return null;
}Vite
Add the script to index.html. If the website id changes between environments, read it from the environment instead of writing it into the markup.
<script async src="https://abackanalytics.com/track.js" data-website-id="abk_xxxxxxxxxxxxxxxx"></script>const WEBSITE_ID = import.meta.env.VITE_ABACK_WEBSITE_ID;Single page applications
Route changes are recorded without any extra work. The script watches the history functions and the navigation events, so a client side route change produces a new pageview with the new path.
If you turn automatic pageviews off for the website, call the pageview function yourself after each route change:
window.aback.pageview();What the script records
With the snippet alone, the script records pageviews, clicks on links to other sites as outbound_click, clicks on links to files as file_download, how long each page stayed in the foreground and how far it was scrolled, and the Core Web Vitals of the page loaded from the network. It never reads a form field, the text of a link or anything typed. Each part can be turned off with an attribute on the script tag.
| Attribute | Default | Effect |
|---|---|---|
| data-auto-pageview | true | Record pageviews and route changes automatically. |
| data-track-outbound | true | Record clicks on links to other sites, by host and path. |
| data-track-downloads | true | Record clicks on links to files. |
| data-download-extensions | pdf,zip,dmg,… | The file extensions that count as a download, separated by commas. |
| data-track-engagement | true | Report foreground time and scroll depth. |
| data-track-vitals | true | Report LCP, INP, CLS, FCP and TTFB. |
| data-hash-routing | false | Count a route in the fragment, #/pricing, as a page. |
| data-cross-domain | none | Your other domains, separated by commas. Links between them keep the visitor. |
| data-respect-dnt | false | Send nothing when the browser sends Do Not Track. |
| data-debug | false | Log every event to the browser console. |
Goals without code
Add data-aback-goal to a button, a link or a form, and a click or a submit records the goal. Every data-aback-goal-* attribute becomes a property, with dashes turned into underscores. A form is never read: only the fact that it was submitted is recorded.
Add data-aback-visible to an element and the goal is recorded once per page when half of it is in view. The share can be set with data-aback-visible-threshold.
<button data-aback-goal="signup_click" data-aback-goal-plan="pro">Start free</button>
<form data-aback-goal="waitlist_joined">…</form>
<section data-aback-visible="pricing_seen" data-aback-visible-threshold="0.6">…</section>Calls before the script loads
The script loads asynchronously. To record an event before it has loaded, add this stub above the snippet. The calls are kept in order and sent once the script is ready.
<script>
window.aback = window.aback || function () { (window.aback.q = window.aback.q || []).push(arguments); };
</script>
<script>aback("track", "hero_viewed");</script>Identify signed-in users
When someone signs in, pass the id your own app uses for them. The visitor is linked to that user, so a payment that carries the same user id is attributed to their visits on every device. Use an opaque id, such as the primary key of your users table. A value that looks like an email address is refused.
Each browser still counts as one visitor. Identifying a user never merges the visitors in your reports.
window.aback.identify("usr_8f3k2");One site on several domains
If the site and its checkout or docs live on different domains, list the other domains on the snippet of every one of them. A link from one to another then carries the visitor in a parameter that expires after two minutes and is removed from the address as soon as the next page loads, and the move is not counted as a referral. Subdomains of a listed domain are included. Forms and server redirects are not followed.
<script async src="https://abackanalytics.com/track.js" data-website-id="abk_xxxxxxxxxxxxxxxx" data-cross-domain="example-shop.com"></script>3. Verify your domain
Optional, but recommended. Open the settings of the website and add the hostname that serves your site, for example example.com. Aback Analytics shows you a DNS record to publish. It looks like this:
Type TXT
Name _aback-analytics.example.com
Value aback-site=aback-site-the-value-you-are-givenOnce the record is published, press Check again. From that point on, events for the website are only accepted from the verified hostnames, so a copy of your tracking id on a site you do not control cannot write into your reports.
The record proves that you control the domain. It is not a secret and it grants no access to your account.
Do Not Track and opting out
The tracker ignores the Do Not Track signal by default. Turn the behaviour on for the website in its settings, or add the attribute to the snippet. When it is on and the browser sends the signal, the script does not send anything.
<script async src="https://abackanalytics.com/track.js" data-website-id="abk_xxxxxxxxxxxxxxxx" data-respect-dnt="true"></script>A visitor can opt out from the page. The opt out is stored in the browser of the site that installed the script and it removes the events that have not been sent yet.
window.aback.optOut();Confirm the install
Open the website in a normal browser window, move between two pages and send a test event from the console:
window.aback.track("test_event", { source: "console" });The test event and the pageviews appear in the report within a few minutes. If they do not, the troubleshooting page lists the things to check, in the order that finds the problem fastest.