SDK documentation

Stream logs, crashes and user feedback to your LogWatcher server. Six SDKs, one API, one wire protocol — pick your platform:

Getting started

You need an application key. Create an account, add an app in the dashboard, and copy the key shown on its card. Every SDK call is tied to that key. Then follow your platform's guide above — the flow is always the same three steps: point the SDK at your server (before init), initialize with the app key, log.

How delivery works

Every SDK implements the same delivery model: log lines are written to a local, wire-ready queue first (SQLite, JSONL file, localStorage or memory depending on the platform), then uploaded in batches — every 5 minutes, or immediately when the queue reaches 200 rows / 64 KiB, in chunks of at most 1000 rows grouped by session. Entries are deleted only after the server acknowledges (at-least-once delivery), the queue is capped at 5 MiB with oldest-first eviction, and platforms with a persistent queue drain leftovers on the next launch — which is what delivers the breadcrumbs leading up to a crash. Android, Flutter and Go gzip large batches.

Remote device control

On every launch the SDK registers the device and receives its remote flags. From the dashboard you can enable log collection for a single device (a misbehaving terminal) while the rest of the fleet stays quiet — no release, no restart loop. To force collection locally regardless of the remote flag:

// same pair on every platform (Go: SetForceEnabled / ForceSendOnce)
LogWatcher.setForceEnabled(true)   // override the remote toggle
LogWatcher.forceSendOnce()          // flush the queue right now

Encrypted applications

An application can be created as encrypted: tick Encrypt this application's content when you create it in the dashboard. Its content is then ciphered on the device with a 16-character shared key that only you hold. LogWatcher stores ciphertext and never receives the key; the dashboard deciphers in your browser when you paste it. It is optional, and it is decided once — an application cannot be switched to or from encrypted later.

Ciphered on the deviceStill readable by the server
Log messages with their tag, method, file, line and thread; titles and texts of issues, crashes and feedback; the values of device key-values. The time and level of each line, the names of key-values, and device and session data — so counts, statistics and device lists work without the key.

The dashboard shows the shared key once, when the application is created (XXXX-XXXX-XXXX-XXXX). Store it where your team keeps secrets: LogWatcher cannot show it again, reset it or rotate it, and without it nobody can read the application's content. Give the same key to the SDK and to everyone who reads the application in the dashboard.

// Android — before init(), like setApiUrl
LogWatcher.setEncryptionKey("K7Q2-M9XH-4TBD-W3NP")
LogWatcher.init(this, "YOUR_APP_KEY", true)

An SDK that was given a key uploads sealed content or nothing: with a wrong key, or a key set for an application that is not encrypted, everything stays in the local queue and one error in the device log says why. In the dashboard, an encrypted application shows a lock; paste the key in the bar above Logs, Crashes or Issues to read and search. Text search then runs in your browser, and Report rules that read log content are not available.

SDK support. Today the Android SDK ciphers. The iOS, JavaScript, Svelte, Flutter and Go SDKs do not yet: pointed at an encrypted application they are switched off by the server, and nothing readable they send is stored.

Platform matrix

SDKPackageRuns onQueueCrash capture
Androidgr.fintechiq.logwatcher (AAR)Android 4.1+SQLite (persistent)uncaught-exception handler
iOSLogWatcher (SwiftPM)iOS 12+, macOS 10.15+JSONL file (persistent)NSUncaughtExceptionHandler
JavaScript@fintechiq/logwatcherBrowsers, Node ≥18localStorage / memoryonerror + unhandledrejection / process hooks
Svelte@fintechiq/logwatcher-svelteSvelte, SvelteKitas JavaScriptSvelteKit handleError + browser globals
Flutterlogwatcher_sdk (pub)Flutter mobile/desktop, Dart CLIJSONL file / memoryrecordError + FlutterError hooks
Gologwatcher-sdk-goGo 1.21+ services (GCP-aware)memory (bounded)RecoverPanic / ReportPanic

HTTP API reference

Everything every SDK does goes through five endpoints. Authentication is the X-App-Token header carrying your application key.

EndpointPurposeNotes
POST /app/device-statusRegister a device, fetch remote enable flagssent on every launch
POST /sessionStart a sessionreturns the numeric session id
POST /log/batchUpload a batch of log linesX-App-Session header; token must match the session's app; body may be gzip (Content-Encoding: gzip)
POST /issueIssues, crashes, user feedbackdiscriminated by type
POST /device/keyvalueSet one device key-valuetyped value

A sixth endpoint only answers a question, and stores nothing: GET /app/check says whether the key in X-App-Token is an application's, what the application is called and whether it is encrypted — for an app that lets a person enter the key and wants to check it before using it. No device is registered by it. It answers {"name": "…", "encrypted": false}, for an encrypted application with the public encryption object that registration returns, and 401 for a key the server does not know. In the Android SDK it is LogWatcher.checkApplication.

For an encrypted application the same five endpoints are used, and no field, header or status code is added: the ciphertext travels in the content fields that already exist, and registration carries one extra value, "encryption": "lwe1", sent only by an SDK that was given a shared key.

The full wire protocol is documented in the LogWatcher repository.

Ready to see your first remote log?
Create an app, copy its key, and init the SDK of your platform.
Get started