Engagement beacon

The wc.js landing-page script — what it collects, how it sends, privacy properties and manual integration.

Updated 2026-09-02

Install#

HTML
<script async src="https://app.whichclick.is/wc.js" data-endpoint="https://app.whichclick.is/api/protect/beacon"></script>

The script reads wc_click_id from the URL, waits for interaction, and sends one beacon (via navigator.sendBeacon, falling back to fetch with keepalive) when the page is hidden or after 15 s.

Payload#

JSON
{ "click_id": "k3Zp9Qw1mR7tXc2b", "fingerprint": "5f2a…", "screen": "390x844", "timezone": "Europe/Istanbul", "languages": "tr-TR,en", "webdriver": false, "touch": true, "dwell_ms": 8200, "scroll": 62 }
FieldUsed for
fingerprintHash of canvas / fonts / UA data — reuse across many IPs indicates a farm
screen, timezone, languagesConsistency with ValueTrack device, IP geo and Accept-Language
webdriver, touchAutomation detection
dwell_ms, scrollEngagement; zero engagement plus other signals raises the score

A click that never receives a beacon after 30 s gets a small "no engagement" weight (landing pages without the script are configurable to skip this).

Privacy#

  • No cookies, no persistent identifiers, no PII. The fingerprint is a salted hash that cannot be reversed to device characteristics.
  • The beacon is sent with Content-Type: text/plain to avoid a CORS preflight; the endpoint accepts JSON or text.
  • Under GDPR / ePrivacy the beacon is a strictly necessary fraud-prevention measure; document it in your privacy notice. If your CMP blocks it before consent, protection still works from server-side signals.

Manual integration#

JavaScript
navigator.sendBeacon("https://app.whichclick.is/api/protect/beacon", JSON.stringify({ click_id, dwell_ms: 5000, scroll: 40 }));

Responses: 200 {"ok":true}, 404 for an unknown click id (beacons for clicks older than 24 h are dropped).