Kiwi SDK Docs
Open SDK Portal

Unity backend services

Build connected Unity games with Kiwi SDK.

Use Kiwi accounts, cloud saves, targeted LiveOps, economy, competition, diagnostics, and evolving multiplayer foundations from one app-and-environment scoped SDK.

v0.3.0 available v0.4 staged Unity 2022.3+

Overview

One SDK context for every service

Kiwi SDK is a developer preview for Unity projects. A single KiwiSdkConfig selects the SDK app and environment used by accounts, remote config, cloud saves, analytics, diagnostics, and tenant-scoped realtime services.

Stable and staged APIs are separated.Version 0.3.0 remains the package used by live products. Cross-platform identity, economy, targeted LiveOps, and competition are staged for 0.4.0-preview.1; they are not available to a live game until its backend and Unity package are deliberately upgraded.
Isolation is part of the contract.Data written to dev is separate from staging and production. The app ID and environment travel with each SDK request.
Ship safer changesPublish environment-specific JSON and load an encrypted remote-config cache before the network responds.
Keep player stateStore small JSON documents or versioned file slots with integrity checks and bounded quotas.
See what happenedSend explicit analytics events, crash payloads, and logs without installing a separate reporting package.
Build on Kiwi accountsUse the same two-step login and rotating session used by Kiwi Studios services.

Recommended integration path

  1. 1
    Create an SDK app

    Open the SDK Portal, create an app, and copy its public app ID.

  2. 2
    Install the tagged package

    Add the Kiwi SDK v0.3.0 Git URL and its two direct Git dependencies to the Unity project manifest.

  3. 3
    Start in dev

    Initialize against dev, authenticate a test account, and verify each service independently.

  4. 4
    Promote deliberately

    Publish config and validate data separately in staging before selecting production.

Getting started

Requirements and package access

The current package is com.kiwistudios.sdk version 0.3.0 and targets Unity 2022.3 or newer. The tagged developer-preview package is available from GitHub.

Pin the release tag.Use kiwi-sdk-v0.3.0 rather than an unversioned branch so package updates remain deliberate and reproducible.

Required packages

PackagePurposeDeclared version
com.cysharp.unitaskAsync Unity operations2.5.10
com.itisnajim.socketiounityRealtime Socket.IO transport1.1.5
com.unity.nuget.newtonsoft-jsonJSON serialization3.2.2
com.unity.modules.unitywebrequestHTTP transport1.0.0

The dependencies are declared in the Kiwi package manifest. Unity cannot resolve transitive Git dependencies, so Git installs must also add UniTask and SocketIOUnity directly to the project manifest. Registry consumers may configure the com.cysharp and com.itisnajim OpenUPM scopes instead.

Install the tagged Git package

Packages/manifest.json
https://github.com/ArtemisMoysen/GDW4.git?path=Packages/com.kiwistudios.sdk#kiwi-sdk-v0.3.0

In Packages/manifest.json, add the tagged Kiwi SDK URL plus UniTask 2.5.10 and SocketIOUnity 1.1.5 as direct dependencies.

Or add the package from disk

  1. Put the approved com.kiwistudios.sdk folder in a stable local location, normally your project's Packages directory.
  2. In Unity, open Window → Package Manager.
  3. Select +, then Add package from disk….
  4. Select com.kiwistudios.sdk/package.json.
Local package file
Packages/com.kiwistudios.sdk/package.json

Getting started

Create an app in the SDK Portal

Sign in to the SDK Portal and create one SDK app for the game. The generated ID starts with ksa_ and does not change.

Safe in a player buildSDK app ID, selected environment, and the Kiwi service origin.
Never put in a player buildMatch authentication keys or another player's session token.

Environments

Every app begins with dev, staging, and production. Remote config, cloud saves, analytics, achievements, crash data, presence, lobbies, queues, and matches are scoped by the selected app and environment. Friend relationships remain account-global.

Getting started

Initialize once at application boot

