Skip to content
Live in production, in shadow mode: FingerTrackID recommends, your system decides.Status →

Troubleshooting

Start from the symptom you see. Each section names the likely causes, how to tell them apart and the fix, and links to the page that holds the full rule. FingerTrackID never blocks your product: while you fix any of these, your login and every other business action keep their normal path (integration guidance).

In the console, open Integração e saúde (Integration and health) for the application (the screen). It covers the last 24 recorded hours; its numbers are not live.

  • Última coleta (last collection) shows a recent time instead of nenhuma coleta na janela (no collection in the window). No collection at all points to the browser side: see the Web SDK collects nothing.
  • In Da coleta à avaliação (from collection to assessment), Coletas aceitas (accepted collections) grows with your logins and Correlacionadas (assessments that found their browser collection) stays close to Avaliações (assessments). Collections without correlated assessments point to the hand-off from the browser to your backend: see assessments arrive without browser evidence.
  • The health Sem dados do SDK (no SDK data) means assessments arrived in the window and none carried the SDK’s context, so none received a score.
  • Credenciais de servidor (server credentials) shows each credential’s key_id and state, Origens das páginas (page origins) the website origins the SDK may collect from, and Limite de requisições (request limit) the rate in force.

For a single access, open it in Acessos (accesses): with browser evidence, Cobertura de evidência (evidence coverage) is above zero, the Automação (robô) indicator shows Detectado or Não detectado instead of Não avaliado, and the limitations do not include Coletor não carregado (collector not loaded). The full list of checks is in check that SDK evidence arrives.

Every SDK call that fails returns UNAVAILABLE with a reason (or, with the helper, a failure with its stage and reason); initializeSdk() and createEvent() throw instead. Log them: the reason tells most causes apart (failure reasons).

What you see Likely cause Fix
No request reaches your collection domain, and the setup in Início is not done The collection domain is not active yet. Without an active collection domain the SDK is not enabled for your application, and publishing DNS alone does not activate it Follow the step Confirmar o domínio de coleta until it shows Concluído, and Configurar a coleta web until Concluída (collection domain)
The step waits on Depende de você, or a record shows Ainda não encontrado A DNS record is missing, has another name, answers with more than one value, or sits behind a proxy; or your CAA policy does not allow the certificate Publish the three records exactly as shown, DNS only, with nothing in front; allow pki.goog and letsencrypt.org in CAA; then choose Verificar agora (the records, how to check)
An automatic step shows Algo travou A platform step did not move for 30 minutes Contact support with the request reference shown in Início
TRANSPORT_ERROR on a page whose origin is not listed in Origens das páginas The page origin is not one of the application’s allowed origins: the collection domain answers 403 origin-not-allowed without CORS approval, so the browser hides that answer Add the exact HTTPS origin in Integração e saúde › Origens das páginas (up to 10, all under the collection domain; the change takes effect at once)
TRANSPORT_ERROR, and the browser console reports a CSP violation Your connect-src does not list the exact collection origin Add it to connect-src; the SDK needs no script-src entry (your site’s CSP)
TRANSPORT_ERROR, and the OPTIONS request to the collection domain answers 400 Page instrumentation adds tracing headers to the SDK’s requests Keep the collection origin out of trace propagation (tracing headers)
TRANSPORT_ERROR only for some visitors A blocking browser extension, or the network Nothing to change in your setup: continue with a null context, and the assessment of that access is inconclusive
AUTHENTICATION_FAILED on an allowed origin The publicKey is not this application’s (pub_app_…), or the SDK version is not the one your application’s collection is set up for Use the public key issued in the dash; install the version the dash offers, and contact support before changing it (upgrading the SDK)
INVALID_RESPONSE A proxy, CDN or WAF in front of the collection domain altered the response Keep the collection CNAME DNS-only
TRANSPORT_ERROR or INVALID_RESPONSE right at the session open, after a build change A minifier option that breaks the SDK, such as compress.unsafe_math (measured on SDK 0.2.0) Exclude the SDK package from that minification or turn the option off (installation)
RATE_LIMITED For example, too many new sessions, or more than 1000 live sessions for the application Prepare only on the first intent of an assessed form, never at page load, and call close() when done (session limits)
initializeSdk() throws INVALID_CONFIGURATION Its configuration is not exactly publicKey and collectionOrigin, an HTTPS origin with no path Fix the two keys (initializeSdk)
initializeSdk() throws UNSUPPORTED_RUNTIME The page is not HTTPS, or the browser lacks Fetch, cryptographic randomness or a monotonic clock Continue with a null context

The SDK is delivered only as the private package bundled into your frontend. FingerTrackID serves no SDK script, so a page that loads it from a URL or a public CDN collects nothing.

Assessments arrive without browser evidence

Section titled “Assessments arrive without browser evidence”

The response is INCONCLUSIVE with trust_score: null, recommendation_basis INSUFFICIENT_EVIDENCE and the fallback MONITOR; all 13 indicators are NOT_EVALUATED with COLLECTOR_NOT_LOADED, and device_intelligence_snapshot_id and sdk_version are null. Under the current managed production profile, an assessment stored without an event_context_token is always like this (when the browser has no event context).

  • Your backend sends null. The browser sends the token and its expiresAt with the business request it already makes; your backend copies the token into event_context_token. Check that the field is forwarded, and that most logins in your backend logs carry a token. A login without one must have a logged reason, such as WAIT_EXCEEDED on a slow network, not one fixed code on every login.
  • The browser had no token. The SDK failed (see above), or the context was taken too late: a submit with nothing prepared needs at least three round trips before a token exists. Call prefetch() on the first focus or pointer-down of the form (the lifecycle).
  • Logins through a redirect (social or OAuth providers) lose the context unless it is taken before the redirect or collected after the callback (login redirects).
  • The client was closed too early. Calling close() before your backend has answered terminates the session that issued the token, and a token whose assessment is not stored yet stops working.
  • The API answers 400 event-context-invalid. The token expired, was already used, or is from another scope (for example, collected for another application). Nothing is stored. Do not retry the same body: assess the event once more as a new operation with event_context_token: null (event-context-invalid).

