Appearance
Unity
The com.xkdlabs.simpledatalogs package tracks events from Unity games and apps. It has no dependencies, uses no reflection, and keeps a crash-safe outbox on disk, so an event is never lost to a crash or a killed app.
- Unity 2021.3 or newer.
- Android, iOS, desktop and WebGL players, on Mono and IL2CPP.
Install
In Unity, open Window → Package Manager, click +, choose Add package from git URL… and enter:
text
https://github.com/XKD-Labs/simpledatalogs-unity.git#v0.1.0Or with OpenUPM:
sh
openupm add com.xkdlabs.simpledatalogsThe Package Manager also offers a Quick start sample with a ready-made MonoBehaviour.
Early access
The package isn't on OpenUPM yet, and the v0.1.0 tag comes with the first release. Until then, add the git URL without the tag:
text
https://github.com/XKD-Labs/simpledatalogs-unity.gitQuick start
Configure once at launch, on the main thread, for example in Awake of a bootstrap object:
csharp
using System.Collections.Generic;
using UnityEngine;
using XKDLabs.SimpleDataLogs;
public sealed class Analytics : MonoBehaviour
{
private void Awake()
{
// The opt-out first, then identity and default properties, then the key.
SimpleDataLogs.SetEnabled(userAllowsUsageStatistics);
SimpleDataLogs.SetDeviceId(anonymousDeviceId);
SimpleDataLogs.SetDefaultProperties(new Dictionary<string, object>
{
["app_version"] = Application.version,
});
SimpleDataLogs.Configure("sdl_pub_…");
}
}Then track from anywhere, on any thread. It returns at once and never throws:
csharp
SimpleDataLogs.Track("level_complete", new Dictionary<string, object> { ["level"] = 3, ["duration_s"] = 41, ["score"] = 1200 });Use a public key (sdl_pub_…) in games. The SDK logs a warning if it sees a secret key.
Events for games
csharp
SimpleDataLogs.Track("level_start", new Dictionary<string, object> { ["level"] = 3 });
SimpleDataLogs.Track("purchase", new Dictionary<string, object> { ["sku"] = "gem_pack_small", ["price"] = 0.99, ["currency"] = "USD" });
SimpleDataLogs.Track("tutorial_step", new Dictionary<string, object> { ["step"] = 2 });
// A screen that is not its own scene, such as a menu panel.
SimpleDataLogs.TrackScreen("Shop");Property values are strings, integers, floats, doubles or booleans. Anything else (null, lists, dictionaries, NaN, infinity) is dropped with a console line.
Autocapture
One argument sends launches, sessions, scene views and errors without any Track call. It is off until you pass it.
csharp
SimpleDataLogs.Configure("sdl_pub_…", autocapture: AutocaptureOptions.All);| Option | What you get |
|---|---|
AppLaunches | app_launched on every launch, with is_first_launch |
Sessions | session_start, a session_id on every event, and session_end (duration_s) once the game has been away 30 minutes; pause and focus loss count as away |
SceneViews | screen_view with screen = the scene name, each time a scene loads (additive loads too) |
Errors | app_error (message, stack, log_type) for logged exceptions and errors; at most 5 per message and 50 per session |
All is all four; combine flags to pick, e.g. AutocaptureOptions.Sessions | AutocaptureOptions.SceneViews.
- Nothing starts on its own: nothing is sent before you call
Configure. - The opt-out applies: with
SetEnabled(false), nothing is captured.
Active and background
Every event tracked now says whether someone was playing, so the Sessions tab can tell active sessions from passive ones:
app_stateisactivewhile the game is unpaused and focused, elsebackground.engaged_msis the time in front since the previous event.- Mark background work yourself with an
app_stateofbackground; your value wins. Configure(key, reportsActivity: false)sends neither.
API
| Call | What it does |
|---|---|
Configure(ingestKey, endpoint, autocapture) | Starts the SDK once; autocapture defaults to none, endpoint to https://edge.simpledatalogs.com. Later calls are ignored |
Track(eventName, properties) | Records one event. event_id and ts are stamped now, when the event happens |
TrackScreen(screenName, properties) | Records screen_view with a screen prop |
SetDeviceId(deviceId) | Sets, or clears with null, the device_id on every later event |
SetDefaultProperties(properties) | Replaces the properties merged into every event; the event's own properties win on a clash |
SetEnabled(isEnabled) | The opt-out. false ignores new events and deletes every unsent event; true collects again |
Flush() | Sends everything now. Undelivered events stay on disk |
The opt-out
Call SetEnabled before Configure. A player who opted out then never sends a byte, and whatever an earlier launch left on disk is deleted instead of sent.
The SDK doesn't persist the choice. Your game's setting is the source of truth, so pass it on every launch.
Privacy
- The SDK sends only what you track, plus the device id and session id when you set or enable them.
- It never reads
SystemInfo.deviceUniqueIdentifieror advertising ids. Pick your own anonymous id; the sample keeps a random one inPlayerPrefs. - Error autocapture sends log messages as they are, so keep personal data out of them, or leave
Errorsoff.
How it behaves
Batching
Events go out in batches of 50, or 10 seconds after the first event of a partial batch (5 seconds in the Editor and development builds). Every request stays under 256 KB, and bodies of 1 KB or more are gzipped (except on WebGL).
A crash-safe outbox
- Each event is appended to a journal on disk as it is tracked.
- Batches are sealed into files and deleted only after a
202. - The next launch resends anything left over, including a journal cut short by a crash.
- Files live in
Application.persistentDataPath/simpledatalogs/.
Lifecycle
A hidden DontDestroyOnLoad object ticks the SDK a few times a second (ignoring Time.timeScale) and flushes when the game pauses, loses focus or quits. Anything a flush can't deliver in time stays on disk for the next launch.
Errors and offline
| Answer | What the SDK does |
|---|---|
202 | Deletes the batch file |
401 | Pauses sending and logs one configuration error; nothing is lost. Re-probes after 1 minute, then every 10 minutes, and on the next launch |
413 | Splits the batch in half and resends. A single event still too large is dropped, with a console line |
415 | Sets the batch aside as .unsupported and moves on |
| Anything else, a timeout, offline | Backs off with full jitter from 1 second to 5 minutes, honoring Retry-After |
Caps
The outbox keeps at most 10,000 events, 10 MB or 500 batch files. Past that, the oldest batches are dropped, with a console line.
No call throws into your game.
Platform notes
- IL2CPP and code stripping. No reflection and a hand-written JSON encoder, so no
link.xmlis needed. - WebGL. Requests go through UnityWebRequest, which uses the browser's networking, so there's no gzip or
User-Agent. The outbox lives in the browser's IndexedDB-backedpersistentDataPath. - Enter Play Mode Options. With domain reload off, the SDK resets when play mode starts, so call
Configurein each play session.
Troubleshooting
Problems are logged to the Unity console with the prefix [simpledatalogs]. A 401 there means the key is wrong or not live yet; events are kept and sent once it works.
For local development, point it at a local ingest:
csharp
SimpleDataLogs.Configure("sdl_pub_…", endpoint: "http://localhost:4001");Next steps
- Unity quickstart: the shortest path.
- Core concepts: one deployment per build, such as
steamandios. - Privacy for senders: device ids, not emails.