Create KiwiSdkConfig before calling any service client. The service origin is owned by the package; the public constructor accepts the app ID, environment, request timeouts, and optional session cache keys.

KiwiSdkBootstrap.cs
using KiwiStudios.Sdk;
using UnityEngine;

public sealed class KiwiSdkBootstrap : MonoBehaviour
{
	private void Awake()
	{
		if (KiwiSdk.IsInitialized) { return; }
		var _config = new KiwiSdkConfig(
			"ksa_replace_with_your_app_id",
			"dev",
			20,
			10);

		KiwiSdk.Initialize(_config);
	}

	private void OnDestroy()
	{
		KiwiSdk.Shutdown();
	}
}
Use dev while integrating.Changing the environment changes the data boundary. It does not copy config, accounts' game data, or queues between environments.

Accounts

Authenticate, cache, then resolve the SDK session

Interactive sign-in uses LoginStep1 followed by LoginStep2. After a successful second step, call SetAuthenticated, CacheSession, and ResolveSdkSession. Resolution verifies that the signed-in account can establish the configured app-and-environment context.

RestoreSession validates cached credentials online and stores a rotated token after success. Offline identity is opt-in: it can restore a recent locally cached identity after a network failure, but only from native secure storage and never for cloud writes, realtime, or other online services.

Restore a cached session
using Cysharp.Threading.Tasks;
using KiwiStudios.Sdk;
using System.Threading;

public sealed class KiwiSessionService
{
	public async UniTask<KiwiResult<KiwiAuthResponse>> Restore(CancellationToken _ct)
	{
		KiwiResult<KiwiAuthResponse> _session = await KiwiSdk.Auth.RestoreSession(_ct);
		if (!_session.Result || !KiwiSdk.Auth.CanAccessOnlineServices)
		{
			return _session;
		}

		KiwiResult<KiwiSdkSessionResolveResponse> _resolved =
			await KiwiSdk.Auth.ResolveSdkSession(_session.Data.UserId, _session.Data.Token, _ct);
		if (!_resolved.Result)
		{
			return KiwiResult<KiwiAuthResponse>.Failure(_resolved.Error, _resolved.StatusCode);
		}
		return _session;
	}
}
Offline identity is disabled by default.Use KiwiSecureSessionStore for macOS Keychain, iOS Keychain, Android Keystore, or Windows Credential Manager. Then opt in with _allowOfflineIdentity: true, set a short maximum age, and gate network features on CanAccessOnlineServices. PlayerPrefs is never accepted for offline identity.

0.4 staged preview

Start anonymously, then link a verified platform

The staged identity client supports anonymous device accounts and verified Apple, Epic, Google, and Steam credentials. Provider credentials are verified by Kiwi before an identity is authenticated or linked; the player build never receives provider configuration secrets.

Requires the 0.4 Unity package.KiwiSdk.Identity does not exist in the live 0.3.0 package. Do not switch a live product until the provider configuration is ready, the backend is deployed, and the new package passes that product's login and account-recovery tests.
Anonymous sign-in
string _deviceSecret = _secureCredentialStore.Load("kiwi_device_secret");
if (string.IsNullOrWhiteSpace(_deviceSecret))
{
	_deviceSecret = KiwiPlatformIdentityClient.CreateAnonymousDeviceSecret();
	_secureCredentialStore.Save("kiwi_device_secret", _deviceSecret);
}

KiwiResult<KiwiPlatformIdentityData> _result =
	await KiwiSdk.Identity.AuthenticateAnonymous(_deviceId, _deviceSecret);
  • Generate one stable random device ID and one device secret per installation. Persist the secret in native secure storage before the first authentication request.
  • Use AuthenticateProvider for Apple, Epic, Google, or Steam sign-in, then use LinkProvider only from an already authenticated Kiwi session.
  • Kiwi rejects unlinking the final recoverable identity unless the account still has a native login or an active anonymous-device credential.
  • Console identity is not implemented in this preview and requires platform-holder approval and verification configuration.

Core services

Load cached values before fetching updates

