Flowtag Docs

Tracking

What Flowtag records automatically, and how to capture your own events.

Once the tag is installed, Flowtag records six kinds of events. Five are automatic; the sixth is yours to send.

TypeRecorded whenConfiguration needed
pageviewA session starts, or the path changesNone
scrollThe visitor scrolls to a new depthNone
clickThe visitor clicks an elementNone
inputThe visitor types into a fieldNone
healthA JavaScript or resource error occursNone
eventYou call flowtag.capture()Yours

Every event is stored with its session, timestamp, and the path it happened on, so any event can be attributed to a page and a traffic source.

Pageviews

The first pageview is recorded during the handshake, at page load. After that, the tag reports the current path with each ping, and the server writes a new pageview whenever the path differs from the last one recorded.

This means single-page apps work without extra code. The tag patches history.pushState and history.replaceState and listens for popstate and hashchange, so client-side navigations are detected as they happen. On a route change, the tag flushes any queued events attributed to the old page, sets the previous path as the new page's referrer, re-reads UTM tags from the new URL, and immediately pings the new path rather than waiting for the next 6-second tick.

Pageviews are keyed on window.location.pathname. Query strings and hash fragments do not create separate pageviews, so /pricing?plan=pro and /pricing are the same page. Only the six attribution tags are read from the query string.

Scroll depth

Scrolling is sampled, not streamed. The tag debounces scroll events over a 1-second window and only reports a depth when it has moved by at least 2 percentage points, and the server additionally accepts at most one scroll event per session every 5 seconds.

Each scroll event carries the scroll percentage, the pixel offset, the viewport height, and the document height. Average scroll depth per page is shown in Page Discovery.

Clicks

Clicks are captured with aggressive throttling so that a rage-clicking visitor cannot flood your quota:

RuleLimit
Per unique element1 click per 5 seconds
Globally1 click per 2 seconds
Per page load50 clicks
Repeated clicks on the same element in a rowIgnored

Each click records the element's tag name, its id, its classes, and the cursor coordinates. If the click is on a link that navigates away, the tag flushes the queue immediately so the event is not lost to the page unload.

Inputs

Input events record that a field was filled, never what was typed. Each event carries the element's tag name, id, classes, name attribute, and input type — no value, ever.

Inputs are throttled like clicks (1 per element per 5 seconds, 1 globally per 2 seconds, 50 per page load) and are only recorded once at least 3 characters have been entered, which filters out stray keystrokes.

The name and id attributes you give your fields are stored as-is. Avoid putting personal data in them (id="[email protected]"), since that value will appear in your event catalog.

Health events

The tag installs three error listeners and reports what they catch as health events:

KindTriggerPayload
unhandled_rejectionA rejected promise with no handlerMessage and stack
window_onerrorAn uncaught JavaScript exceptionMessage and stack, or source:line:column
resource_errorA <script>, <link>, or <img> that failed to loadThe failing URL and element tag

These are useful for spotting a broken deploy in the same timeline as your traffic — a spike in health events next to a drop in conversions usually explains itself.

Custom events

Call capture() with an event name and an optional flat object of properties:

flowtag.capture("signup_completed", { plan: "pro", trial: false });
flowtag.capture("button_clicked");

From plain HTML the API is on window:

<script>
  window.flowtag.capture("checkout_started", { cart_value: 49 });
</script>

In a React or Next.js app, import the typed client instead — see @flowtag/next.

Rules and limits

  • The event name must be a non-empty string, and the payload must be a plain object (not an array).
  • Events sent before the handshake completes are rejected. If you capture on page load, do it after the first paint or in an effect, not in a top-level module body.
  • The tag throttles each event name to once per second, and the server accepts at most one event per session every 3 seconds.
  • Property values are stored for filtering in the Event Browser. Values longer than 256 characters are truncated, and Flowtag keeps at most 500 distinct values per property — once that ceiling is hit, further values are grouped as (other).

Design event names as a small, closed set (signup_completed, not signup_completed_pro_annual_2026). Put the varying parts in properties. This keeps the catalog readable and keeps you under the distinct-value ceiling.

UTM tags and attribution

Six query parameters are read from the landing URL and stored on the session:

utm_source, utm_medium, utm_campaign, utm_term, utm_content, ref

They are re-read on client-side route changes, so a UTM-tagged link into a single-page app is attributed correctly. Any other query parameter is ignored.

The session's referrer is recorded alongside them:

ValueMeaning
A URLThe external page the visitor came from
<direct>No referrer — typed URL, bookmark, or a stripped referrer
<self>The referrer was the same page

How these feed the Referred and Organic metrics is covered in Metrics.

Controlling the tag at runtime

window.flowtag exposes the same API the SDK wraps:

MethodPurpose
capture(name, data?)Send a custom event.
consentCookies(allowed?)Grant or revoke cookie consent. Called with no argument, it grants.
getConsent()Read the current consent state.
init()Start tracking manually when data-auto-init="false".
stop()Stop tracking for the rest of this page load.
doNotTrackMe()Toggle a persistent opt-out for this browser, stored in localStorage.
getConfig(key?) / setConfig(key, value)Read or change debug, gtagsync, trackerId, or baseUrl at runtime.

doNotTrackMe() is the one to hand to your own team: call it once from the console on a site you're developing and that browser stops sending data permanently, until you call it again.

Debugging

Set data-debug="true" on the script tag (or run flowtag.setConfig("debug", true)) to log the tracker ID, visitor ID, current path, referrer, consent state, and captured tags to the console every 10 seconds, plus a line for every queued event and every envelope sent.

The tag also warns in the console when it detects localhost, so you'll notice before test traffic lands in your production reports.

Next steps

On this page