Gamearly API v1
Dashboard

Ownership & anti-piracy / Launch context

Launch context#

Every time the Gamearly launcher starts your game, it sets a group of GAMEARLY_* environment variables on your game's process. Together they describe how the launch was authorized: who the player is, whether we could verify them right now, and if not, why not.

They are plain, individual environment variables — not a JSON blob — so reading any one of them is a single line in any engine, with no parsing.

Read this first

Only GAMEARLY_LAUNCH_TOKEN is authoritative: it is cryptographically signed and verified by our servers. Every other variable is advisory. They are unsigned text, and anyone can set them by hand before running your executable.

Use them to decide user experience and to understand why a token is missing. Never use them, on their own, to grant access to anything you care about.

Always present#

Variable Values Meaning
GAMEARLY_LAUNCHER 1 Gamearly started this process. If this variable is absent, the launcher was not involved at all.
GAMEARLY_CONTEXT_VERSION 1 Version of this variable set. Ignore values you don't recognize; we only bump it if the meaning of an existing variable changes.
GAMEARLY_ENV production / staging / local Which Gamearly environment launched you.
GAMEARLY_GAME_ID integer Your game id.
GAMEARLY_TOKEN_STATUS see table below Whether a token was issued, and if not, why.
GAMEARLY_ACCESS_STATE ok / unknown ok if we have confirmed this player's access online — now, or on a previous launch.
GAMEARLY_ONLINE 1 / 0 / unknown Whether the machine had connectivity at launch.

Present when we know them#

Variable Values Meaning
GAMEARLY_LAUNCH_TOKEN signed JWT The launch token. Present only when GAMEARLY_TOKEN_STATUS=ok.
GAMEARLY_TOKEN_EXPIRES_AT unix seconds When the token stops verifying.
GAMEARLY_USER_ID uuid The Gamearly user. Set whenever we know who is signed in — including when no token could be issued. Advisory until confirmed by /launch_tokens/verify.
GAMEARLY_LAST_VERIFIED_AT unix seconds The last time we confirmed this player's access online, for this channel. Absent if we never have.
GAMEARLY_INSTALLATION_ID uuid Stable id for this install on this device. Occasionally absent in the first few seconds after the launcher starts.
GAMEARLY_CHANNEL_ID string The build channel launched — main, demo, DLC, beta …
GAMEARLY_BUILD_ID string The exact build.
GAMEARLY_BUILD_VERSION e.g. 1.4.2 Version string of that build.
GAMEARLY_LAUNCHER_VERSION e.g. 1.8.2 The launcher's own version.

Token status values#

Value Meaning Recommended handling
ok A token is attached. Verify it server-side.
offline The machine has no connectivity, so we couldn't request one. Apply your offline policy — see the grace period in Enforcement.
server_error Gamearly was reachable but failed. Treat exactly like offline. Never punish a player for our outage.
auth_expired The player's Gamearly session expired. Treat like offline. You may prompt them to sign in to Gamearly.
not_entitled Gamearly says this player does not own this channel. The one status worth refusing even if you're lenient about offline.
no_channel Launch metadata was incomplete. Should not happen. Treat like unknown.
unknown Unclassified failure. Treat like offline.

GAMEARLY_LAUNCH_TOKEN is set only for ok. For every other status there is no token to verify — the status is telling you why.

The distinction that matters most#

GAMEARLY_LAUNCHER is set     ->  Gamearly started your game.
                                 Read GAMEARLY_TOKEN_STATUS to learn how much we could verify.

GAMEARLY_LAUNCHER is absent  ->  Your executable was started directly: from Explorer, from a
                                 copied folder, by a script, or by another launcher. None of
                                 the guarantees on this page apply.

Worked examples#

You have a token; verify it and enforce fully.

GAMEARLY_LAUNCHER=1
GAMEARLY_CONTEXT_VERSION=1
GAMEARLY_ENV=production
GAMEARLY_GAME_ID=42
GAMEARLY_TOKEN_STATUS=ok
GAMEARLY_ACCESS_STATE=ok
GAMEARLY_ONLINE=1
GAMEARLY_LAUNCH_TOKEN=eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...
GAMEARLY_TOKEN_EXPIRES_AT=1755865260
GAMEARLY_USER_ID=8a8c0198-6e85-4fa3-8c7f-9f6d43bcb8b2
GAMEARLY_LAST_VERIFIED_AT=1755865200
GAMEARLY_INSTALLATION_ID=2b1f9c44-77e3-4a0e-9d31-6c8a5f2e10bd
GAMEARLY_CHANNEL_ID=chn_9f3a21
GAMEARLY_BUILD_ID=bld_7c41de
GAMEARLY_BUILD_VERSION=1.4.2
GAMEARLY_LAUNCHER_VERSION=1.8.2

No token exists to verify, but you know who they are and when we last confirmed their access — five days ago here. Under a 14-day grace window, let them play.