Publish a JSON object from the SDK Portal. At runtime, load the encrypted local cache first, then fetch the selected environment. A successful changed response is written to the cache before its hash is committed.

Remote config
using Cysharp.Threading.Tasks;
using KiwiStudios.Sdk;
using Newtonsoft.Json.Linq;
using UnityEngine;

public sealed class GameConfigLoader
{
	public async UniTask Load()
	{
		KiwiSdk.RemoteConfig.TryLoadCache();
		KiwiResult<JObject> _result = await KiwiSdk.RemoteConfig.Fetch();
		if (!_result.Result)
		{
			Debug.LogWarning(_result.Error);
			return;
		}

		int _dailyMatchLimit = KiwiSdk.RemoteConfig.GetInt("dailyMatchLimit", 5);
		Debug.Log(_dailyMatchLimit);
	}
}

Remote config is delivered to player clients. Do not publish match keys, credentials, private endpoints, or values that must remain secret.

0.4 staged preview

Layer rules and experiments over base config

LiveOps keeps the published environment document as the base, then applies active rules in priority order. Rules can match build and custom attributes, use start and end times, and roll out to a deterministic percentage of players. Experiments assign one stable weighted variant per player.

Fetch targeted config
var _attributes = new KiwiLiveOpsAttributes
{
	BuildId = Application.version,
	Custom = new Dictionary<string, object>
	{
		["region"] = "na",
		["skillTier"] = "gold"
	}
};

KiwiResult<JObject> _result =
	await KiwiSdk.RemoteConfig.FetchTargeted(_attributes);
Existing games remain compatible.The existing Fetch() method continues to receive only the published base config. Updating the Unity package is required to opt into targeting, submit build or custom attributes, or inspect LastAppliedRules and LastAssignments.

Targeted responses are online-only in this preview and are not written to the shared base-config cache. This prevents one signed-in player's rules or experiment variant from being restored for another account on the same device. Use gameplay defaults when a targeted fetch is unavailable.

Core services

Choose JSON data or file slots

Cloud save provides two surfaces. User data is a small JSON record for profile-shaped values. Slots are immutable file commits for larger save payloads, with a manifest and SHA-256 integrity metadata.

User data protection labels

Public

The signed-in player can write it. Use it for data that is safe to show outside the owner account.

Protected

The signed-in player can currently write it. Treat it as owner-scoped, client-authoritative data.

Private

Normal player writes cannot change it, but the owning player receives it when loading. It is not a secret store.

JSON saves shallow-merge top-level keys.A write does not replace the complete object, and nested objects are not deep-merged. Load the current Version and pass it to SaveUserDataVersioned; stale writes return 409 cloud_save_version_conflict.
Save and load player data
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using KiwiStudios.Sdk;

public sealed class PlayerProfileSave
{
	public async UniTask<KiwiResult<KiwiCloudSaveLoadResponse>> SaveAndLoad(
		string _userId,
		string _token)
	{
		var _publicData = new Dictionary<string, object>
		{
			["selectedTitle"] = "pathfinder"
		};
		var _protectedData = new Dictionary<string, object>
		{
			["tutorialComplete"] = true
		};

		KiwiResponse _save = await KiwiSdk.CloudSave.SaveUserData(
			_userId,
			_token,
			_publicData,
			_protectedData);

		if (!_save.Result)
		{
			return KiwiResult<KiwiCloudSaveLoadResponse>.Failure(_save.Message, _save.StatusCode);
		}

		return await KiwiSdk.CloudSave.LoadUserData(_userId, _token);
	}
}

File slots

Slot uploads commit a complete version atomically. Files are sent as base64 inside one JSON request; uploads and downloads are not streamed. Set ExpectedVersion to 0 when creating a slot or to the last observed version when replacing it. A stale upload or delete returns 409 cloud_save_version_conflict without changing the committed slot.

Upload one slot file
using System;
using System.Collections.Generic;
using System.Text;
using Cysharp.Threading.Tasks;
using KiwiStudios.Sdk;

