Telemetry & Tracing Configuration

📡 Ditto ID SDK: Telemetry & Tracing (OpenTelemetry)

📘 What this is, in plain terms

As the Ditto ID SDK runs, it can keep a short diary of the steps it takes —
starting up, setting up a session, talking to the server, signing a user in, and
so on. Each diary entry is called a span, and a related group of spans is a
trace. You can have the SDK send this diary to a monitoring service of your
choice so your team can see how the SDK is behaving in the field.

You don't need to change any code to turn this on, off, or point it somewhere.
It is all driven by configuration:

  • The server decides the settings for you (it sends a telemetry_configs object),
    and can change them at any time.
  • The app has a single master off-switch that always wins over the server.

The SDK reads these settings when it starts, and again whenever the server sends
new ones.

A few words you'll see below:
span / trace = the SDK's diary entries described above ·
collector = the monitoring service that receives them ·
OTLP/HTTP = the standard web format used to send them.

This telemetry diary is not the same as the SDK's log messages. For log
verbosity see RDNALoggingLevel and SDK Logs.


🎯 Quick start

  • Send the diary to your monitoring service — have the server deliver a
    telemetry_configs object (in Agent Info, or in the create-session response) with:
    • telemetry_export_mode: "network_only"
    • telemetry_http_endpoint: "https://<your-collector-host>/v1/traces"
      (the full web address of your collector's traces endpoint)
  • Turn it off from the server: telemetry_export_mode: "none" in telemetry_configs.
  • Turn it off from the app, for good: set disableTrace: 1 in the init
    otelConfig (see below). While this is set, the server cannot switch it
    back on.

⚙️ App-side options (otelConfig at initialize)

These are passed in the SDK's initialize options. They are optional — letting the
server configure telemetry is the preferred approach.

FieldTypeWhat it does
disableTrace0 / 10 = telemetry is allowed (this is the default). 1 = hard off — the SDK creates and sends nothing, and the server cannot override it.

disableTrace is the only app-side telemetry option. Everything else — where
traces go, the collector address, and all tuning — is configured by the server
(see below).


🛰️ Server-side settings (the telemetry_configs object)

The server is the main place telemetry is configured. It sends the keys below inside a
telemetry_configs object (see Where telemetry_configs comes from below for
the exact locations). Anything you leave out keeps its current value, and any number
that is out of range is quietly pulled back into range (clamped), not rejected.

KeyTypeDefaultAllowed range (clamped)What it controls
telemetry_export_modestringfile_onlynone | file_only | network_only | file_networkWhere the diary goes (see Export modes).
telemetry_http_endpointstringThe full web address of your collector's traces endpoint. Send an empty string to clear an endpoint you set earlier.
telemetry_http_export_max_batch_sizeint51264 – 2048How many spans are sent per upload.
telemetry_max_queue_sizeint2048256 – 8192How many spans can wait in memory before being sent.
telemetry_schedule_delay_msint5000500 – 60000How often the SDK sends what it has, in milliseconds.
telemetry_http_export_timeout_msint100001000 – 30000How long one upload may take before giving up, in milliseconds.
telemetry_http_export_max_retriesint30 – 10How many times to retry a failed upload.
telemetry_file_max_size_bytesint642097152 (2 MiB)262144 – 67108864 (256 KiB – 64 MiB)Size limit for each on-device diary file. Keep it comfortably above one upload's worth of spans — a file always holds whole batches, so a limit smaller than a single batch can't be honoured (hence the 256 KiB floor). (Used by file modes.)
telemetry_file_max_filesint31 – 100How many diary files to rotate through. Total on-device buffer ≈ max_files × max_size_bytes; once full, the oldest file is overwritten. (Used by file modes.)

No separate on/off switch. Whether tracing is actually running is worked out
automatically
from the export mode and whether an endpoint is set (see
Is tracing on? below). There are also no server settings for custom headers
or sampling in this release.

Where to configure it

For a BAU (NON-SaaS) deployment, telemetry is configured in the management console:

GM → Module Config Management → DC → BlaZe-Adapter → sdk.app.settings

That console field already holds a JSON object of application settings. Add
telemetry_configs as one more entry alongside the settings already there
— you are
editing the value of sdk.app.settings, so do not wrap it in another
sdk_app_settings object (the server adds that layer for you). Save, and the new settings
reach devices on their next create-session.

Example — the value to put in sdk.app.settings

The line stands for whatever is already configured in that field — leave it as-is
and add the telemetry_configs block next to it. Every tuning key below is shown at its
default; only telemetry_export_mode and telemetry_http_endpoint are set to a
typical "send to your collector" choice — change those two to suit. It's a partial
config, so you can safely delete any line you don't want to change (an omitted key keeps
its default).

