Release notes
What's new in each version of the ROLearn-Multiplatform SDK packages. Versions follow semver — minor bumps are backwards-compatible, major bumps are not. Direct download links live on the Downloads page.
Roblox (Lua)
v0.6.1 — 2026-05
- Critical fix: the LocalizationService method name shipped in v0.3.0–v0.6.0 was misspelled as GetCountryRegionCodeForPlayerAsync (extra "Code") — a method that does not exist on Roblox's API. pcall silently swallowed the error and every player resolved to "XX", which is why the country pulse dashboard has only "XX" data on record for games running an older SDK. The correct method is GetCountryRegionForPlayerAsync. After republishing your place with v0.6.1 the country column on the SDK Dashboard should populate with real ISO codes within one nightly aggregation cycle.
- Add: country lookup now retries up to 3× with exponential backoff (2s, 4s, 8s) to ride out Roblox's per-IP rate-limit on the country endpoint during mass-join waves — the most common cause of remaining "XX" rows on real adult accounts after the typo fix.
- Add: Player.LocaleId fallback. When the account-region API returns empty or fails after all retries (under-13 accounts, restricted regions), the SDK now parses the locale tag (e.g. "vi-vn" → "VN") so the player still attributes to a country, just at lower confidence.
- Add: session_start and session_end payloads now carry a `country_source` field ∈ {"account_region","locale_id","unknown"} so the dashboard can distinguish definitive country from inferred country at the event level.
- Add: delayed re-resolve. If the join-time lookup returns "XX" we retry once 5 minutes later (after Roblox's per-IP bucket refills), patching the cached session entry so subsequent events for the same player carry the real ISO code.
- Add: warn() lines are now emitted when LocalizationService raises an error, so a future API rename surfaces loudly in your Studio output instead of silently degrading to "XX" like this typo did for three weeks.
- Improve: SDK_VERSION stamped to 0.6.1 in every event payload (_sdk_version field).
v0.6.0 — 2026-05
- Fix: flush now uses HttpService:RequestAsync and classifies failures — a 4xx (except 429) is treated as a permanent validation/auth rejection (the batch is dropped and the server's error body is logged), while 5xx / 429 / network errors stay retryable with exponential backoff. Resolves the infinite HTTP 422 retry loop where a single malformed event blocked every event behind it and re-persisted across server restarts.
- Fix: an out-of-enum purchase.source (e.g. a product NAME passed where iap|gamepass|devproduct|subscription is expected) is now repaired to "iap" at enqueue time — before the event can enter the in-memory or persistent buffer. This was the root cause of the 422 loop.
- Fix: crash/error auto-capture now ignores the SDK's own [RoLearnSDK] log lines (which previously formed a self-amplifying feedback loop) and Roblox's "DataStore request was added to queue" throughput notices. Extend the ignore list via the new config.crash_ignore_patterns option.
- Improve: the persistent DataStore buffer is now schema-tagged; a buffer written by an incompatible older version is discarded on load instead of being replayed.
- Improve: SDK_VERSION stamped to 0.6.0 in every event payload (_sdk_version field).
- Server-side companion: the ingest endpoint now partial-accepts batches — valid events are written and only malformed events are dead-lettered (visible in /sdk/dlq), so one bad event no longer fails the whole batch even for older clients.
v0.5.0 — 2026-05
- Add: SDK.getVariant(player, experimentId) — sticky deterministic A/B test assignment via /experiments/{id}/assign. Returns the variant name, or nil if the player is not in the experiment / fetch fails. Per-server 1h in-memory cache keyed by (experimentId, playerId) so customers can call it per-event without spamming the assign endpoint. (Phase 8.1, Scale+ plans.)
- Phase 4+5 parity: trackAdImpression, trackPerformance, trackCrash, trackError now match Unity + Steamworks event shapes 1:1.
- Improve: SDK_VERSION stamped to 0.5.0 in every event payload (_sdk_version field).
v0.4.0 — 2026-05
- Add: country propagated into purchase, session_end, and ad_impression payloads — cached once per join from LocalizationService:GetCountryRegionForPlayerAsync(), then attached to every subsequent event for the player. Powers per-country playtime + revenue rollups on the new Demographics panel without re-resolving country on each event.
- Fix: SDK.purchase() now defaults currency to "ROBUX" instead of "USD". The MarketplaceService gamepass auto-hook passes no currency field, so the prior "USD" default silently excluded every auto-tracked gamepass purchase from sdk_revenue_daily rollups. Gamepass revenue should populate correctly going forward.
- Improve: SDK_VERSION stamped to 0.4.0 in every event payload (_sdk_version field).
v0.3.0 — 2026-05
- Add: FPS sampling via RunService.Heartbeat — one performance snapshot emitted per session_end.
- Add: LogService crash/error capture — multi-line errors grouped as crash events, single-line as error events.
- Add: trackAdImpression() for ILRD (Impression Level Revenue Data) — format/network/revenue_usd fields.
- Add: trackPerformance() and trackCrash() manual helpers for custom instrumentation.
- Improve: SDK_VERSION stamped to 0.3.0 in every event payload.
v0.2.1 — 2026-04
- Fix: DataStore offline buffer no longer drops events when a server crashes mid-flush.
- Add: optional before_send(event) hook for per-event PII redaction.
- Improve: exponential backoff jitter cap raised to 60s to reduce thundering-herd on outages.
v0.2.0 — 2026-03
- Add: persistent offline buffer using DataStore — survives server restart.
- Add: auto-attached MarketplaceService.PromptPurchaseFinished purchase tracking.
- Breaking: SDK.init now requires endpoint (was hardcoded). Update your boot script.
v0.1.0 — 2026-02
- Initial release — server-side telemetry for Roblox games.
Unity (C#)
Package: com.rolearn.sdk · UPM (Git URL)
v0.5.0 — 2026-05
- Add: RoLearnSDK.GetVariantAsync(experimentId, playerId) — sticky deterministic A/B test assignment via /experiments/{id}/assign with 1h in-memory cache. Returns the variant name (Task<string>), or null if the player is not in the experiment / fetch fails. (Phase 8.1, Scale+ plans.)
- Phase 4+5 parity: TrackAdImpression, TrackPerformance, TrackCrash, TrackError implementations brought to full event-shape parity with Roblox + Steamworks.
- Improve: _sdk_version stamped as "0.5.0" on every event payload.
v0.1.0 — 2026-04
- Initial release — UPM package for Unity 2021.3 LTS+.
- IL2CPP-safe via shipped link.xml.
- Optional Unity IAP listener auto-tracks purchases when #if UNITY_PURCHASING.
Steamworks (C++)
Package: rolearn-sdk · vcpkg / Conan
v0.5.0 — 2026-05
- Add: rolearn::Client::get_variant(experiment_id, player_id) — sticky deterministic A/B test assignment via /experiments/{id}/assign over libcurl, mutex-guarded in-process 1h cache. Returns the variant string, or empty string if the player is not in the experiment / fetch fails. C ABI wrapper rolearn_get_variant() also exposed. (Phase 8.1, Scale+ plans.)
- Phase 4+5 parity: track_ad_impression, track_performance, track_crash, track_error now match Roblox + Unity event shapes 1:1.
- Improve: SDK_VERSION constant stamped to "0.5.0" in every event payload (_sdk_version field).
v0.2.1 — 2026-04
- Fix: ISteamMicroTxn query batching no longer leaks file descriptors on Linux.
- Add: optional Conan recipe alongside vcpkg manifest.
v0.2.0 — 2026-03
- Add: ISteamUserStats hook — periodic capture of live concurrent users.
- Add: thread-safe instance singleton.
v0.1.0 — 2026-02
- Initial release — header-only C++ embed client with libcurl + nlohmann/json.