public sealed class WorldSlotSave
{
	public async UniTask<KiwiResult<KiwiCloudSaveSlotCommitResponse>> Upload(
		string _userId,
		string _token,
		string _json,
		long _lastKnownVersion)
	{
		var _request = new KiwiCloudSaveUploadRequest
		{
			SlotId = "autosave",
			DisplayName = "Autosave",
			ExpectedVersion = _lastKnownVersion,
			Manifest = new Dictionary<string, object> { ["scene"] = "village" },
			Files = new List<KiwiCloudSaveFileUploadData>
			{
				new KiwiCloudSaveFileUploadData
				{
					Path = "world/save.json",
					ContentBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(_json))
				}
			}
		};

		return await KiwiSdk.CloudSave.UploadSlot(_userId, _token, _request);
	}
}

Current default slot limits

BoundaryDefault
Slots per player, app, and environment10
Files per slot32
Decoded bytes per file512 KiB
Decoded bytes per slot700 KiB
Total slot bytes per player5 MiB
Serialized manifest64 KiB
Slot ID length96 characters
File path length191 characters

Limits are service defaults and may change during the preview. Design save formats below every boundary because base64 and JSON add request overhead.

Core services

Track lightweight achievement progress

Use the portal to describe lightweight client achievements, then call Unlock, Increment, or List from an authenticated player session. For trusted achievements, attach a rule to a statistic definition; Kiwi marks that achievement server-authoritative and only the portal or authenticated match-report statistic path can satisfy it.

Choose authority deliberately.Undefined and client-authority achievements still accept player unlocks and increments. A statistic rule converts its achievement ID to server authority, blocks client writes, and hides any older client-authored row until the trusted rule is actually satisfied.
Increment progress
KiwiResponse _response = await KiwiSdk.Achievements.Increment(
	_userId,
	_token,
	"matches_played",
	1);

0.4 staged preview

Make every balance change a transaction

The staged economy publishes versioned catalogs containing currencies, items, stores, and store entries. Player balances and inventory change through a locked transaction ledger, and virtual purchases require a player-scoped idempotency key.

Catalogs and storesPublish currency, item, bundle, price, purchase-limit, and metadata definitions as one catalog version.
Atomic transactionsCosts and grants commit together under database locks; insufficient balances and stack-limit violations reject the transaction.
Purchase validationApple, Google, and Steam receipts use an authenticated server-side verifier adapter and cannot be replayed across players, apps, or environments.
ReversalsPortal refunds append an inverse ledger transaction. Consumed grants become scoped debt that future grants settle before increasing the available balance.
Idempotent virtual purchase
KiwiResult<KiwiEconomyTransactionData> _result =
	await KiwiSdk.Economy.Purchase(
		_userId,
		_token,
		"featured",
		"starter_bundle",
		_purchaseAttemptId);
Requires the 0.4 Unity package and configured receipt verification.The live 0.3.0 package has only the first-party inventory reader. Apple, Google, and Steam real-money purchases must stay disabled until the external verifier services and store credentials are configured and tested.

0.4 staged preview

Write trusted results from the match server

Define statistic aggregation as replace, sum, maximum, or minimum. Seasonal statistics accept writes only while their season is active; leaderboards use dense ranks so tied values share a place; tournaments attach a dated competition window and catalog-backed reward ranges to a leaderboard.

Reset boundariesEach season id has an independent value row, so a new season starts without deleting historical standings.
Reward settlementAfter the tournament ends, an operator settlement locks the tournament, computes dense ranks, and grants each eligible player through one idempotent economy transaction.
Reads are client-facing; writes are trusted.KiwiSdk.Competition reads a player's statistics, leaderboard entries, and competition configuration. Stat updates come from the portal or the already authorized one-time match report, not from a player-write API.
Read a leaderboard
KiwiResult<KiwiLeaderboardData> _result =
	await KiwiSdk.Competition.ReadLeaderboard(
		_userId,
		_token,
		"ranked_wins",
		100);