GAMEARLY_LAUNCHER=1
GAMEARLY_CONTEXT_VERSION=1
GAMEARLY_ENV=production
GAMEARLY_GAME_ID=42
GAMEARLY_TOKEN_STATUS=offline
GAMEARLY_ACCESS_STATE=ok
GAMEARLY_ONLINE=0
GAMEARLY_USER_ID=8a8c0198-6e85-4fa3-8c7f-9f6d43bcb8b2
GAMEARLY_LAST_VERIFIED_AT=1755432000
GAMEARLY_INSTALLATION_ID=2b1f9c44-77e3-4a0e-9d31-6c8a5f2e10bd
GAMEARLY_CHANNEL_ID=chn_9f3a21
GAMEARLY_BUILD_ID=bld_7c41de
GAMEARLY_BUILD_VERSION=1.4.2
GAMEARLY_LAUNCHER_VERSION=1.8.2

We were online and we asked; the answer was no. Note GAMEARLY_ACCESS_STATE=unknown and the absence of GAMEARLY_LAST_VERIFIED_AT — we have never confirmed access for this player. This is the case to refuse.

GAMEARLY_LAUNCHER=1
GAMEARLY_CONTEXT_VERSION=1
GAMEARLY_ENV=production
GAMEARLY_GAME_ID=42
GAMEARLY_TOKEN_STATUS=not_entitled
GAMEARLY_ACCESS_STATE=unknown
GAMEARLY_ONLINE=1
GAMEARLY_USER_ID=8a8c0198-6e85-4fa3-8c7f-9f6d43bcb8b2
GAMEARLY_INSTALLATION_ID=2b1f9c44-77e3-4a0e-9d31-6c8a5f2e10bd
GAMEARLY_CHANNEL_ID=chn_9f3a21
GAMEARLY_BUILD_ID=bld_7c41de
GAMEARLY_BUILD_VERSION=1.4.2
GAMEARLY_LAUNCHER_VERSION=1.8.2

Someone opened your .exe from Explorer, or copied the install folder to a machine that has no Gamearly. There is nothing at all:

(no GAMEARLY_* variables are set)

Reading it#

Call GamearlyLaunch.Init() early, e.g. in a bootstrap MonoBehaviour.Awake.

using System;
using UnityEngine;

public static class GamearlyLaunch {
    public static bool   ViaLauncher  { get; private set; }
    public static string Token        { get; private set; }
    public static string TokenStatus  { get; private set; }
    public static string UserId       { get; private set; }
    public static long   LastVerified { get; private set; }   // unix seconds, 0 = never
    public static bool   IsOnline     { get; private set; }

    public static bool HasToken => !string.IsNullOrEmpty(Token);

    static string Env(string key) => Environment.GetEnvironmentVariable(key);

    public static void Init() {
        ViaLauncher  = Env("GAMEARLY_LAUNCHER") == "1";
        Token        = Env("GAMEARLY_LAUNCH_TOKEN");
        TokenStatus  = Env("GAMEARLY_TOKEN_STATUS") ?? "unknown";
        UserId       = Env("GAMEARLY_USER_ID");
        IsOnline     = Env("GAMEARLY_ONLINE") == "1";

        long.TryParse(Env("GAMEARLY_LAST_VERIFIED_AT"), out long lastVerified);
        LastVerified = lastVerified;

        // Never block boot here. Gate online features on the VERIFIED result instead.
        Debug.Log($"[Gamearly] launcher={ViaLauncher} tokenStatus={TokenStatus}");
    }

    // Send Token to YOUR backend, which calls
    // POST https://api.gamearly.com/v1/launch_tokens/verify with your X-Api-Key.
}

For example in your GameInstance init.

const bool bViaLauncher =
    FPlatformMisc::GetEnvironmentVariable(TEXT("GAMEARLY_LAUNCHER")) == TEXT("1");
const FString Token  = FPlatformMisc::GetEnvironmentVariable(TEXT("GAMEARLY_LAUNCH_TOKEN"));
const FString Status = FPlatformMisc::GetEnvironmentVariable(TEXT("GAMEARLY_TOKEN_STATUS"));

if (!bViaLauncher) {
    UE_LOG(LogTemp, Log, TEXT("[Gamearly] Direct launch; continuing (fail-open)."));
} else if (Token.IsEmpty()) {
    UE_LOG(LogTemp, Log, TEXT("[Gamearly] No token (%s); applying offline policy."), *Status);
} else {
    // POST Token to YOUR backend -> it calls .../launch_tokens/verify.
    // Gate online services on the result.
}
func _ready():
    var via_launcher := OS.get_environment("GAMEARLY_LAUNCHER") == "1"
    var token        := OS.get_environment("GAMEARLY_LAUNCH_TOKEN")
    var status       := OS.get_environment("GAMEARLY_TOKEN_STATUS")

    # token may be empty (offline, or a direct launch) — never abort here.
    # Verify server-side and gate only online features.