Embedding fp-token.js
Signup Protection compares the visit that obtained
a page token with the request that submits your form. fp-token.js obtains the
token through the separately served fp-probe.js file. Your page writes the
returned value into a hidden field. The served file owns the request, browser
assessment and optional WebTransport session, so Emvero can update them
independently of the small token wrapper in your bundle.
Replace the client code and page key with the values from your account:
<form method="post" action="/signup"> <input type="email" name="email"> <input type="hidden" name="fp_token"> <button>Create account</button></form>
<script src="/fp-token.js"></script><script src="https://probe.tlsatlas.com/fp-probe.js?client=your_client_code"></script><script> let visitToken; async function onSignupFormShown(vid) { const field = document.querySelector('input[name="fp_token"]'); if (typeof FpToken !== 'function') return ''; visitToken = new FpToken( 'https://fp.tlsatlas.com/_fp/token', 'fp_key_your_page_key', { quic: true }, ); const token = await visitToken.fetch(vid); field.value = token; return token; }</script>Call const tokenPromise = onSignupFormShown(vid) from your form-show handler,
after applicable consent. For a form visible from the start, use your page-ready
handler; for a dialog, wait until it opens. Script loading makes the library
available; it does not itself trigger initialization.
vid is an optional opaque identifier for this visit, supplied as a string or
a Promise. Do not pass an account or user ID, email address or phone number. The handler
returns a Promise<string> resolving to the token or ''. The library returns
the value; the handler assigns it to the hidden field. A missing wrapper or
missing/incompatible served probe leaves no token.
Keep the hidden field inside the form. Your server sends its current value as
token, alongside the submitted address and request details it observed.
A public page key cannot replace the secret API key used by that server call.
The versioned token script
Section titled “The versioned token script”| URL | https://docs.emvero.io/js/c535799/fp-token.js |
|---|---|
| Integrity | sha384-BscMW37DO5GnwOEP3UejPSWnRR+7WQ/KCgfpmYFEvVxWJWYgIcHgNnWIpHG+s+Yo |
| Size | 10,226 bytes |
| Revision | c53579916601, copied byte for byte from Emvero’s internal token-script source |
Each release has its own URL and its bytes stay unchanged. Older releases stay
available. Download this file, check its integrity and serve it from your own
origin as /fp-token.js, as the example above assumes:
curl -sSo fp-token.js https://docs.emvero.io/js/c535799/fp-token.jsecho "sha384-$(openssl dgst -sha384 -binary fp-token.js | base64)"Alternatively, load that version from the documentation host:
<script src="https://docs.emvero.io/js/c535799/fp-token.js" integrity="sha384-BscMW37DO5GnwOEP3UejPSWnRR+7WQ/KCgfpmYFEvVxWJWYgIcHgNnWIpHG+s+Yo" crossorigin="anonymous"></script>crossorigin="anonymous" is required for a browser to check the integrity of a
script loaded from another origin. Do not edit a pinned copy and retain its old
integrity value.
The current token script is also available at
https://probe.tlsatlas.com/fp-token.js. That URL follows service updates; use
the versioned file above when you need fixed bytes and an integrity value.
The constructor and browser probe
Section titled “The constructor and browser probe”new FpToken(endpoint, key, options)| Argument | Meaning |
|---|---|
endpoint |
The token endpoint shown in your account, such as https://fp.tlsatlas.com/_fp/token. |
key |
A public page key: fp_key_ and 43 more characters. It is accepted only on its configured origins. |
options |
Optional settings below. |
| Option | Effect |
|---|---|
{ timezone: false } |
Omits the browser’s time-zone statement; the related comparisons report themselves not evaluated. |
{ probe: false } |
Disables the browser probe and its WebTransport session, even if the probe script is loaded. |
{ quic: true } |
Opts into a WebTransport session through the probe. It is off by default and needs a compatible probe and a node that supports the session. |
{ preconnect: false } |
Disables connection prewarming when collection runs. |
Load fp-probe.js?client=… with your public client code. Do not substitute the
page key for that code. Its current interface is window.FpProbe with API
contract 3; FpToken.fetch() delegates to its token() method. The file is
required even with { probe: false }: that option skips browser assessment,
while the served file still performs the token request.
Keep the probe on its service URL so its build can update independently.
A missing or incompatible probe file leaves no token. Individual browser checks
can remain not evaluated while a usable token is obtained; in that case the
operation can remain evaluated and include fp_probe_not_evaluated.
Automation findings can require confirmation; property-tampering findings are
informational. See the signal-code reference.
Start when the form is shown
Section titled “Start when the form is shown”Create the FpToken instance and call fetch(vid) when the person can see the
form, after applicable consent. For a form visible from the start, initialize
when the page is ready; for a dialog, wait until it opens. Calling it only on submission can
produce fp_fast_submission.
The token script makes no request before fetch(). A remotely loaded script
tag still downloads its file before that call. If your consent flow must defer
those downloads too, insert the script tags only after consent.
The method’s contract is:
fetch(vid?: string | PromiseLike<string>): Promise<string>The return value is always a Promise. It resolves to the token string on success
or to '' if no token was obtained. Your page writes that value into its field.
The library does not stop the person filling or submitting
the form, and uses no cookies, localStorage or sessionStorage.
Refresh a token on a long form
Section titled “Refresh a token on a long form”A token lives for 15 minutes in the current profile. After the form-show handler
has created visitToken, schedule refreshes before expiry:
const field = document.querySelector('input[name="fp_token"]');const timer = setInterval(async () => { field.value = await visitToken.fetch();}, 10 * 60 * 1000);field.form.addEventListener('submit', () => clearInterval(timer));A repeated fetch() uses a live token kept by the served probe in page memory.
The node preserves the first issue time only if the previous token is usable,
the IPv4 address or IPv6 /64 is unchanged, the browser family, major version
and platform match, and the visit is no older than 24 hours. Otherwise the
timing starts again; a submission soon afterwards can produce the
fast-submission finding. Schedule the call before expiry and update the field
with its result.
An expired token can require confirmation; refresh after expiry cannot be relied
on to preserve an earlier visit interval. The wrapper has no timers of its own.
An optional visitor identifier
Section titled “An optional visitor identifier”If your application uses an opaque visit identifier, pass its string value or
a Promise to fetch(vid). Use a visit-scoped value with no embedded account or
user ID, email address or phone number. The raw value can enter the token
request query; it is not a field for customer identity. The served probe can collect while it resolves;
an unavailable or late identifier is omitted. A later fetch() keeps the
previous page identifier, fetch(vid) replaces it and fetch('') removes it.
Every call returns Promise<string>; no identifier is created by omitting it.
The script creates no visitor identifier. Emvero’s public checking API accepts
no vid field and does not compare the submitted request against that digest.
Passing an identifier does not provide cross-visit identity detection.
What leaves the browser
Section titled “What leaves the browser”With a compatible served file, fetch() initiates a cross-origin GET for a token,
with credentials: 'omit' and cache: 'no-store'. Its query can contain the
page key, browser time zone, previous token, customer-supplied vid, probe
result and WebTransport receipt. No custom headers or CORS preflight are used.
With { quic: true } and a compatible probe, collection also attempts a
WebTransport session. Its failure does not prevent the TCP token request.
Current opaque tokens use format v14; forward the value without decoding it.
The internal processing runs within Emvero’s EU infrastructure; the website’s
privacy policy explains data and retention.
Content-Security-Policy
Section titled “Content-Security-Policy”For the example with a locally served token script and remotely served probe:
Content-Security-Policy: default-src 'self'; script-src 'self' https://probe.tlsatlas.com 'wasm-unsafe-eval'; worker-src 'self' blob:; connect-src 'self' https://fp.tlsatlas.comThe probe needs its script host, 'wasm-unsafe-eval' for WebAssembly and
worker-src blob: for its Worker checks. The token endpoint belongs in
connect-src. Loading the pinned token script from this documentation host
also needs https://docs.emvero.io in script-src.
Put the initialization in your own script file, or authorize the inline block with a nonce or hash. A blocked probe script prevents token collection. Restrictions on individual Worker or WebAssembly checks can leave those comparisons incomplete; inspect the returned assessment limits. A WebTransport attempt uses the capture node’s origin.
Page keys and origins
Section titled “Page keys and origins”The account area accepts up to 20 origins per key and 20 live keys per account.
An origin can be an exact HTTPS origin, including a port, or a subdomain zone
such as https://*.example.com. Paths, queries, HTTP, a bare * and
https://*.com are refused. Hostnames are normalized to lowercase and IDN to
Punycode.
A revoked key cannot be restored. Key changes take effect after synchronization; a ready connection is separate from a working integration. Complete a real server check and read its result as described in Signup Protection.