Pageview tracking

The beacon reference — modes, data-fs attributes, and the observation shape

The beacon is a single JavaScript file served at https://api.formshield.dev/js/formshield.js. Drop it on a page with a <script> tag and it auto-initializes from data-fs-* attributes — no extra code. This page is the full reference for those attributes, the three modes, and the observation a hit produces.

The beacon runs only where JavaScript runs, so it never sees pure crawlers. To capture AI agents and bots that fetch HTML without running scripts, pair it with server reporting.

Minimal embed

html
<script
  async
  src="https://api.formshield.dev/js/formshield.js"
  data-fs-project-key="fs_pub_live_…"
  data-fs-action="pageview"
  data-fs-mode="pageload"
></script>

data-fs-project-key is the only required attribute. Everything else has a default.

Modes

data-fs-mode selects what the beacon does on load. The default is auto.

ModePageview on loadForm handlingUse when
pageloadYes — one scored page.viewNoYou only want pageview analytics.
formsNoYes — attaches to formsYou only want to score form submissions.
auto (default)YesYesYou want both from one tag.

pageload

Records exactly one scored pageview on window load and does nothing else. This is the recommended mode for traffic analytics.

forms

Attaches to forms matching data-fs-form-selector (default form). On submit, the beacon collects signals and injects them as a hidden field named _fs_signals (configurable via data-fs-field). Your backend forwards that field’s JSON to the FormShield check API, which scores the submission.

auto

Both behaviors: records one pageview on load and attaches to forms. This is the default when data-fs-mode is absent or unrecognized.

Attributes

data-fs-project-key string path required

Your publishable key, fs_pub_live_…. Safe to expose in the browser. Create one in the project’s Settings.

data-fs-mode string path default: auto

pageload, forms, or auto. Unknown or absent values fall back to auto.

data-fs-action string path default: pageview

A label for the hit, stored on the observation — for example pageview, signup, or contact. The pageload path defaults to pageview. A per-<form> data-fs-action overrides this global default for that form.

data-fs-form-selector string path default: form

CSS selector for the forms the beacon attaches to in forms and auto modes.

data-fs-field string path default: _fs_signals

Name of the hidden input the beacon injects with the signals payload on form submit.

data-fs-init-url string path

Advanced. Override the handshake endpoint. Defaults to /v1/handshake derived from the script’s origin.

data-fs-collect-url string path

Advanced. Override the collect endpoint. Defaults to /v1/collect derived from the script’s origin.

data-fs-probe-url string path

Advanced. Override the client probe endpoint. Defaults are derived from the script’s origin.

What the beacon collects

On a pageview the beacon gathers signals that distinguish a real browser from automation, then sends them to FormShield, which scores the hit and stores the result. The signals include:

  • Browser fingerprint and automation tells — webdriver, headless, and other automation markers.
  • A signed handshake token — proves the beacon actually ran in a real browser. Its absence or failure is a strong bot tell on the client path.
  • User-agent classification — browser, OS, device, and whether the UA is a named bot.

FormShield combines these with server-side IP reputation (VPN, proxy, datacenter, scanner, country, ASN) to produce the final score. The beacon does not collect form field contents on a pageview.

The observation

Each hit becomes one observation. A clean human pageview:

json
{
  "score": 0.09,
  "decision": "allow",
  "reasons": [],
  "action": "pageview",
  "ua": {
    "browser": "Chrome",
    "os": "macOS",
    "device": "desktop",
    "bot_kind": null,
    "bot_name": null
  }
}

An automated visit (webdriver) crosses the block threshold:

json
{
  "score": 0.93,
  "decision": "block",
  "reasons": ["automation_detected", "ua_bot"],
  "action": "pageview",
  "ua": {
    "browser": "Chrome",
    "os": "Linux",
    "device": "desktop",
    "bot_kind": "automation",
    "bot_name": null
  }
}

Fields

FieldTypeMeaning
scorefloat 0.01.0Risk probability. Higher is more bot-like.
decisionallow | review | blockallow below 0.45, review from 0.45, block from 0.8.
reasonsstring arrayRules that fired (see below).
actionstringThe data-fs-action label.
uaobjectUser-agent classification: browser, os, device, bot_kind, bot_name.
bot_idstring | nullThe identified bot’s stable id, e.g. googlebot, gptbot. null when no bot matched.
bot_operatorstring | nullThe bot’s operating company, e.g. Google, OpenAI.
bot_verifiedtrue | false | nulltrue = IP-verified; false = spoofed (UA claims a bot from the wrong IP); null = unverifiable. See bot detection.

Common reasons

ReasonMeaning
automation_detectedA webdriver or headless automation tell was present.
ua_botThe user agent classified as a bot.
bot:ai_crawlerA declared AI agent (GPTBot, ClaudeBot, PerplexityBot, Bytespider).
bot:search_crawlerA search crawler (Googlebot, Bingbot).
bot:id:<id>A bot was identified from the registry, e.g. bot:id:googlebot.
bot:verifiedThe bot is IP-verified — its user agent and IP both check out.
bot:spoofed:<id>The user agent claims a bot, but the IP is out of the operator’s published ranges.
client_token_missingThe signed handshake token was absent — the beacon could not confirm a real browser ran.
ip_datacenterThe IP belongs to a hosting or datacenter range.
ip_vpn / ip_proxyThe IP is an anonymizing VPN or proxy.
ip_scannerThe IP is a known scanner or abuse source.

Bot detection

FormShield names the bot behind each hit and, for operators that publish their IP ranges (Google, Microsoft, OpenAI, DuckDuckGo), verifies that the request really came from them. A forged crawler — a user agent claiming to be Googlebot from an unrelated IP — is flagged as spoofed and scored high. You can also allow or block bots per project from the dashboard. See bot detection for the full reference and the allow/block controls.

Where to view observations

Open the project’s Logs in the dashboard. Each observation shows its score, decision, reasons, IP profile, and user-agent classification. Filter by decision, action, or IP, and click any IP to see its full profile across observations.

Single-page apps

In an SPA the beacon records a pageview on the initial document load. Route changes that do not reload the document are not yet tracked as separate pageviews — that is a follow-up. See the React and TanStack Start guides for SPA-specific placement.

Next steps

Type to search…

↑↓ navigate open esc close