Handle errors gracefully in production to prevent silent failures. When a call such as getResult() fails, the SDK throws a TracioError — an Error subclass with a machine-readable code field.
Wrap await tracio.getResult() in a try/catch and narrow the thrown value with isTracioError(), then branch on error.code:
import { Tracio, isTracioError, isRetryableError } from "@tracio/sdk"
const tracio = Tracio.init({ publicKey: "5ca175fc..." })
try { const result = await tracio.getResult() console.log(result.visitorId, result.bot.detected)} catch (error) { if (isTracioError(error)) { if (isRetryableError(error)) { // Transient failure (network, timeout, blocked script, upstream) — // a fresh attempt may succeed. console.warn(`Retryable TRACIO error: ${error.code}`) } else { // Terminal failure (bad config, misuse, destroyed instance) — // fix the caller; retrying the same call will not help. console.error(`Terminal TRACIO error: ${error.code} — ${error.message}`) } } else { console.error("Unexpected error:", error) }}The agent loads asynchronously in the background. If loading fails before you ever call getResult(), the failure is delivered through the onError callback. Register it right after init():
const tracio = Tracio.init({ publicKey: "5ca175fc..." })
tracio.onError((error) => { // Same TracioError instance you would catch from getResult(). console.warn(`TRACIO failed to initialize: ${error.code}`)})
tracio.onReady((result) => { console.log("Visitor identified:", result.visitorId)})The same error remains observable through getResult() — you can use either channel.
Every TracioError carries a code of type TracioErrorCode. The retryable getter (and the isRetryableError() helper) report whether a fresh attempt may succeed.
| Code | Meaning | Retryable |
|---|---|---|
invalid_config | The config passed to Tracio.init() is invalid | No |
multiple_keys | More than one public key was used on the same page | No |
non_browser | getResult() was awaited outside a browser (e.g. on the server) | No |
load_failed | The agent script failed to load | Yes |
blocked | The script was blocked (ad blocker or CSP) | Yes |
script_error | The loaded script threw while initializing | Yes |
network | Network/transport failure reaching the API | Yes |
timeout | The call exceeded the configured timeoutMs budget | Yes |
server | The edge/server returned an upstream failure | Yes |
destroyed | The instance was destroyed (via destroy()) before the call | No |
Terminal codes (invalid_config, multiple_keys, non_browser, destroyed) indicate a configuration, usage, or lifecycle problem — fix the caller or call Tracio.init() again. Retryable codes are transient and a fresh attempt may succeed.
For retryable errors, retry with backoff against a fresh attempt rather than re-awaiting the same rejected promise:
import { Tracio, isRetryableError } from "@tracio/sdk"
async function identifyWithRetry(maxAttempts = 3) { let attempt = 0 while (true) { const tracio = Tracio.init({ publicKey: "5ca175fc..." }) try { return await tracio.getResult() } catch (error) { attempt++ if (!isRetryableError(error) || attempt >= maxAttempts) throw error await new Promise((r) => setTimeout(r, 2 ** attempt * 250)) } }}