For an authorized match player, add KiwiStatistics to that player's game-data entry. Each item contains StatId, Value, and an optional SeasonId. Existing reports that omit the field keep their current behavior.

The read client requires the 0.4 Unity package.Server-side match statistic writes are additive and do not change existing RIVE reports, but RIVE needs a package update before gameplay UI can call KiwiSdk.Competition or submit typed statistic fields.

Core services

Send intentional telemetry

Analytics can send immediately or persist a local queue. The queue holds up to 500 events and flushes at most 100 per request. The server returns an accepted count rather than per-event IDs; the client removes that many events from the front of the submitted batch. Failed and unaccepted events remain queued for retry.

The SDK Portal provides app-scoped Dashboards, Events, and Exports views. Dashboard layouts are shared across dev, staging, and production; the environment selector changes only the data being queried. App owners can combine up to four safe measures with count, distinct count, sum, average, minimum, maximum, and source-defined calculations such as match win rate. The builder never accepts SQL, JavaScript, arbitrary joins, or custom formulas.

Scalar event payload fields may be registered to a maximum object depth of four. Arrays, mixed-type fields, and deeper objects remain visible in the raw Events inspector, but they cannot be aggregated in the first dashboard release. Server receipt time in UTC is canonical for trends; client time remains display and export metadata. Events can be narrowed by dashboard range, event, schema, build, player, and an exact UTC received-time window, then advanced in 50-row cursor pages.

A panel may include up to four measures and two grouping dimensions. Metric, line, stacked bar, and table displays can show multiple measures; other visualizations require one measure so their encoding remains unambiguous. Registered fields that do not exist in the selected environment remain visible as unavailable rather than being removed from the app-scoped dashboard definition.

Shared dashboards belong to the app; personal dashboards are visible only to their creator. Either type can be selected as that operator's default, and a shared dashboard can be duplicated into a personal copy. Saves use revision checks: 409 analytics_definition_conflict lets the operator reload the saved revision or keep the draft as a new personal dashboard.

Dashboard definitions can be exported and imported as app-layout JSON without moving environment data. Data exports support CSV and JSON for a filtered panel, generic events, and the six match-report datasets. They are capped at 50,000 rows; operators may use the dashboard range or the full retained range.

Crash reports and logs are manual API calls. The package does not automatically subscribe to Unity log callbacks or unhandled exceptions.

Queue and flush analytics
var _payload = new Dictionary<string, object>
{
	["mode"] = "practice",
	["durationSeconds"] = 84
};

KiwiSdk.Analytics.QueueEvent("match_completed", _payload, "match.v1");
KiwiResponse _flush = await KiwiSdk.Analytics.FlushQueuedEvents(
	_userId,
	_token,
	Application.version);
Keep payloads deliberate.Do not submit credentials, match keys, full authorization headers, or unnecessary personal information. Crash and log payloads are visible to the owning SDK app in the portal.
Match reports are a separate source.RIVE currently reports through the match-report pipeline rather than KiwiSdk.Analytics. Its dashboard reads match players, damage, healing, deaths, and distinct matches. Its raw Events view may therefore be empty, and match history is not copied into generic events.

Realtime

First-party multiplayer foundations

The current realtime layer exposes low-level Socket.IO subscriptions plus convenience emitters for friends, presence, lobbies, and matchmaking. It is shaped by Kiwi Studios' first-party integration, not yet a general-purpose multiplayer contract.

  • Subscribe to events before calling ConnectAndIdentify.
  • Friends are account-global. Presence, lobbies, queue state, and matches are scoped to the configured app and environment.
  • Multiple handlers may subscribe to the same event. Use Off(eventName, handler) to remove one or Off(eventName) to remove all.
  • ConnectAndIdentify returns a KiwiResponse, accepts cancellation, and uses the configured authentication timeout.
  • Reconnects emit state callbacks and automatically re-identify with the last supplied session. Dispose the client during SDK shutdown.
  • Use JObject for presence and lobby payloads in new integrations. Current convenience DTOs do not cover every live backend shape.