{
  "…": "your existing sdk.app.settings entries — leave as-is",
  "telemetry_configs": {
    "telemetry_export_mode": "network_only",
    "telemetry_http_endpoint": "https://otel.example.com/v1/traces",
    "telemetry_http_export_max_batch_size": 512,
    "telemetry_max_queue_size": 2048,
    "telemetry_schedule_delay_ms": 5000,
    "telemetry_http_export_timeout_ms": 10000,
    "telemetry_http_export_max_retries": 3,
    "telemetry_file_max_size_bytes": 2097152,
    "telemetry_file_max_files": 3
  }
}

Common mistake: pasting the whole { "sdk_app_settings": { … } } wrapper into the
field. That nests it one level too deep. The field is sdk.app.settings — enter only
its value, with telemetry_configs sitting beside your other entries.


📍 Where telemetry_configs comes from

All the keys above live inside a single telemetry_configs object. The server can
deliver that object from a few places; the SDK looks for it in this order and the
first match wins:

  1. telemetry_configs beside sdk_app_settings (a sibling in the create-session
    response) — checked first.
  2. telemetry_configs inside sdk_app_settings — used only if there is no
    sibling one.
  3. telemetry_configs in Agent Info (the connection profile) — applied earlier,
    at initialize.

The create-session sources (1 & 2) are the highest-priority live tier and override
Agent Info; the resolved result is remembered (encrypted) on the device for the next
launch. All of them are partial — send only the keys you want to change; anything
you leave out keeps whatever value was already in effect.

Why two spots in the create-session response? (BAU vs SaaS)

A single SDK build serves both server types, so it accepts telemetry_configs
whichever way your server sends it:

Server typeHow it sends telemetry_configsSDK behaviour
SaaS server (has a connection profile)as a sibling of sdk_app_settings (option 1)picked up first; sdk_app_settings isn't consulted for telemetry
BAU server (no connection profile)nested inside sdk_app_settings (option 2)used because no sibling is present

You don't choose this in the app — it's determined by which server the device talks to;
the SDK resolves it automatically.

Agent Info — the telemetry_configs object sits alongside the profile's other
sections (the rest is abstracted here):

{
  "agent_uuid": "…",
  "preferred_agent": "agent_rel_id",
  "agent_rel_id": "…",
  "device_security_check": { "…": "MTD / security section" },

  "telemetry_configs": {
    "telemetry_export_mode": "network_only",
    "telemetry_http_endpoint": "https://otel.example.com/v1/traces",
    "telemetry_schedule_delay_ms": 5000
  }
}

Create-session response (SaaS)telemetry_configs as a sibling of
sdk_app_settings:

{
  "telemetry_configs": {
    "telemetry_export_mode": "network_only",
    "telemetry_http_endpoint": "https://otel.example.com/v1/traces"
  },
  "sdk_app_settings": { "…": "other app settings" }
}

Create-session response (BAU)telemetry_configs lives inside the
sdk.app.settings value (which the server delivers under sdk_app_settings). You don't
build that wrapper yourself — just configure the sdk.app.settings value in GM as shown
in Where to configure it above.


🧭 What each setting does

