Linkzly

SDKs

Linkzly provides SDKs to make it easier to send gaming events from your app or game. The SDKs handle event batching, retry logic, session management, and HMAC r

11 min read

SDKs

Linkzly provides SDKs to make it easier to send gaming events from your app or game. The SDKs handle event batching, retry logic, session management, and HMAC request signing so you do not have to build that infrastructure yourself.

When to use the SDK: Use the SDK when you are integrating from inside a game or app. The SDK batches events automatically, manages sessions in the background, and queues events during network outages.

When to use the REST API directly: Use the REST API when you are integrating from a server, a script, or a platform where no SDK is available. You construct and send HTTP requests manually.


17.1 Android SDK (Kotlin)

Installation

Add the Linkzly Gaming dependency to your app-level build.gradle file:

dependencies {
    implementation 'com.linkzly:gaming-tracking:LATEST_VERSION'
}

Replace LATEST_VERSION with the version listed in the Linkzly SDK release notes.

The SDK requires a minimum Android API level as documented in the release notes for each version.

Finding Your SDK Key

Your SDK key is available in the Linkzly console under Game Settings โ†’ SDK Configuration โ†’ SDK Key. Navigate to /dashboard/gaming/[gameId]/settings to find it. The SDK key is masked by default; use the eye icon to reveal it or the copy button to copy it to your clipboard.

Initialization

Call LinkzlyGamingTracking.configure() once, early in your application lifecycle (for example, in Application.onCreate()):

LinkzlyGamingTracking.configure(context, GamingOptions(
    apiKey = "YOUR_SDK_KEY",
    organizationId = "YOUR_ORG_ID",
    gameId = "YOUR_GAME_ID"
))

Your SDK key, organization ID, and game ID are all available from the Gaming Intelligence settings page in the Linkzly console.

Configuration Options

Parameter Type Default Description
apiKey String required Your game's SDK key from the Linkzly console
organizationId String required Your organization ID
gameId String required Your game ID
baseUrl String https://gaming.linkzly.com API base URL; override only if using a custom deployment
sdkVersion String auto SDK version string; set automatically
gameVersion String required Your game's version string (e.g., 2.1.0)
maxBatchSize Int 100 Maximum events per batch. Range: 1โ€“100
maxBatchBytes Int 524288 Maximum batch payload size in bytes. Range: 1,024โ€“524,288 (512 KB)
flushIntervalMs Long 5000 How often the SDK sends queued events, in milliseconds. Range: 500โ€“5,000
maxRetries Int 3 Retry attempts on a failed send. Range: 0โ€“3
retryDelayMs Long 1000 Delay between retry attempts in milliseconds. Range: 250โ€“1,000
maxQueueSize Int 10000 Maximum events held in the queue before overflow. Range: 10โ€“10,000
sessionTimeoutMs Long 1800000 Inactivity duration before a session ends. Minimum: 30 minutes (1,800,000 ms)
autoSessionTracking Boolean true Automatically send session_start and session_end events
signingSecret String? null HMAC signing secret; required if HMAC Signing is enabled in Game Settings
debug Boolean false Enable verbose debug logging in Logcat
includeTraits Boolean false Attach player traits to every event payload

Core Methods

Method Description
identify(playerId, traits?) Set the current player's identity. Pass optional key-value traits (age range, segment, etc.). Call this after login.
track(eventType, data?, immediateFlush?) Track a custom event. data is an optional key-value object. Set immediateFlush = true to send without waiting for the next batch.
startSession() Manually start a new session. Only needed if autoSessionTracking = false.
endSession() Manually end the current session. Only needed if autoSessionTracking = false.
setAttribution(clickId?, deferredDeepLink?, metadata?) Set attribution data for the current player, used to tie installs back to campaigns.
clearAttribution() Remove stored attribution data.
flush(reason, callback?) Force-send all queued events immediately. Useful before the app closes.
reset() Tear down the SDK and clear the player identity and event queue. Call on logout.
getPendingCount() Returns the number of events currently waiting in the queue.
hasInflightBatch() Returns true if a batch is currently in transit to the server.

Automatic Session Tracking

When autoSessionTracking = true (the default), the SDK manages sessions for you:

  • A session_start event is sent automatically when the app comes to the foreground.
  • A session_end event is sent when the app goes to the background, after the inactivity timeout defined by sessionTimeoutMs.
  • Each session receives a unique UUID as its session_id.