Subscribe before identify
using Cysharp.Threading.Tasks;
using KiwiStudios.Sdk;
using Newtonsoft.Json.Linq;
using System.Threading;
using UnityEngine;

public sealed class KiwiRealtimeBootstrap
{
	public async UniTask Connect(string _userId, string _token, CancellationToken _ct)
	{
		KiwiSdk.Realtime.OnAuthFailed += _error => Debug.LogError(_error);
		KiwiSdk.Realtime.On("lobby:members_updated", _json =>
		{
			JObject _lobby = KiwiRealtimeClient.DeserializePayload<JObject>(_json);
			Debug.Log(_lobby);
		});

		KiwiResponse _response = await KiwiSdk.Realtime.ConnectAndIdentify(_userId, _token, _ct);
		if (!_response.Result)
		{
			Debug.LogError(_response.Message);
		}
	}
}

Queue options, game-mode fields, ranked rules, allocation payloads, and several response shapes still reflect the current first-party integration. Validate the exact wire payloads in a test environment before building reusable gameplay UI around them.

Trusted server

Consume the one-time match key once

The allocated match supplies a match ID and one-time match authentication key. The report must match the allocated app and environment and arrive while the match is running. Duplicate player IDs are rejected.

The allocated roster must be complete.Duplicate player IDs and reports missing any allocated player are rejected before the match key is consumed. Unexpected IDs are logged as possible bots, the report may continue, and those IDs are excluded from authoritative player-stat writes.
A successful report consumes the key.Retries after acceptance return an already-used response. Persist enough server-side state to distinguish an accepted report from a network failure before retrying.
Submit from the game server
var _report = new KiwiMatchReportPayload
{
	MatchId = _matchId,
	MatchAuthKey = _matchAuthKey,
	GameMode = _gameMode,
	Map = _map,
	AnalyticsData = _analyticsData,
	GameData = _gameData
};

KiwiResponse _response = await KiwiSdk.MatchReport.SendReport(_report);

The package writes SdkAppId and Environment from the active config before sending. Match and player payload models remain tied to the current first-party allocation contract.

Backend and portal

Operate each app and environment as a data boundary

The SDK Portal can export or delete one player's app-scoped data, set telemetry retention, apply retention immediately, create encrypted logical snapshots, restore an exact snapshot with explicit confirmation, and track public or internal incidents. Account settings also provide account-wide export and deletion for players who do not own SDK apps.

Privacy requestsExports include cloud data, economy, achievements, statistics, telemetry, and diagnostics. Deletions stage physical files and restore them if the database transaction fails.
RetentionConfigure per-environment analytics, crash, log, match, and completed privacy-export retention, then review the deletion counts returned by each run.
RecoverySnapshots are gzip-compressed, AES-256-GCM encrypted, checksummed, scoped to one app environment, and require RESTORE:<snapshot-id>.
ResponseLiveness and database readiness endpoints separate process health from dependency health; app incidents can be published, monitored, resolved, or kept internal.
Backups need production key management.Configure a unique 32-byte backup key, protect and rotate it through the server secret store, copy encrypted snapshots off-host, test restoration regularly, and alert on any cleanup_pending privacy request or restored_cleanup_pending restore.

These controls are portal and backend features. They do not require a Unity package update and do not change live RIVE request payloads.

Release boundary

Deploy backend capability before opting a game into 0.4

  1. 1
    Keep RIVE pinned

    Leave the live game on kiwi-sdk-v0.3.0. Do not replace that tag or publish 0.4.0-preview.1 under a stable version.

  2. 2
    Configure backend dependencies

    Set the backup key, identity provider audiences and credentials, receipt-verifier endpoints, and monitoring before enabling the corresponding product surface.

  3. 3
    Deploy additive backend routes

    Existing authentication, cloud-save, config, and match-report payloads remain accepted. Keep economy purchase entry points disabled until receipt validation is ready.

  4. 4
    Test 0.4 in a separate RIVE branch

    Verify login recovery, anonymous-secret persistence, catalog purchases, targeted config, leaderboard reads, and legacy match reports in dev before updating the game.

  5. 5
    Publish and promote deliberately

    Create a new immutable package tag only after the backend and game checks pass, then promote the game through staging before production.