KeyWhat it does
telemetry_export_modeThe master switch for where traces go: none (off), file_only (keep on device only), network_only (send live to your collector, no file), file_network (keep on device and forward to the collector).
telemetry_http_endpointYour collector's full traces web address that traces are sent to. Needed for any sending; an empty string clears it (and in network_only, sending stops until a new address arrives).
telemetry_http_export_max_batch_sizeHow many traces are grouped into one upload. Bigger = fewer, larger uploads; smaller = more frequent, lighter ones.
telemetry_http_export_timeout_msHow long a single upload may run before it's given up on — protects against a slow or unreachable collector holding things up.
telemetry_http_export_max_retriesHow many times a failed upload is retried before those traces are dropped. 0 means no retry.
telemetry_max_queue_sizeHow many traces can wait in memory for sending. When it's full, new ones are dropped — this protects app memory if the collector is slow or offline.
telemetry_schedule_delay_msHow often the SDK sends whatever it has waiting, even if a full batch hasn't built up yet.
telemetry_file_max_size_bytesThe size limit for each on-device buffer file; when a file reaches it, the SDK moves on to the next one (file modes).
telemetry_file_max_filesHow many buffer files are rotated through. Together with the size limit this sets the total on-device buffer ceiling (files × size) before the oldest data is overwritten (file modes).

⏱️ How and when traces are sent

Traces aren't sent one-by-one as they happen — that would drain battery and network.
Instead the SDK collects them in memory and sends them in batches. A batch goes out
when either of these happens first:

  • The timer elapses — every telemetry_schedule_delay_ms (default 5 s) the SDK
    sends whatever it has waiting, even if that's just one trace.
  • A batch fills up — as soon as telemetry_http_export_max_batch_size traces
    (default 512) have piled up, they're sent right away without waiting for the timer.

So sending is both time- and size-driven — whichever comes first. In a quiet app the
5-second timer does the work; during a busy burst the batch-size trigger kicks in so
memory doesn't keep growing.

The waiting room. Traces wait in an in-memory queue that holds up to
telemetry_max_queue_size (default 2048). If your collector is slow or offline and the
queue fills up, new traces are dropped to protect the app's memory — telemetry never
blocks or crashes the app.

Each upload carries up to telemetry_http_export_max_batch_size traces, may run up to
telemetry_http_export_timeout_ms (default 10 s) before it's given up on, and if it
fails it's retried up to telemetry_http_export_max_retries times (default 3) before
those traces are discarded.

Tuning the behaviour

You want…ChangeEffect
Traces to arrive soonerlower telemetry_schedule_delay_ms (e.g. 1000)more frequent, smaller uploads (slightly more battery/network)
Fewer, larger uploads (save battery/network)raise telemetry_schedule_delay_ms and/or telemetry_http_export_max_batch_sizetraces arrive less often, grouped together
Headroom for bursty activityraise telemetry_max_queue_sizefewer drops when many traces are produced at once
To give up faster on a bad collectorlower telemetry_http_export_timeout_ms and telemetry_http_export_max_retriesless time and effort spent on uploads that won't succeed

All of these are server-side keys inside telemetry_configs — change them the same way as
any other setting (see Where to configure it). Values out of range are quietly clamped.

Mobile reality: these sends happen only while the app is running. If the app is swiped
away or killed before the next send, traces still waiting in memory are lost. To keep
them across restarts, use a file mode (file_network): traces are written to the
on-device buffer first and forwarded afterwards — see On-device buffering &
store-and-forward
.


🧮 How missing or invalid values are handled

The SDK never rejects a bad telemetry value — it always resolves to something safe.
There are three behaviours depending on the key:

Kind of keyIf the value is missingIf the value is invalid / out of range
Numbers — batch size, queue size, timeout, retries, schedule delaykeeps the value already in effectpulled back into the allowed range (e.g. 0 → the minimum, a huge number → the maximum)
File limitstelemetry_file_max_size_bytes, telemetry_file_max_fileskeeps the value already in effectzero or below resets to the default (2 MiB / 3 files); a positive value is then pulled back into the allowed range (256 KiB – 64 MiB per file, 1 – 100 files)
Mode & endpointtelemetry_export_mode, telemetry_http_endpointkeeps the value already in effectan unrecognised mode is ignored (previous mode kept); an empty endpoint clears the address

