Drop Playloop into the engine you already ship with. Your next playtest lands in the dashboard as a plain-English playthrough report, where players stalled, what they skipped, which build broke pacing. No video, no manual upload.
C# · Unity 2021 LTS+
Drop Playloop into your Unity game. Track() what players do, get back a plain-English playthrough report.
# Unity → Window → Package Manager → + → Install package from git URL https://github.com/playloop/sdk-unity.git
using Playloop;
var client = new PlayloopClient(new PlayloopOptions {
ApiKey = "YOUR_API_KEY",
});
client.Telemetry.StartSession(new() {
{ "build", "0.5.0" },
});
client.Telemetry.AutoBatch();
// Anywhere in your game:
client.Telemetry.Track("unit_purchased", new() {
{ "unit_id", "skeleton" },
{ "cost", 50 },
});C++ · Blueprints · Unreal 5.3+
Drop Playloop into your Unreal 5 game. Track() what players do from C++ or Blueprints, get back a plain-English playthrough report.
git clone https://github.com/playloop/sdk-unreal.git YourProject/Plugins/PlayloopSDK
#include "PlayloopClient.h"
UPlayloopClient* Client = NewObject<UPlayloopClient>(GetGameInstance());
FPlayloopConfig Config;
Config.ApiKey = TEXT("YOUR_API_KEY");
Config.GameSlug = TEXT("your-game-slug");
Client->Configure(Config);
Client->Start();
// Anywhere in your game (C++ or Blueprint):
Client->Track(TEXT("unit_purchased"),
TEXT("{\"unit_id\":\"skeleton\",\"cost\":50}"));
// A/B experiments (set Config.GameId first):
Client->Experiments()->VariantAsync(TEXT("exp_tutorial_v2"),
FOnPlayloopVariantResolved::CreateLambda([](const FString& V) {
// V is "" when no variant / not running (Unreal's stand-in for null).
if (V == TEXT("treatment")) { /* ... */ }
}));GDScript · Godot 4.4+
Add Playloop to your Godot project. One addon, one autoload, and your next playtest is recorded.
cp -R sdk-godot/addons/playloop res://addons/playloop
var client = Playloop.new(self)
client.configure({
"api_key": "YOUR_API_KEY",
})
client.telemetry.start_session({ "build": "0.5.0" })
client.telemetry.auto_batch()
# Anywhere in your game:
client.telemetry.track("unit_purchased", {
"unit_id": "skeleton",
"cost": 50,
})CPython 3.10+
Stream telemetry from QA bots, CI runs, or batch imports, anywhere you have events but no game runtime.
pip install playloop
import asyncio, os
from playloop import Playloop
async def main():
async with Playloop(
api_key=os.environ["PLAYLOOP_INGEST_KEY"],
device_id="qa-bot-01",
game_id="game_abc123", # enables A/B experiments
) as client:
client.telemetry.start_session({
"runner": "ci",
"build": "0.5.0",
})
# Async, never raises; None when not running.
variant = await client.experiments.variant("exp_tutorial_v2")
client.telemetry.track("level_completed", {
"level": 3, "deaths": 0, "variant": variant,
})
client.end_session()
asyncio.run(main())Node · Bun · browser
Tell Playloop what your TypeScript game just did. Runs in Node, Bun, Deno, or the browser.
npm install @playloop/sdk
import { Playloop } from '@playloop/sdk'
const client = new Playloop({
apiKey: process.env.PLAYLOOP_INGEST_KEY!,
})
client.telemetry.startSession({ build: '0.5.0' })
client.telemetry.track('level_completed', {
level: 3, deaths: 0,
})
await client.endSession()Every SDK ships linkTester, getCurrentTester, and unlinkTester. A tester pastes their pl_tt_… token once and every session from that device tags with their handle. Optional, skip it if anonymous telemetry is enough.
Every SDK ships a session-state accumulator (client.state.setState in TypeScript; the same call follows each language's conventions, e.g. set_state in Python and Godot). The SDK ships the full snapshot on every session_heartbeat (60s default, 30s floor) and once on session_summary; that final snapshot becomes the AI digest's top resolution block. Pair it with per-event flags (sdkIgnore, linkToSummary, hideFromAi) the SDK pulls from GET /api/v1/games/<slug>/event-config on startup. Edit the flags from the dashboard or, in Unity and Godot, from the in-engine inspector. Same canonical rows.
Each SDK repo ships skill files for the major coding agents so they pick up Playloop's conventions on first touch, env-keyed API keys, the “things to never break” list, and the test patterns.
| Format | Path in each repo | Picked up by |
|---|---|---|
| Claude Code Skill | .claude/skills/<name>/SKILL.md | Claude Code |
| Codex Skill | .agents/skills/<name>/SKILL.md | OpenAI Codex CLI |
| Cursor Rule | .cursor/rules/<name>.mdc | Cursor |
| AGENTS.md | repo root | Cross-tool baseline (Aider, Continue, Copilot, Windsurf, & more) |
The Claude Code and Codex SKILL.md files are byte-identical (both follow the Agent Skills open standard). Full org index: github.com/playloop.
These docs are evolving. Playloop is in active development ahead of launch, so APIs and details may change as we polish.