Reference

Check the result before reading data

Write-style calls return KiwiResponse. Typed reads return KiwiResult<T>. A failed response is data, not an exception contract: inspect Result, retain StatusCode, and show a product-safe message.

Typed result handling
KiwiResult<KiwiCloudSaveLoadResponse> _result =
	await KiwiSdk.CloudSave.LoadUserData(_userId, _token);

if (!_result.Result)
{
	Debug.LogWarning($"cloud save failed ({_result.StatusCode}): {_result.Error}");
	return;
}

KiwiCloudSaveLoadResponse _save = _result.Data;

The package retries transient failures only for retry-safe reads, using bounded exponential backoff. Authentication, analytics, increments, uploads, match reports, and other side-effecting writes are not retried automatically. Treat validation failures, quota errors, cloud-save 409 conflicts, and consumed match keys as state that requires a different action.

Reference

Know which side is authoritative

Value or surfaceBoundary
SDK app ID and environmentPublic client configuration; together they select the tenant boundary.
Player session tokenSensitive account credential. KiwiSecureSessionStore uses native platform credential storage; PlayerPrefs remains compatibility-only.
Match authentication keyOne-time game-server credential for one allocated match report.
Protected user dataClient-writable in the current Kiwi contract.
Private user dataNot player-writable through the normal endpoint, but returned to its owning player.
AchievementsClient-authoritative; unsuitable for trusted rewards.
EconomyServer-authoritative transaction ledger in the staged 0.4 preview. Real-money entry points require configured receipt verification.
Competition writesPortal or allocated match-server authority only. Player clients receive read APIs.
Anonymous device secretInstallation credential. Persist it only through native secure storage and never submit it to telemetry.
  • Never put secrets in remote config, analytics, logs, crash payloads, achievements, or cloud save.
  • Validate game-impacting values on a trusted server before granting competitive or paid outcomes.
  • Use separate apps for separate games and separate environments for the delivery lifecycle.
  • Collect only the player data your game needs and disclose telemetry in your player-facing privacy materials.

Reference

Available and staged client surfaces

ClientCurrent useStatus
AuthKiwi account registration, two-step login, rotating session restore, and opt-in offline identityPreview
RemoteConfigPublished environment JSON with encrypted local cachePreview
CloudSaveShallow-merged user data and version-checked bounded file slotsPreview
Analytics / CrashExplicit events, queued batches, manual crash reports, and logsPreview
AchievementsClient progress for lightweight goals and server-authoritative statistic rules for competitive goalsMixed authority
Realtime / Friends / Presence / Lobby / MatchmakerSocket.IO and first-party multiplayer foundationsFirst-party preview
MatchReportOne-time authenticated report from an allocated game serverFirst-party preview
InventoryKiwi wallet and inventory readsFirst-party only
IdentityAnonymous/device, Apple, Epic, Google, Steam, and identity linking0.4 staged
EconomyCatalog, balances, inventory, virtual purchases, receipt purchases, and transaction history0.4 staged
CompetitionPlayer statistics, leaderboard reads, seasons, and tournaments0.4 staged
RemoteConfig.FetchTargetedBuild and custom targeting attributes plus rule and experiment metadata0.4 staged

Preview APIs, quotas, payloads, and availability can change before a stable release. Pin the package version and verify release notes before updating a project.

Support

Bring an app ID and a reproducible case

For package access or integration help, include the SDK version, Unity version, app ID, environment, failing client method, status code, and a redacted response. Never send a session token or match key.

Available package 0.3.0 · Staged package 0.4.0-preview.1 · Updated July 13, 2026

Kiwi SDK documentation

Search documentation