"Keeps the value already in effect" vs "the default": the built-in defaults are set
once at startup. Each source (Agent Info, then the remembered settings, then the
create-session telemetry_configs) is layered on top and only changes the keys it
actually includes. So
a key you don't send is not reset to its default — it simply keeps whatever the
previous layer set. Defaults only apply to keys that no source ever set.

The full default and range for every key is in the Server-side settings table above.


🔀 Export modes

The export mode simply says where the diary should go.

ModeWhat happensAvailable now?
noneOff. Nothing is recorded or sent.✅ Yes
network_onlySend entries straight to your collector over the web.✅ Yes
file_onlyKeep entries on the device only (no network).✅ Yes
file_networkKeep entries on the device and send them to your collector — so nothing is lost if the device is offline or the app is closed.✅ Yes

Default: telemetry_export_mode defaults to file_only — out of the box the
SDK buffers to the device and nothing leaves it until you switch to network_only or
file_network and set an endpoint.

Is tracing on? (worked out automatically)

ModeEndpoint set?Result
network_onlyyesOn
network_onlynoOff — and it turns itself on automatically the moment an endpoint arrives
noneOff
file_only / file_networkanyOn

And remember: the app's disableTrace: 1 switch beats all of the above and
forces tracing Off.


🥇 Which setting wins?

The same setting can come from more than one place. When that happens, the higher
one on this list wins (and each level only changes the specific keys it provides):

  1. Built-in defaults
  2. telemetry_configs in the connection profile (Agent Info)
  3. The last settings we saved on the device (used at startup, before the server answers)
  4. App disableTrace off-switch — beats everything except the server's live settings for the keys it doesn't touch, and can never be overridden as an off-switch
  5. telemetry_configs from the create-session response (sibling of sdk_app_settings, else nested inside it) — the highest live source

The resolved settings are saved on the device in encrypted form, so the SDK can
apply the last known behaviour on the next launch even before the server responds.


🚦 Turning it on and off

  • Switching telemetry_export_mode to none (or removing the endpoint) stops
    sending
    . The SDK keeps everything ready in the background so it can start again
    instantly when you re-enable it — no restart needed.
  • Setting the app's disableTrace: 1 is a hard off: nothing is recorded, and no
    server setting can turn telemetry back on while it stays set.

Two ways to keep tracing off — and they are not the same

How you turn it offCan the server turn it back on?Use this when…
App disableTrace: 1 (in the init otelConfig)No — it's a hard offYou must honour a user saying "no", or meet a compliance / legal requirement
Off in the connection profile / Agent Info (e.g. mode none, no endpoint)Yes — this is only a soft default, and a later telemetry_configs from the server can switch it onIt's just an operational default you're fine letting the server change

Rule of thumb: if the reason for turning telemetry off is consent or
compliance
, always use the app's disableTrace: 1. Turning it off only in
Agent Info can be silently switched back on by the server.


🔒 Privacy, what's collected & compliance

The diary leaves the device only when you set up an HTTP endpoint (modes
network_only or file_network). Because an entry can include a device identifier,
privacy laws may treat it as personal data — even though it contains no names,
passwords, or message content. Please read this section before turning on HTTP
export in production.

This is integration guidance, not legal advice — confirm your obligations with
your own privacy / legal team.

What goes into an entry

Included:

  • Operation names — the SDK step being recorded (for example EnrollUser,
    ForgotPassword, AuthenticateChannel, coreLogOff, and session/channel setup).
    These say what the SDK did, not who did it.
  • A device tag / identifier — a REL-ID device identifier. This is the one item
    that could tie an entry back to a specific device (and so, indirectly, a person).
  • The server host / port — which REL-ID server the device talked to
    (infrastructure detail, not user data).
  • Result / status codes and a few operation labels (for example the step-up
    authentication operation/api).
  • trace_id / span_id — random reference numbers; they are not built from any
    user or device detail.

Never included — the SDK never puts any of these into an entry: names, email,
phone, user IDs, login IDs, session IDs, passwords or PINs, biometric data,
security keys or tokens, card numbers or any cardholder data, or the contents of any
message.