You do not need to call startSession() or endSession() manually unless you have set autoSessionTracking = false.

The SDK also flushes queued events automatically based on the following triggers: BATCH_FULL, TIME_INTERVAL, SESSION_END, APP_BACKGROUND, MANUAL_FLUSH, QUEUE_OVERFLOW, ERROR_RECOVERY, and STARTUP_RECOVERY.

Event Types

The following event types are natively understood by the ingestion pipeline. Field values are case-insensitive.

Core events:

Event Type Description
session_start Session began. Sent automatically when autoSessionTracking = true.
session_end Session ended. Sent automatically when autoSessionTracking = true.
app_install First-time app installation detected.
app_open App brought to the foreground.
app_close App sent to the background or terminated.

Gaming events:

Event Type Description
level_start Player started a level.
level_complete Player completed a level.
achievement_unlocked Player unlocked an achievement.
tutorial_complete Player completed the tutorial.
currency_spent In-game currency was spent.
currency_earned In-game currency was earned.
item_purchased Player purchased an item.
battle_won Player won a battle or match.
tournament_join Player joined a tournament.
friend_invited Player invited a friend.

Monetization events:

Event Type Description
purchase Real-money purchase completed.
subscription_start Subscription started.
subscription_renew Subscription renewed.
subscription_cancel Subscription cancelled.
ad_watched Player watched an ad.

Custom events:

For events that do not match a built-in type, use event_type: 'custom' and include the specific event name inside the data object:

{
  event_type: 'custom',
  data: {
    custom_event_name: 'boss_defeated',
    boss_id: 'dragon-king',
    difficulty: 'hard'
  }
}

17.2 Web / JavaScript SDK

For web games and browser-based integrations, use the standard fetch API with the correct headers. There is no npm package to install โ€” use the fetch-based approach below directly.

Initialization

Set up a client object with the required headers:

const client = {
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${SDK_KEY}`,
    'X-Organization-ID': ORG_ID,
    'X-Game-ID': GAME_ID,
  }
};

Replace SDK_KEY, ORG_ID, and GAME_ID with the values from your game's settings page in the Linkzly console. Your SDK key is located at Game Settings โ†’ SDK Configuration โ†’ SDK Key (/dashboard/gaming/[gameId]/settings).

Sending Events

Post events to the ingestion endpoint:

await fetch('https://gaming.linkzly.com/api/v1/gaming/events', {
  method: 'POST',
  headers: client.headers,
  body: JSON.stringify({
    events: [{
      event_id: crypto.randomUUID(),
      event_type: 'session_start',
      timestamp: new Date().toISOString(),
      player_id: 'player-001',
      session_id: 'session-uuid',
      platform: 'web',
      data: {},
    }],
  }),
});

The endpoint accepts an array of events in a single request. For the full list of event object fields, see Section 8.9 of the documentation.

Response Format

The ingestion endpoint returns 202 Accepted with a summary:

{
  "success": true,
  "batch_id": "...",
  "events_received": 5,
  "events_valid": 5,
  "events_dropped": 0,
  "trace_id": "...",
  "server_timestamp": "2025-01-01T00:00:00Z"
}
  • batch_id โ€” Unique identifier for this batch
  • events_received โ€” Total events in the payload
  • events_valid โ€” Events that passed validation
  • events_dropped โ€” Events that failed validation (use trace_id for debugging)

Batch Validation Limits

The ingestion endpoint enforces the following limits per request:

Limit Value
Maximum events per batch 1,000
Maximum size per event 10 KB
Maximum request body size 1 MB
Maximum events per player per batch 100
Maximum data object nesting depth 3 levels
Maximum timestamp age 24 hours in the past
Maximum timestamp future skew 5 minutes in the future

Events that exceed these limits are dropped and counted in events_dropped. The rest of the batch is still processed.

Rate Limiting

The ingestion endpoint allows 1,000 requests per minute with a burst allowance of 200 requests. Requests exceeding the rate limit receive 429 Too Many Requests.


17.3 Unity SDK (C#)

For Unity games, use UnityWebRequest to send events to the ingestion endpoint.

Sending Events via UnityWebRequest

IEnumerator SendEvent() {
    var payload = JsonUtility.ToJson(new { events = new[] { /* event object */ } });
    var request = new UnityWebRequest(BASE_URL + "/api/v1/gaming/events", "POST");
    request.SetRequestHeader("Authorization", "Bearer " + SDK_KEY);
    request.SetRequestHeader("X-Organization-ID", ORG_ID);
    request.SetRequestHeader("X-Game-ID", GAME_ID);
    request.SetRequestHeader("Content-Type", "application/json");
    request.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(payload));
    request.downloadHandler = new DownloadHandlerBuffer();
    yield return request.SendWebRequest();
}

Set BASE_URL to https://gaming.linkzly.com and replace SDK_KEY, ORG_ID, and GAME_ID with your game's credentials from the Linkzly console (available at Game Settings โ†’ SDK Configuration โ†’ SDK Key).

Use JsonUtility.ToJson to serialize your event object before sending. The request is a coroutine โ€” call it using StartCoroutine(SendEvent()) from your MonoBehaviour.


17.4 React Native SDK

The React Native SDK supports both iOS and Android from a single codebase.

Initialize the SDK with your apiKey, organizationId, and gameId. The SDK automatically detects the platform and sets it to ios or android based on the device.

The React Native SDK exposes the same core methods as the Android SDK:

  • identify(playerId, traits?)
  • track(eventType, data?, immediateFlush?)
  • startSession()
  • endSession()

Refer to the Android SDK section for method descriptions. Initialization parameters and behavior are identical.


17.5 Supported Platforms

Platform SDK / Language
Android Kotlin / Java
iOS Swift / Objective-C / React Native
Web JavaScript / TypeScript
Unity C# (UnityWebRequest)
Unreal Engine C++ / Blueprint
Steam C++ / Steamworks SDK
PlayStation C++ (PS SDK integration)
Xbox C++ (GDK integration)
Nintendo Switch C++ (NX SDK)
Epic Games Store C++ (EOS SDK)
Discord Activities JavaScript

For platforms not listed above, use the REST API directly by sending HTTP POST requests to the ingestion endpoint with the required headers.


17.6 HMAC Request Signing

HMAC signing adds an extra layer of security by letting the Linkzly ingestion API verify that each request actually came from your game and was not tampered with in transit.

HMAC Signing is enabled by default for all new games. You can disable it in Game Settings โ†’ Security Settings โ†’ HMAC Signing Required if you need to temporarily send unsigned requests (not recommended for production).

When to Use It

Use HMAC signing whenever your game sends events from a client (browser, mobile app, game client). It prevents third parties from injecting fake events into your analytics by forging requests.

Required Headers

When HMAC signing is enabled, every ingestion request must include three additional headers in addition to the standard authentication headers:

Standard authentication headers (always required):

Header Description
Authorization Bearer <SDK_KEY> โ€” your game's SDK key
X-Organization-ID Your organization ID
X-Game-ID Your game ID

HMAC signing headers (required when HMAC is enabled):

Header Description
X-Signature-256 The HMAC-SHA256 signature of the request, hex-encoded
X-Timestamp The current Unix timestamp in milliseconds
X-Nonce A UUID v4 one-time nonce to prevent replay attacks

How the Signature Is Computed

Concatenate the timestamp, nonce, and raw request body with dots, then compute an HMAC-SHA256 hash using your signing secret:

HMAC-SHA256(signingSecret, "{timestamp}.{nonce}.{bodyString}")

The result is hex-encoded and sent as the X-Signature-256 header value.

Your signing secret is available in Game Settings โ†’ SDK Configuration. Treat it like a password โ€” do not include it in client-side code that is publicly visible.

Replay Protection

Linkzly checks the X-Timestamp value against the server's current time. Requests with a timestamp outside the replay window are rejected with 401 Unauthorized.

The replay window is fixed at 300 seconds (5 minutes). This value is not configurable.

Each nonce is stored for 60 seconds after it is first seen. If the same nonce is submitted again within that window, the request is rejected with 401 Unauthorized. This ensures that even a legitimately signed request cannot be replayed successfully within the replay window.

To avoid rejection:

  • Generate a new UUID v4 nonce for every request.
  • Ensure your device clock is reasonably synchronized (within 5 minutes of UTC).

Was this helpful?

Help us improve our documentation