SDK Log Reference
Every line the LinkTrail iOS and Android SDKs log, with its level and when it prints: install, consent, deferred and re-engagement links, events and state.
Both native SDKs print the same lines, at the same level, for the same step, and the React Native and Flutter wrappers print them too, because they call the native SDKs. Every line reads [LinkTrail] [LEVEL] <message>, with LEVEL DEBUG, INFO, WARNING or ERROR. Lines print only when logEnabled is on and the level is at or above logLevel. <...> marks a value filled in at runtime, and <error> is the platform's error description.
Turn them on with iOS LinkTrailOptions(logEnabled: true, logLevel: .debug) and read the Xcode console, or Android LinkTrailOptions(logEnabled = true) and run adb logcat -s LinkTrail. React Native and Flutter: pass logEnabled and logLevel in the options you give configure.
A first launch that works
[LinkTrail] [INFO] Configured — base URL: https://backend.linktrail.io
[LinkTrail] [INFO] Install held — awaiting consent decision
[LinkTrail] [INFO] Consent granted
[LinkTrail] [INFO] Sending install event… (consent: true)
[LinkTrail] [INFO] Install attributed (deterministic click token)
[LinkTrail] [INFO] Deferred link routed → path: /promo/summerInstead of Install attributed (deterministic click token) you may see Install attributed or Organic install (no attribution match). The last line prints only when there is a link to route.
Shared lines (iOS and Android)
| Step | Level | Message |
|---|---|---|
| Configured (first call) | INFO | Configured — base URL: <baseURL> |
| Already configured (same key and options; the instance is reused) | DEBUG | Already configured — reusing the existing instance |
| Reconfigured (different key or options; the old instance is shut down first) | WARNING | Reconfigured — previous instance shut down (base URL: <baseURL>) |
linkDomains entry empty or invalid, ignored (at configure) | WARNING | linkDomains entry "<value>" is not a valid host; ignored |
linkDomains entry with a single label, kept (at configure) | WARNING | linkDomains entry "<value>" is a single label and will match every host under it |
| Install held (consent not decided yet) | INFO | Install held — awaiting consent decision |
| Consent granted | INFO | Consent granted |
| Consent denied | INFO | Consent denied — sending the install with consent: false |
| Sending install | INFO | Sending install event… (consent: <true|false>) |
| Attributed, deterministic click token | INFO | Install attributed (deterministic click token) |
| Attributed | INFO | Install attributed |
| Organic | INFO | Organic install (no attribution match) |
| Install not counted (denied), link to route | INFO | Install not counted (no consent) — routing the deferred link only |
| Install not counted (denied), nothing to route | INFO | Install not counted (no consent) — no deferred link to route |
| Deferred link routed | INFO | Deferred link routed → path: <path> |
Deferred link saved (no onLink yet) | DEBUG | Deferred link saved until onLink is set → <path> |
Saved deferred link delivered to a late onLink | DEBUG | Delivering saved deferred link → <path> |
| Saved deferred link expired (older than 7 days) | DEBUG | Saved deferred link expired — dropped |
| Saved deferred link unreadable (dropped) | WARNING | Saved deferred link unreadable — dropped: <error> |
| Install already sent | INFO | Install already tracked — skipping network call |
| Denied install already sent | INFO | Denied install already sent — skipping network call |
| Install failed | ERROR | Install tracking failed: <error> |
| Not a LinkTrail link | DEBUG | Not a LinkTrail link — ignoring: <url> |
| Handling a re-engagement link | DEBUG | Handling deep link: <url> |
| Re-engagement resolved (no consent) | INFO | Re-engagement resolved route-only — consent not granted (not recorded) |
| Re-engagement resolve failed (no consent) | WARNING | Re-engagement resolve failed (no consent) — routing by URL only: <error> |
| Re-engagement open failed (consent) | WARNING | Deep-link open failed — delivering a URL-only link (campaign/customData will be empty): <error> |
| Re-engagement link delivered | DEBUG | Deep link resolved → path: <path> |
| Deep link handling failed | ERROR | Deep link handling failed: <error> |
| Event dropped (no consent) | INFO | Event '<name>' dropped — consent not granted |
| Event failed, queued | WARNING | Event '<name>' failed; queued for retry: <error> |
| Event rejected (non-retryable status), dropped | WARNING | Event '<name>' rejected (<status>) — not retried |
| Corrupt queued event skipped (the rest are kept) | WARNING | Skipped a corrupt queued event: <error> |
| Offline queue flush | DEBUG | Flushing <n> queued event(s) |
| Queued event still failing | DEBUG | Queued event <name> still failing |
| HTTP retry | DEBUG | Retrying <path> after <seconds>s (status <code>, attempt <n>) |
| Transport retry | DEBUG | Transport error, retrying (attempt <n>) |
| SDK state moved to device-only storage (first launch after the upgrade) | DEBUG | Moved SDK state to device-only storage (<n> keys) |
| SDK state unreadable (starts fresh) | WARNING | SDK state unreadable — starting fresh: <error> |
| SDK state write failed (retried on the next change) | WARNING | SDK state write failed: <error> |
| SDK state can't be read yet; install held, nothing overwritten | DEBUG | SDK state not readable yet — waiting: <error> |
<url> in "Not a LinkTrail link" and "Handling deep link" is the link's scheme, host and path only. The query string, fragment, user-info and port are never logged, so OAuth codes and magic-link tokens stay out of the log. "Not a LinkTrail link" prints for any URL the SDK doesn't claim — see Which links the SDK claims.
Only retryable event failures are queued: transport errors, 408, 429 and 5xx. Any other status goes to onError and is dropped with the "rejected" line, where <status> is the HTTP status (401 for a rejected API key). A queued entry that gets one on a later flush is dropped with the same line, but no onError. More on Tracking Events.
iOS only
| Step | Level | Message |
|---|---|---|
Click token read (paste button or .automatic) | DEBUG | Deferred click token read; pasteboard cleared |
Pasted token ignored (clickTokenSource is .none) | INFO | clickTokenSource is .none — ignoring the pasted token; install stays probabilistic |
Paste button tapped after a denial (default grantsConsent) | INFO | Paste tapped after a denial — consent stays denied (pass grantsConsent: true to override) |
| SKAdNetwork, iOS 16.1+ | DEBUG | SKAdNetwork: AdAttributionKit available (iOS 16.1+); no explicit registration required |
| SKAdNetwork registered, iOS 15.4+ | INFO | SKAdNetwork: registered with conversion value 0 |
| SKAdNetwork registered, older | INFO | SKAdNetwork: registered for ad network attribution |
| SKAdNetwork value updated (iOS 16.1+ appends the coarse value) | INFO | SKAdNetwork: updated conversion value <value> |
| SKAdNetwork error | ERROR | SKAdNetwork: <error> |
| ATT not authorized | INFO | ATT: not authorized |
LinkTrail.resetForTesting() (printed whatever logEnabled says) | INFO | Reset for testing — next launch will send a fresh install event |
Call on an instance replaced by a later configure (ignored) | DEBUG | Instance shut down — ignoring call |
retryPolicy.maxAttempts below 1, clamped | WARNING | retryPolicy.maxAttempts <value> is below 1; using 1 |
retryPolicy.baseDelay not positive, defaulted | WARNING | retryPolicy.baseDelay <value> is not a positive number; using <default>s |
retryPolicy.maxDelay not positive, defaulted | WARNING | retryPolicy.maxDelay <value> is not a positive number; using <default>s |
retryPolicy.maxDelay below the base delay, raised | WARNING | retryPolicy.maxDelay <max> is below baseDelay <base>; using <base>s |
requestTimeout not positive, defaulted | WARNING | requestTimeout <value> is not a positive number; using <default>s |
The option-clamp warnings print only when configure creates an instance (the first call or a reconfigure), never on a repeat call that reuses it. On iOS 16.1+ the SKAdNetwork update line also carries the coarse value: SKAdNetwork: updated conversion value <value> (<coarse>).
Android only
| Step | Level | Message |
|---|---|---|
| Consent changed while the install was in flight | INFO | Consent changed during the install — re-evaluating |
| Play Install Referrer unavailable | INFO | Play install referrer unavailable — not a Play install, or lookup timed out |
Play Install Referrer read (lt_click value redacted) | DEBUG | Play install referrer: "<referrer>" |
No lt_click token in the referrer | INFO | No lt_click token in referrer — organic install, no deterministic match |
lt_click token found (first 4 characters and length only) | DEBUG | Install referrer lt_click token: <first 4>… (<n> chars) |
| Install referrer connection failed | DEBUG | Install referrer failed to connect: <error> |
| App Set ID unavailable | DEBUG | App Set ID unavailable: <error> |
| App Set ID error | DEBUG | App Set ID error: <error> |
Call on an instance replaced by a later configure (ignored) | WARNING | <call> ignored — this instance was replaced by a later configure; use LinkTrail.shared |
Debug referrer override in use (debuggable app only; lt_click value redacted) | WARNING | Using debug referrer override "<referrer>" (debug build only; from <source>) |
requestTimeoutMillis not positive, clamped | WARNING | requestTimeoutMillis (<value>) <= 0; using <default> |
retryPolicy.maxAttempts below 1, clamped | WARNING | retryPolicy.maxAttempts (<value>) < 1; using 1 |
retryPolicy.baseDelayMillis not positive, clamped | WARNING | retryPolicy.baseDelayMillis (<value>) <= 0; using <default> |
retryPolicy.maxDelayMillis not positive, clamped | WARNING | retryPolicy.maxDelayMillis (<value>) <= 0; using <default> |
retryPolicy.maxDelayMillis below the base delay, raised | WARNING | retryPolicy.maxDelayMillis (<max>) < baseDelayMillis (<base>); using <base> |
| Old SDK state from a backup discarded (fresh install or restore) | DEBUG | Discarded SDK state restored from a backup |
On Android, "Install attributed (deterministic click token)" prints when the Play Install Referrer carried an lt_click token. The referrer line prints at DEBUG with the lt_click value replaced by <redacted>, and the token line shows only its first 4 characters and length. The debug referrer override line redacts the value the same way.