Private by default

  • Nothing leaves the device unless you ask for it. Sending starts only once you
    set an HTTP endpoint; network_only with no endpoint stays off.
  • There is a hard off-switchdisableTrace: 1 (see the table above) is the one
    to connect to a user's consent choice.
  • Only the minimum is collected — the list above is fixed and small, and no
    free-form user content is ever attached.
  • Protected in transit and at rest — sending uses OTLP/HTTP, so please use
    HTTPS; any on-device diary is kept in the app's private storage and is
    size-limited (it rotates through a fixed set of files).

Your part as the integrator

  • Where the data lives — the diary goes to the exact telemetry_http_endpoint
    you set. If your users are in a regulated region (EU/EEA, India, and so on), point
    them at a collector in that region and record the reason for any cross-border
    transfer. Keep DEV/QA and PROD (and, where needed, per-region) endpoints
    separate.
  • Consent & transparency — mention telemetry in your privacy notice; where
    consent is required (for example ePrivacy), only send after you have it, and wire
    the user's opt-out to disableTrace: 1.
  • Controls on your side — set retention limits and access controls at your
    collector, and remove duplicates by trace_id / span_id (delivery can send the
    same entry more than once).
  • Laws that often apply when the diary leaves the device include GDPR (a
    device identifier counts as an "online identifier", i.e. personal data),
    ePrivacy, CCPA/CPRA and other US state laws, the India DPDP Act, and —
    for regulated industries — PCI-DSS / GLBA / HIPAA / DORA. The SDK's
    data-minimisation and off-switch are there to help you meet these; the lawful basis,
    consent, and endpoint choice remain your responsibility.

🗄️ On-device buffering & store-and-forward (file modes)

The file modes (file_only / file_network) provide durable on-device buffering so
entries are not lost when the device is offline or the app is closed before the
next send:

  • Entries are written to a size-limited, rotating set of files in the app's
    private storage (by default: 3 files × 2 MiB), controlled by
    telemetry_file_max_files / telemetry_file_max_size_bytes.
  • In file_network, a background helper delivers the saved entries to your collector and
    clears them once accepted. The same entry may occasionally be sent more than once,
    so your backend should de-duplicate by trace_id / span_id.
  • If tracing is turned off (either the none mode or the app's disableTrace: 1
    off-switch): the SDK stops creating new entries and writes nothing more to disk, but
    entries already saved are kept on the device — they are never wiped. They stay put
    (in the bounded, rotating buffer) and are sent the next time tracing is on with a
    reachable endpoint.
  • No special Android/iOS permissions are needed (it uses private app storage).

❓ FAQ

  • Do I need any Android/iOS permissions for telemetry? No.
  • Can the server force telemetry on if the app turned it off? No —
    disableTrace: 1 is a hard off.
  • I turned tracing off only in Agent Info / the connection profile — is that a hard
    off too?
    No. That's only a soft default, and the server can switch it back on
    via a later telemetry_configs. Use disableTrace: 1 for a real,
    consent/compliance-grade off-switch.
  • Does telemetry contain personal data? It can — an entry may include a device
    identifier
    , which counts as personal data under laws like GDPR. It never includes
    names, passwords, biometrics, tokens, card data, or message content. See
    Privacy, what's collected & compliance.
  • Where should I send the diary for EU / India / other regulated users? To a
    collector in the right region, using separate DEV/QA and PROD endpoints. Where
    the data lives and the lawful basis are your responsibility as the integrator.
  • What format is used to send it? The OpenTelemetry standard over the web
    (OTLP/HTTP), sent to the telemetry_http_endpoint you set (the full /v1/traces
    address). Both http:// and https:// endpoints are supported — use https://
    in production
    (the mode name network_only refers to the destination, not the
    protocol version).
  • Where does the diary show up? In whatever OpenTelemetry-compatible tool your
    endpoint feeds (for example a collector → Tempo/Jaeger → Grafana). Filter by
    service.name (set to your tenant/app id).

Did this page help you?