A token is single-use, one per business event, and the assessment that carries it must be stored before its expiresAt. The evidence window is 60 or 300 seconds from when the collection reaches FingerTrackID, depending on your application; every response shows it in data_freshness.maximum_required_age_ms (the evidence window). If event-context-invalid is frequent, collect closer to the action.

The type tells three cases apart. timestamp-out-of-window and request-replayed only answer a request whose signature was verified for a known credential: if you see them, your signature is right.

The uniform failure, not retryable: the response never says which part was wrong. Treat it as a configuration error and check, in order:

  1. The secret. The key is the decoded bytes of the secret, decodeSecret(text, 'hex'), never the hexadecimal text. Use the secret delivered with that key_id: after Trocar segredo the new credential has a new key_id, and the previous one is revoked at the end of an overlap of at most 24 hours.
  2. The bytes. The body hash covers the exact bytes you send. Build the body with a single JSON.stringify call and send those bytes; re-serializing after signing gives 401.
  3. The canonical string. Exactly ten lines separated by LF, without a trailing LF, the ninth empty; the path is literally /v1/assessments (the canonical string).
  4. The headers. X-FTID-Signature: v1=<key_id>:<mac>, one signature, with a lowercase 64-character MAC; key_id and request_id are lowercase UUIDv7. X-Client-Id, X-Signature, X-Timestamp and X-Nonce are refused with 401.
  5. The credential’s state. In Integração e saúde › Credenciais de servidor, the credential must be active, not revoked or suspended. A credential still waiting for secure installation is not usable. A client that kept retrying 429 without waiting is blocked for at least 10 minutes, during which every request gets 401.

Run the reference self-check on the Node.js that runs your backend: node ftid-hmac-v1-self-check.mjs must print OK and the test vector’s MAC. If it does, the signer works, and the cause is the secret, the key_id or the bytes you send (reference signer).

Retryable. X-FTID-Timestamp is the second at which you sign the attempt, not the event’s occurred_at, and it must be within ±300 s of the server clock. Synchronize your backend clock (NTP), then send a new attempt. An occurred_at out of ±300 s is a different error, 400 occurred-at-out-of-window.

Retryable. A request_id was reused. It is the anti-replay nonce: generate a new one for every attempt, including after 401, 403, 429 or 503, with crypto.randomUUIDv7(), never crypto.randomUUID(), which makes version 4. Then fix the generator that repeated it.

You are authenticated, but the credential lacks the route’s capability. A credential’s capabilities are frozen in its version, so you cannot add one to it: create a server credential with that permission in the console. The feedback routes need action:write and outcome:write (forbidden).

Your server client is above its rate: 5 requests per second with a burst of 10 on the standard tier (limits). Wait for Retry-After (whole seconds, today 1), then send a new attempt with the same body, a new request_id, the current timestamp and a new signature. Reusing the old request_id gives 401 request-replayed, and retrying without waiting exhausts the security budget and blocks the credential for at least 10 minutes.

To raise the rate, open Integração e saúde › Limite de requisições and choose Pedir aumento de limite, as Administrador da empresa or Gestor de integração; the console offers up to 10 per second, approved at once. For more, contact support at contato@fingertrackid.com. Momentary saturation of the service is 503 assessment-unavailable instead, retried the same way.

INCONCLUSIVE is a statement about the evidence, not about the person: no limitation code is a reason against the access.

  • Without a context every assessment is INCONCLUSIVE (above).
  • With a context, the assessment is COMPLETED only when at least 30% of the 13 indicators were evaluated with fresh evidence (evidence_coverage ≥ 30) and both indicators that count toward the score, BOT_AUTOMATION and BROWSER_SPOOFING, were evaluated.
  • Your company’s active rules make every indicator you activate required: an active indicator without usable fresh evidence leaves the assessment without a score (trust_score: null, MONITOR), even above 30% coverage (risk rules).

Read each indicator’s not_evaluated_reason_code to see what was missing (limitation codes). For example:

  • STALE_DEVICE_PROFILE: the browser evidence was older than your application’s evidence window (collect closer to the action), or a server-side evidence source was older than its maximum age, which recollecting does not fix.
  • UNSUPPORTED_RUNTIME on the browser privacy and private browsing indicators: the SDK ran inside an iframe or an in-app browser, or the browser engine could not be identified consistently.
  • REQUIRED_EVIDENCE_MISSING on DEVICE_MULTI_USER: expected on the first login of a new browser installation; later logins evaluate it.

Outbound assessment webhooks are not enabled (production status): there is no webhook to configure or debug. Your backend receives each assessment only in the response to its POST /v1/assessments.

Keep and send operation IDs, request_id, correlation_id (the X-Correlation-Id header of every response), the assessment_id, public error codes, timestamps and versions. Never send tokens, secrets, cookies, raw headers, personal data or full payloads.