Ravensight

Developer docs

Everything you need to send events and ask questions about them.

SDKs for Godot, Unity, Unreal, web, native mobile, C++ and Odin, the HTTP API for everything else, the MCP server for your own agents, the run_sql tool for when you want the number yourself, the Playtest CLI for sending AI personas through your build, and the studio context graph that keeps every answer you get.

1. Quickstart

From zero to your first event, in about five minutes

Ravensight is hosted. You do not run a server, you point your game at ours.

  1. Create an account. Sign in at https://app.ravensight.io through RealitySE, the identity system Ravensight runs on. Use email and password, or one of the SSO providers: Apple, Google, Facebook, GitHub, Twitch, Xbox, or Steam.
  2. Create a project. A project is one title, and it holds one game per environment. The first time you sign in the dashboard asks for a name, an id and an engine, and creates the project with its production environment in one step. Every feature is available right away, no upgrade required. See Projects and environments for the shape.
  3. Copy the ingest key. Each environment has its own. It is shown once on the confirmation screen and looks like gt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. It is publishable: safe to ship inside your game binary, since it can only create sessions, read the tracking on/off switch and the AI suggestions feed, submit player reports and submit doctor reports. It cannot read analytics or manage your account. If you lose it, rotate it from Settings > Projects for a new one.
  4. Add the autoload. Copy Ravensight.gd into your Godot project, e.g. res://autoload/Ravensight.gd. Open Project > Project Settings > Autoload, add the script, name it Ravensight, and enable it. In the Inspector, set api_url to your Ravensight base URL (no trailing slash, no /api/v1) and ingest_key to the key from step 3.
  5. Send your first event. Call track_event() from anywhere in your game.
  6. See the dashboard. Pick your project in the switcher, and the environment beside it if the project has more than one. The SDK batches and sends events shortly after you call track_event(), so they typically show up within a few seconds, no restart needed.

Godot, res://autoload/ravensight.gd

Ravensight.track_event("level_completed", {
    "level": 3,
    "score": 15000,
    "time_seconds": 87.4
})

Not on Godot? The same account and ingest key work against the plain HTTP API: three headers and a JSON body from any engine or client that can make a POST request.

2. Projects and environments

One title, one project, one game per environment

Your development build and your shipped build must not share an event stream, or a week of debugging quietly becomes your retention number. Ravensight keeps them apart by making each one its own game, and groups the games of one title into a project.

The three scopes

ScopeWhat lives there
Environment, one game Its own ingest key, its own tracking and history switches, and its own events, sessions, players, funnels, journeys, retention, reports and digests. Labels are fixed: production, staging, development, at most one of each per project.
Project, one title Name and engine, and the environments underneath it. Project-scoped pages read the project rather than one build.
Studio, your org Members and roles, billing and the prepaid balance, the studio context graph, studio notes, cross-game analytics and the audit log.

Picking one

The switcher at the top of the sidebar picks a project. Beside it in the header, on the pages whose numbers come from one build, an environment control picks which environment you are looking at. A project with a single environment needs no second choice, and the pages that belong to the whole project do not show the control at all.

Managing them

Settings > Projects is where projects are renamed, merged, and given new environments. Because every existing game was migrated into a project of its own, two environments of the same title can start out as two projects. Ravensight proposes the merge when their names normalize to the same thing and their environment labels do not collide, and nothing is merged until you accept the proposal. Dismiss one and it stays dismissed. You can also move a single environment from one project to another, or delete a project once it is empty.

Creating, renaming, merging and deleting all need an admin role or above. Everyone in the studio can read the list.

Analytics queries are still keyed on one game, which is why a number on screen always belongs to exactly one environment. A project-level or studio-level number is the same per-game query asked of several games and summed, never a new aggregation with its own rules.

3. The dashboard

What each page is for

The sidebar is grouped by what you are doing rather than by which database the answer comes from. The order below is the order the sidebar puts them in.

Build

Project-scoped: these read the title, not one of its builds.

  • Design. Your design documents, and a chat that has read your studio's findings before it proposes an edit. See Design studio.
  • Code scan. What your code reports against what your telemetry actually receives. See Source scan.
  • Playtest. Jobs, briefs, findings and reports from AI personas playing your build. See Playtest.

Live data

Environment-scoped: every number here comes from the events one build sent. Overview, Player insights and Events each carry an Include AI personas switch, because persona sessions are real rows in the same store and are excluded by default.

  • Overview. Daily active players, top events, lifetime totals, retention, the level funnel and the implementation health card. Results are cached per scope and range, so a repeat visit does not re-run the warehouse queries; a missing or expired snapshot still fetches fresh.
  • Player insights. A triage board of the sessions the backend flagged, with the plain-language signals behind each call. See how the detections read your events.
  • Events. Raw events newest first, filterable by name and paged, with expandable payload rows.
  • Funnels. An ordered sequence of two to eight event names: who reached each step, how many were lost against the step before, and the average and median gap into each one. Count players or sessions, and filter by an event property.
  • Journeys. The level-to-level graph, where players stop, churn-heavy transitions, loops and estimated common paths. Only on deployments with journey graphs configured.
  • Player Reports. The inbox for what players sent from inside the game. See Player Reports. A game without the report overlay sees its free-form feedback here instead, summarized by sentiment and theme and searchable by meaning.

Understand

  • Studio Intelligence. An investigation that ties a question to its evidence to a decision. See Studio Intelligence.
  • AI Analyst. Ask in plain English; it picks its own read-only tools and answers with the numbers it used. Conversations are listable, resumable, renameable and deletable.
  • Studio context. Everything your studio has learned, across every game. See Studio context.

Studio

  • Brainstorm. A board of cards in columns beside a chat with the partner, which has read your studio's own findings, patterns, touchpoints and sales before it answers and can put cards on the board it is sitting at. Start blank, or fill a board from what the studio already knows for one AI unit. See Brainstorm.
  • Marketing. What you did outside the game and the lift the platform measured afterwards. See Marketing memory.
  • Sales. Its own page directly below Marketing in the Studio navigation. Record what each title earned, filter the ledger, compare totals by currency, explore a 90 day launch curve, and import store exports. See the Sales ledger.
  • Audit log. Who did what in the org. Owner and admin only.

In the footer

Settings sits below the groups rather than inside them, because it is global to the account rather than to the selected game. Its tabs are Usage and billing and Payment history (both owner only), Projects, Team, AI Analyst, MCP access and Appearance. The events meter beside it shows this month against the free allowance.

Analyst context you write yourself

Findings are extracted by a model. Analyst context is the opposite: it is what you write, and the analyst is told to trust it over its own reading of the data. There are two levels, both inserted into the prompt verbatim and ahead of the findings. Game context lives in Settings > AI Analyst and holds up to 2,000 characters of facts about one game. Studio notes hold up to 1,000 characters of facts that are true across every game in the studio. A note like "levels 5 through 7 are an intentional difficulty spike" or "we ship weekly builds on Fridays" heads off a wrong conclusion before the analyst reaches for a tool. Writing either needs a member role or above; reading them needs nothing extra.

The same question across every game

Three questions can be asked of the whole studio rather than one game: the headline metrics, a funnel, and an event property's breakdown. The analyst has them as compare_metrics, compare_funnel and compare_property, and the API exposes them under /api/v1/studio/analytics/.... This is how a problem in one game is told apart from a habit of the studio: if the tutorial loses the same share of players in all three of your games, the tutorial design is the finding. Studio totals are sums and conversions are weighted by volume. There is deliberately no studio median, because the median of medians is not the median.

4. Godot SDK reference

Ravensight.gd

Code samples scroll horizontally when needed. Focus a sample and use the arrow keys, or swipe to read a long line.

Player Reports

Add an optional in-game form that captures the current game screen, lets players highlight or hide an area, and sends a short message. Bind the reporting action to a key, controller input or pause-menu button. The dashboard groups reports into issues and tracks fixes through verification.

Download Ravensight.gd, RavensightReports.gd and RavensightReportOverlay.gd. Add the latter two as children of the Ravensight autoload, named RavensightReports and ReportOverlay. Bind ravensight_report in Input Map. The overlay captures only the game viewport and never pauses multiplayer.

Reports use your existing event allowance and prepaid balance automatically. A text report uses 1 event; a screenshot adds 20,000 usage events covering processing, storage and delivery. There is no separate screenshot budget to configure. Failed or canceled uploads release their reserved usage. Retention and file limits are listed in Settings. Text-only reporting remains available if capture or upload fails. Screenshots are not automatically sent to AI providers.

One autoload script. It owns device identification, session creation, batching, retries, and the offline queue, so your game code only ever needs to call track_event().

Exported properties

Set these in the Inspector after adding the autoload.

PropertyTypeDefaultNotes
api_urlStringhttps://your-ravensight-instance.example.comNo trailing slash, no /api/v1: the SDK appends the path itself.
ingest_keyStringgt_live_your_ingest_key_hereThe publishable key from your game's confirmation screen.
game_versionString1.0.0Reported to the server as the client's game version.
max_queue_sizeint100Max unsent events kept in memory. Oldest are dropped first once full.

Public functions

FunctionDescription
track_event(event_name: String, data: Dictionary = {})Queue an event. Safe to call before the session is ready: it is queued and sent once a session exists.
flush()Force an immediate flush attempt. No-op if nothing is queued, no session is ready, or a flush is already in flight.
submit_feedback(message: String, category: String = "", rating: int = 0)Send free-form player feedback. category and rating (1 to 5) are optional. Requires an active session; unlike track_event(), a call made before one exists fails immediately rather than queueing.
fetch_suggestions()Experimental. Requests AI-generated design suggestions for your game; result arrives on the suggestions_received signal.

You can also read Ravensight.tracking_enabled at any time to check whether the server-side kill switch is on.

Signals

SignalFires when
session_readyA session token has been issued and is ready to use.
session_failed(reason: String)Session creation fails outright.
tracking_disabled(source: String)Once, at boot, if the server-side kill switch has tracking off for this game.
events_flushed(count: int)A batch of events is accepted by the server.
flush_failed(reason: String)A batch flush attempt fails. The SDK retries automatically; you do not need to.
feedback_submittedA feedback submission is accepted.
feedback_failed(reason: String)A feedback submission fails, including "no_session" when called too early.
suggestions_received(suggestions: Array)Experimental. Carries the result of fetch_suggestions().
func _ready():
    Ravensight.session_ready.connect(func(): print("ready"))
    Ravensight.session_failed.connect(func(reason): print("session failed: ", reason))
    Ravensight.tracking_disabled.connect(func(source): print("tracking off: ", source))
    Ravensight.events_flushed.connect(func(count): print("sent ", count, " events"))

Offline queue and backoff

Every track_event() call adds to an in-memory queue. The SDK flushes it via POST /api/v1/track/batch, up to 50 events per request, looping until the queue is empty. If the server is unreachable, events stay queued (up to max_queue_size, oldest dropped first once full) and are retried with exponential backoff, starting at 10 seconds and doubling up to a 5 minute cap. If the server responds 429, the SDK backs off using the server's Retry-After value when one is given, and keeps the events queued for the next attempt: you do not need to handle this yourself.

Kill switch

On boot, the SDK calls GET /api/v1/settings once with ingest_key. If tracking is off for your game, it goes idle for that run: no session is created and nothing is sent, and the tracking_disabled signal fires with source "server". Flip trackingEnabled from the dashboard's game settings and it takes effect on the game's next launch, no update required.

5. HTTP API

Building for the web or Node? The JavaScript SDK wraps everything below in a zero-dependency client with batching, an offline queue, and tab-close flushing. Unity developers use the Unity SDK. Everything else speaks plain HTTP.

Ingestion for anything that isn't Godot

The Godot SDK is a client for this same surface. If you're on Unity, Unreal, a browser game, or anything else, this is what to call directly. The ingest endpoints answer any web origin, so browser games on GitHub Pages, itch.io or your own site need no CORS setup.

Base URL

https://api.ravensight.io

POST /api/v1/session

Opens a session for a device. Auth: X-API-Key (your ingest key). The game identity comes from the key, never from the body.

Request

POST /api/v1/session
X-API-Key: gt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "deviceId": "a1b2c3d4-windows-1735689600",
  "gameVersion": "1.4.2",
  "platform": "Windows"
}

Response, 201

{
  "token": "st_9f2c...redacted",
  "expiresAt": "2026-08-29T16:00:00.000Z",
  "expiresIn": 86400
}

Errors: 400 missing_device_id when deviceId is absent, 401 invalid_api_key or missing_api_key, 403 tracking_disabled when the game's kill switch is off, 429 rate_limited at more than 60 session creations per minute for the game.

GET /api/v1/settings

Reads the tracking kill switch. Auth: X-API-Key.

Response, 200

{ "trackingEnabled": true }

POST /api/v1/track

Sends a single event. Auth: X-Session-Token (from step above).

Request

POST /api/v1/track
X-Session-Token: st_9f2c...redacted
Content-Type: application/json

{
  "event": "level_completed",
  "data": { "level": 3, "score": 15000, "time_seconds": 87.4 },
  "timestamp": 1735689642
}

Response, 202

{ "accepted": 1 }

POST /api/v1/track/batch

Sends up to 50 events in one call. Same auth as /track.

Request

POST /api/v1/track/batch
X-Session-Token: st_9f2c...redacted
Content-Type: application/json

{
  "events": [
    { "event": "level_started", "data": { "level": 3 } },
    { "event": "checkpoint_reached", "data": { "idx": 2 } }
  ]
}

Response, 202

{ "accepted": 2 }

Errors: 400 invalid_batch when events is missing or empty, 400 batch_too_large above 50 events, 400 missing_event if any entry lacks an event name.

GET /api/v1/agent/suggestions

Experimental, machine-readable design suggestions from your weekly digest. Auth: X-API-Key. Returns an empty array until a digest has run for your game.

{ "suggestions": [] }

POST /api/v1/feedback

Auth: X-Session-Token.

Request

POST /api/v1/feedback
X-Session-Token: st_9f2c...redacted
Content-Type: application/json

{
  "message": "Level 3's second checkpoint feels unfair.",
  "category": "suggestion",
  "rating": 4
}

Response, 201

{ "id": "66c1f2a9d4e8b0021f9a7c31" }

category and rating are both optional. When present, category must be one of bug, suggestion, complaint, praise, playtest, or other.

Errors

StatusErrorMeaning
400missing_device_id, missing_event, invalid_batch, batch_too_large, event_name_too_long, event_too_large, invalid_event_data, missing_message, message_too_long, invalid_category, invalid_feedbackMalformed request body or a payload ceiling (see Limits).
401missing_api_key, invalid_api_key, or a missing/expired session tokenBad or absent credentials for the header the endpoint expects.
403tracking_disabledThe game's server-side kill switch is off. Only returned by POST /api/v1/session.
429rate_limitedPer-game ceiling hit: 60 session creations or 600 tracked events per minute. Carries a Retry-After header in seconds.
429quota_exceededMonthly event quota reached for this account. Carries a Retry-After header, in seconds until the quota resets at the next UTC month.
503storage_unavailableEvent storage is temporarily unavailable. Carries Retry-After: 60; nothing was accepted or charged against quota.

6. MCP server

Your analytics as tools for your own agents

Ravensight runs an MCP server at /mcp so you can ask Claude Code, Claude Desktop, or anything else that speaks MCP about your game's data directly, without opening the dashboard.

Connect it

Mint a personal access token from the dashboard's Settings > MCP access tab. It looks like gt_mcp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and is sent as a Bearer token.

claude mcp add --transport http ravensight https://api.ravensight.io/mcp --header "Authorization: Bearer gt_mcp_..."

The endpoint is a stateless streamable HTTP transport: every request is handled independently, with no session to resume and nothing to clean up between calls.

Tools

Every tool below that takes a game_id checks it against the games your token's owner actually has, on every single call rather than once when the token was minted: a token can never read another tenant's game, and a teammate removed from your studio loses access on their next call.

MCP calls are metered usage on the same event meter as everything else: one call weighs 100,000 events, which is $0.05 once the included million is spent, and a write costs exactly what a read costs. MCP needs an account that has loaded a prepaid balance at least once. Each token also carries its own monthly cap in Settings > MCP access, and a token that has spent its cap is refused rather than charged further, so a looping agent cannot empty the account on one credential. A call that fails is not charged. Your external AI client may charge separately for its own model usage.

A token reads by default. The write tools below need a token an owner has switched Allow writes on for, on the token's own form in Settings > MCP access. Nothing about money, tokens, team members, games or projects is writable over MCP at all: a write-capable token can record marketing touchpoints, keep the sales ledger, store reference documents and put cards on a brainstorm board, and that is the whole list. Every write is written to your audit log with the tool name and how many rows it created, updated or rejected, never the rows themselves.

The studio-wide comparisons are not MCP tools. Asking the same metric, funnel or property of every game at once is something the in-dashboard analyst does, and the API exposes under /api/v1/studio/analytics/...; an MCP client asks list_games and then one game at a time.

Some of them are written to your org's audit log: run_sql, every studio-context read, and every write. Those are the calls that can pull the most out of an account, or put the most into it, in one request, so if a token ever goes astray you can see exactly what was taken and what was added. The log records the tool name and the game, never your query text and never what a write said.

list_games

List your games: gameId, name, and whether tracking is enabled. Every other tool needs a gameId from this list. One entry per environment, so a title with a production and a development build appears twice; the project grouping is dashboard-side and is not returned here.

get_overview(game_id, from?, to?)

Headline analytics for one game: daily active players, totals, median session length, top events.

query_players(game_id, from?, to?, limit?, skip?)

Per-session behavior rows with rage-quit, stuck, and engaged flags and the indicators behind them.

query_levels(game_id, from?, to?)

Per-level funnel: starts, completions, deaths, completion rate.

get_retention(game_id, from?, to?)

D1/D7 retention, overall and by first-seen cohort.

get_metrics(game_id, from?, to?)

Players, sessions, new versus returning, and session length as both an average and a median. New means first seen ever, not first seen in the window you asked about.

get_funnel(game_id, steps, windowSeconds?, countBy?, filters?, from?, to?)

An ordered conversion funnel over 2 to 8 event names: how many reached each step, the share lost from the step before, and the gap into each step as an average and a median. Steps must happen in order inside the conversion window, so doing step two first does not count as converting. Count players or sessions, and filter by event property.

get_property_breakdown(game_id, property, limit?, from?, to?)

How one event property's values are distributed: ranked values with event and player counts, plus a daily series. Reads the top-level keys of the payload your game sends, so ask for the key name. An unknown key returns an empty breakdown, which is an answer.

get_usage_rate()

What a metered MCP call costs, the result and byte ceilings a tool answer is held to, and the header to send when you retry one. Free: ask it first if your agent wants to know the price before it spends.

get_history(game_id, from?, to?)

Lifetime totals and long-range trends from stored rollups, beyond the 90-day raw window: lifetime players, sessions and events, a daily active player series, summable totals and merged top events for the window you ask for. This is the tool for month over month, year over year, and all-time questions.

search_studio_context(query, game_id?, limit?)

Search everything your studio has learned, across every game you have shipped: findings the analyst distilled from past questions, weekly digest findings, and confirmed cross-game patterns. Ask it before you design or change a system, to find out whether you have already hit the problem you are about to walk into. Pass a game_id to narrow it to one game, or leave it off to search the whole studio.

get_game_brief(game_id, limit?)

The compact "what we know about this game" brief: the findings you have confirmed or most recently recorded about one game, human confirmed first and newest after that.

get_code_brief(game_id, limit?)

What the last code scan understood about the repositories behind one game: the architecture, the modules, and which telemetry the code actually sends against which is missing. For a coding agent that last part is the pairing worth having, because a funnel that stops dead at a step nothing in the repo fires is an instrumentation gap rather than a player behaviour. Our notes, never your source. Empty until a scan has run.

list_playtest_jobs(game_id, state?, limit?)

Ravensight Playtest jobs for one game: AI persona playtests, not real players. Each row is one priced job, its state, which modules and personas ran, how many findings it produced and their severity split, and what it cost. Newest first.

list_playtest_findings(game_id, severity?, category?, persona?, job_id?, q?, limit?)

Findings from Ravensight Playtest: what an AI persona hit while playing your game, each with repro steps and evidence references, a screenshot, a video timestamp, a transcript step or a file line, rather than a bare claim. Filter by severity, category, persona or job, or search title and description with q.

get_playtest_report(game_id, job_id, run_id?, format?)

Read a Ravensight Playtest report, an AI persona's notes on playing your game, as markdown or JSON. Omit run_id for the job's aggregate report across every persona that ran, or give a run_id for that one persona's own report.

list_design_docs(kind?, game_id?, limit?)

List your studio's design documents: id, kind, title, gameId, version count, and when each was last touched. Filter by kind (gdd, brief, or note) or by the gameId label on a document. Bodies are not included here, read one with get_design_doc.

get_design_doc(doc_id)

Read one design document by id: its header plus the current markdown body, capped at 40,000 characters with a note when a document runs longer. Never returns version history, a coding agent wants the doc as it stands.

list_touchpoints(game_id?, from?, to?, kind?, limit?)

Your studio's marketing memory: the ads, videos, streams, posts, press mentions, launches, updates and sales you recorded, with what you spent and the measured 72 hour lift. Pass a game_id to get that one game's lift per touchpoint, or leave it off for every game's. A null ratio means there was no baseline to compare against, not that the lift was zero. This is correlation you can explain, not attribution.

list_sales(game_id?, project_id?, storefront?, currency?, period?, from?, to?, limit?)

Your studio's sales ledger, row by row: which title sold how much on which storefront in which period, with units, gross and net, refunds, price, discount and wishlist adds, exactly as you recorded them. Money is whole minor units of the currency on the same row and is never converted, so an agent must not add two currencies together or a monthly row to a daily one. A game_id narrows to that game's title, the only sales scope a build has. Newest period first. Metered as a programmatic read on the event meter.

summarize_sales(group_by?, game_id?, project_id?, storefront?, currency?, period?, from?, to?)

The ledger rolled up one way: by storefront, month, title, region or line item. Every group is keyed on its currency and its granularity as well, so two currencies are two rows and a month is never added to its own days; mixedGranularity warns when a key carries both. wishlistRows says how many rows reported a wishlist number, so a zero over no rows is not read as nobody wishlisting. Prefer it over adding up list_sales. Metered as a programmatic read on the event meter.

get_launch_curve(project_id, currency?)

One title's first 90 days, day by day: units and net revenue per day and cumulative, anchored on the project's release date or, without one, on its first recorded day of sales (the answer says which). One currency per answer, the one the title earned most in unless you name one, with the others listed so your agent can ask for them rather than add them. Monthly rows are counted and left out rather than spread across days you never reported. Money is whole minor units of that currency, as you recorded it, never converted. Metered as a programmatic read on the event meter.

get_sales_playbook()

What your own sales history says, per title: where the money came from by storefront and currency, what share of the first 90 days the launch week was, the price points you sold at, refund rates, how wishlists converted to units, and the best weeks. Deterministic arithmetic over your recorded rows, no model call. Every figure is keyed on its currency and never converted, a null is an absence and not a zero, and the answer carries its own caveats. Metered as a programmatic read on the event meter.

preview_sales_import(csv, project_id?, storefront?, currency?, region?, line_item?, period?)

What import_sales_csv would do with a store export, without doing it: the header row, the mapping the platform matched by rule, the headers it could not map with a suggested field and a probability for each (kept apart from the mapping, so nothing is imported on a guess), the first rows parsed through the real validators, and a warning for anything ambiguous such as a thousands separator. Nothing is stored and no import id is issued. Send the confirmed mapping to import_sales_csv with the same defaults. Metered as a programmatic read on the event meter.

list_brainstorm_sessions(limit?)

Your studio's brainstorm boards: each with its title, how many cards it holds, which project and game it is about, its status and when it last moved, most recently moved first, up to 100. Read one with get_brainstorm_board. Metered as a programmatic read on the event meter.

get_brainstorm_board(session_id, column_key?, limit?)

One board: its columns and the cards in each, who put each card there (a person or the partner), what each card cites, and whether it has been promoted into a design document. The conversation is not included: a thread is a working conversation between you and the partner, and the board is the part that is a record. Narrow to one column by its key. Another studio's board, or one that never existed, reads as a board you do not have. Metered as a programmatic read on the event meter.

get_starting_context(genre?, platform?, game_id?)

What your own history says before you design anything new, as a digest: the patterns confirmed across your games, what each shipped game taught you, the marketing touchpoints that actually moved players ranked by measured lift with what they cost, what your sales ledger says per title and storefront, and what your playtests keep finding, by category. Deterministic arithmetic over your own records and no model call, so the same question gets the same answer every time. Name a genre and platform to have them echoed into the digest, or a game_id to narrow it to one of your games. Metered as a programmatic read on the event meter.

list_investigations(project_id?, status?)

Your investigations: the questions you opened about player experience, what you decided, and what you observed afterwards. One row each with its project, environment, question, status, decision and outcome, most recently changed first. Filter to one project or one status.

get_investigation(investigation_id)

One investigation in full: question, intent, decision, observed outcome, release comparison, the evidence attached to it and the saved analysis if one was generated. Evidence is listed by kind, title and population rather than quoted, because a feedback message, a design document and a playtest finding are each readable through their own tool. An analysis marked stale was written against an older revision, or against evidence that has changed since.

get_latest_digest(game_id)

The most recent weekly digest for one game: the headline, the bullets behind it, and the machine-readable suggestions a game client can act on. A digest is written once a week from that week's events, so this is last week's reading of the game rather than a live number. Ask the analytics tools for now.

search_feedback(game_id, query?, category?, limit?)

Search player-submitted feedback for one game. Every message is also read by a cheap model at ingest, which extracts a one-line summary, the facts it states, topic keywords and a sentiment; those ride along with each result and power the Themes panel on the dashboard's Feedback screen.

run_sql(game_id, sql)

Run a read-only SELECT against your events. See run_sql and the events schema below for the rules.

get_journeys(game_id, from?, to?)

Level-to-level journey graph: which levels players move between, with churned versus retained counts per edge. Only available on deployments with journey graphs configured.

find_bottlenecks(game_id)

Progression problem spots derived from the journey graph: levels ranked by players lost, the churn-heavy transitions between them, and the loops players cycle in before quitting. Only available on deployments with journey graphs configured.

get_top_paths(game_id, hops?)

The most common multi-step level paths, estimated from the aggregate graph, two to four hops long. Only available on deployments with journey graphs configured.

Writing, with a token an owner allowed

These seven need Allow writes on the token. Each one is priced as a programmatic call, the same as a read, and a write that is refused is not charged.

Retry a write with the same X-Ravensight-Operation-Id header. An operation id that has already run answers with what it did rather than doing it again, so a timeout or a dropped connection is safe to retry and cannot record the same campaign twice. A retry with a new id is a second write, and is charged and stored as one. A token restricted to a project cannot use these at all: a touchpoint and a reference document belong to the studio rather than to one project.

record_touchpoint(kind, title, occurred_at, url?, channel?, spend?, notes?, tags?)

Record one marketing touchpoint: an ad, video, stream, post, press mention, launch, update or sale. This is your own account of what you did, so your agent states the kind rather than guessing it from the link. Spend is a plain amount like 129.99. The 72 hour lift is measured by the platform afterwards and is never accepted here.

import_touchpoints_csv(csv)

The same thing from a store or ad export. The header row must name kind, title and occurred_at; url, channel, spend, notes and tags are optional and the order does not matter. Partial success is the contract: every row that validates is stored, and every row that does not comes back with its line and a reason, so your agent can fix three rows rather than resend forty.

upload_reference_doc(title, markdown)

Store source material you did not write in Ravensight as a reference document: a pitch, a publisher brief, a page of research. It becomes retrievable by the analyst and the design partner alongside your own documents, and reads back through list_design_docs and get_design_doc. Markdown or plain text, up to 256 KB of document text (the limit is on the text, not on the request carrying it). There is no PDF over MCP. A person uploads a PDF in the dashboard's Design page, which is where the text extractor and the page limit live; that upload needs a dashboard session rather than an MCP token.

import_sales_csv(csv, mapping, project_id, storefront?, currency?, region?, line_item?, period?)

Import sale rows from a store export under the mapping you confirmed with preview_sales_import, every row for the one title named by project_id. Up to 1 MB of CSV and 5,000 rows. Idempotent by row identity (title, storefront, period, period start, currency, region, line item and label): the same export twice creates nothing, and a corrected export updates the same rows in place, so the answer's created, updated and rejected counts say what happened. Partial success is the contract, with a line and a reason for every row that did not land. Money is stored as whole minor units of the currency on each row, at that currency's own scale, as you recorded it and never converted.

record_sales(rows)

The same ledger without a file: up to 100 rows per call, each naming its own title, storefront, day or month, currency and what sold, as your agent read them off a store's own report. Money is a plain amount in the row's currency, like 129.99. Idempotent by the same row identity as the import, so sending the rows again creates nothing and a row with corrected numbers updates the stored one. A row that does not validate, names a title you do not have, or repeats an earlier row in the call comes back with its position and a reason; every other row lands.

create_brainstorm_session(title, project_id?, seed?)

Open a brainstorm board, optionally about one of your titles. With seed: "studio" the board starts with a snapshot of your studio's own starting context, the same free digest get_starting_context answers, so the people and the partner on it start from what you already know; it puts no cards on the board and calls no model. The partner's synthesis and the conversation stay in the dashboard, because they call a model on the platform's key.

add_brainstorm_card(session_id, column, text, citations?)

Put one card on one of your boards, in a column it has, as the person the token belongs to. A citation names something your studio already holds, by kind and id: an insight, a document, a touchpoint, a playtest finding or a sales row. It is resolved against your studio when the card is written, and a citation from anywhere else refuses the card. Another studio's board reads as a board you do not have.

Your own agent can keep the books

The loop worth wiring up: your agent reads a storefront or ad dashboard you already have open, and writes what it saw into the studio's memory so the lift gets measured, the ledger stays current and the analyst can cite both later.

  1. Ask for the export, or read the numbers off the page, and call record_touchpoint once per campaign, with a distinct X-Ravensight-Operation-Id per campaign so a retry of one cannot duplicate another. For a file, call import_touchpoints_csv and read the rejected lines back before deciding whether to fix them.
  2. For the sales side, send the store's export to preview_sales_import first and look at the mapping it proposes and the headers it could not place. Confirm the mapping (a suggestion is only a suggestion until your agent puts it in the mapping), then call import_sales_csv with it and the same defaults. Running the same export again is safe: the ledger is keyed on the row, so a re-import updates rather than doubles. For a handful of rows read straight off a payout page, call record_sales instead, one storefront report per call.
  3. Call list_touchpoints and get_launch_curve afterwards. The lift is empty at first: it is measured against the 72 hours after the touchpoint, so it appears once that window has passed. Neither number is attribution: lift is a correlation your studio can explain, and the ledger is what you recorded.
  4. Drop the brief or the research behind the campaign in with upload_reference_doc, so the next question your agent asks about it has the source material in reach, and put what it concluded on a board with add_brainstorm_card, citing the sales row or the touchpoint it rests on.

Worked example

Ask your agent: "In Hollow Verge, why are players dropping off partway through?" It calls list_games to find the gameId, get_overview and query_levels to find which level has the worst completion rate, then run_sql to look at deaths by checkpoint on that level, and answers with the numbers it found.

The one worth wiring into your own workflow is the other direction. Before your coding agent touches a system, have it call search_studio_context with a sentence describing the change. It gets back your studio's own findings about that subject, from every game you have shipped, and can tell you that you already tried this in 2024 and it cost you a third of your players.

7. run_sql and the events schema

Your events, queryable directly

run_sql is available both as an MCP tool and to the in-dashboard analyst. It is a real SELECT against your event store, not a canned report.

events table columns

ColumnType
game_idString
device_idString
session_idString
event_nameString
tsDateTime64(3, 'UTC')
levelString
platformString
game_versionString
payloadString, arbitrary JSON

Rules

  • SELECT only. A single SELECT or WITH ... SELECT statement. Writes, DDL, and settings changes are rejected before the query runs.
  • No comments or extra statements. --, /* */, #, and semicolons (beyond one optional trailing one) are all rejected.
  • events only. The only readable table is ravensight.events, plus any CTEs you define in the same query. Other table names, table functions, and cross-database reads are rejected.
  • The game filter is automatic. Every reference to events is rewritten to a subquery scoped to your own game_id before it runs. Do not write your own game_id predicate: you cannot see or query another game's rows regardless.
  • Row cap. Results are capped at 200 rows no matter what LIMIT you write.
  • Query and time limits. Queries are capped at 4,000 characters and 15 seconds of execution time, and run with readonly=1 at the database level.

Example

Deaths by level, most first:

select level, count() as deaths
from events
where event_name = 'player_death'
group by level
order by deaths desc

How the built-in detections read your events

The level funnel, journeys, and the player flags are computed from your event names and the level field, with no configuration. Name your events accordingly and they light up.

  • Deaths are events whose name contains died, destroyed, or killed (lowercase substring match, so player_died and ship_destroyed both count).
  • Level starts are names containing start, begin, or enter; completions contain complet, finish, win, or clear.
  • The level field is what places an event. The funnel, per-level deaths, and journeys only see events with a non-empty location value. The API uses the first non-empty payload field in this order: level, location, track. It is any string that names a place or mode in your game: a level id, an encounter, a scene name.
  • Rage quit likely flags a session with 3 or more deaths in its last 5 events, 3 or more deaths at the same level (counting died/destroyed names), or a final event containing died followed by more than 10 minutes of silence inside the queried window.
  • Potentially stuck flags a session that repeats one event 10 or more times while the whole session has fewer than 20 events.
  • Highly engaged flags a session with at least 20 events at more than 2 events per minute and fewer than 5 deaths.

Every flag comes back with the plain-language indicators that triggered it, so you can always see why a session was tagged.

8. Limits and fair use

What the free allowance actually gets you

Every feature is available on every account. Pricing is usage-based: a free monthly allowance, then metered rates for anything past it.

Rate limits

Per game, per 60 second window: 60 session creations and 600 tracked events. A batch call costs one unit per event, capped at the 50-event batch ceiling, so a full batch never charges more than a valid batch could. Both the versioned and legacy ingestion paths share the same budget for a given game.

Payload ceilings

Request bodies are capped at 100KB. Within them, an event name is capped at 200 characters and one event's data at 8KB serialized: events are gameplay facts, not documents. A batch containing one oversized event answers 400, and every SDK isolates and drops the offending event automatically, so a single bloated event never costs the rest of its batch. Feedback messages are capped at 2,000 characters.

Data retention

Raw events are kept for 90 days. Before they age out, Ravensight extracts daily and monthly aggregates (active players, new players, sessions, events, top events, level funnels, cohort retention) and keeps those forever, along with lifetime totals per game. The 1y and All views in the dashboard, and the analyst's long-range answers, are served from these aggregates. Raw SQL via run_sql only reaches the live 90 days. History collection can be switched off per environment in Settings > Projects; production environments keep it on by default, development and staging environments start with it off.

One consequence worth knowing: the aggregates are computed from real player sessions only, and carry no column saying which rows an AI persona produced. So the long-range history endpoints take no persona scope at all, because there is nothing there to include. Your 1y and All numbers are real players, always. The Include AI personas switch applies to the live 90-day window.

Raw event export

GET /api/v1/games/<gameId>/analytics/events/export?after=0&limit=10000
Cookie: gt_session (dashboard sign-in)

{ "events": [ { "deviceId", "sessionId", "event", "ts", "level",
               "platform", "gameVersion", "data" }, ... ],
  "nextAfter": 1755648000123 }

Oldest first, up to 10,000 events per page; keep requesting with after = nextAfter until it returns null. Export anything you want to keep beyond the 90-day raw window.

Free monthly allowance and usage rates

1,000,000 events / month free 10 shared AI units / month included 90 day retention

One studio shares 1,000,000 events and 10 shared AI units each month, across every project and every environment in it. Additional event usage costs $0.05 per started 100,000-event block; additional AI units cost $0.20 each. A text report uses one event and a screenshot adds 20,000. Analyst, Design, risk checks, investigation analysis and digests each use one AI unit; synthesis uses five and enrichment uses one per batch of up to 25 items.

MCP bounded reads weigh 100,000 events each, $0.05 once the included million is spent, and need an account that has loaded a balance at least once. Source scans have a separate quote before running. Playtest is priced per unit and has no free allowance of its own: $1.00 a persona run, $4.00 a game profile, $5.00 a fix attempt, charged when a job registers and refunded for any unit that did not produce a usable result. These charges use the same prepaid balance. Top-ups start at $5; balances do not expire. Paid work stops when funds are unavailable unless optional auto-recharge adds funds. Browsing saved dashboard data does not use AI units.

There is also a safety ceiling of 500,000,000 events a month per account, which applies even with a balance loaded. It exists so a runaway loop or a broken build cannot turn a prepaid balance into hundreds of millions of events you never meant to send, and it is checked before anything is charged, so a refused batch costs nothing. Past it you get the same 429 quota_exceeded, with a message saying it is the ceiling rather than the allowance. If that volume is genuinely yours, ask and we will raise it.

AI actions use Ravensight-managed providers and the shared prepaid balance. Customers do not supply provider API keys.

Retention

Events are kept for 90 days and then dropped automatically. Export or query anything you need to keep longer before then.

9. Platform support

Where the SDKs run

Every SDK is plain HTTPS against the same four endpoints. There is no native plugin, no binary blob, and no platform specific code path in any of them, so an SDK works wherever its engine exports.

Support matrix

SDKDesktopiOSAndroidWebConsole
Godot Yes Yes Yes Yes, on the web export Yes, subject to cert
Unity Yes Yes Yes Yes, on WebGL Yes, subject to cert
Unreal Yes Yes Yes No web target in UE5 Yes, subject to cert
JavaScript (web and Node) Yes, in Electron or Node Yes, in a web view Yes, in a web view Yes Not applicable
C++ Yes, C++17 plus libcurl Yes, links libcurl Yes, links libcurl Not applicable Yes, subject to cert
Odin Yes, via libcurl binding Untested Untested Not applicable Untested
iOS native Swift Yes, macOS 12+ Yes, iOS 15+ Not applicable Not applicable Not applicable
Android native Kotlin Not applicable Not applicable Yes, minSdk 24 Not applicable Not applicable
Any engine via HTTP Yes Yes Yes Yes Yes, subject to cert

These are honest cells, not a marketing grid. Because everything is an HTTPS request, an SDK runs on any target its engine can export to, and we have not special cased a single platform. What we have not done is ship a title on every one of them, so treat the mobile and console columns as "nothing in the way" rather than "verified in a submitted build".

Consoles

Nothing in any SDK is blocked on a console. What is blocked is everything else about console networking: each platform holder requires that outbound traffic, privacy disclosure, and any data collection be declared and approved as part of certification, and NDA restrictions mean we cannot ship console specific code publicly anyway. Ravensight is an ordinary HTTPS call from your title's own network stack, and passing cert with it is the developer's responsibility, exactly as it would be for a leaderboard or a patch notes fetch.

Mobile privacy

Ravensight does not touch an advertising identifier. Every SDK generates its own random device id on first run and stores it locally: no IDFA on iOS, no Android advertising id, no hardware identifier, and no IP based fingerprinting. That id is meaningless outside your game's own data.

No App Tracking Transparency prompt is required for Ravensight. The ATT prompt exists for tracking that links a user to data from other companies' apps and sites, usually through the IDFA. Ravensight never reads it, so on Ravensight's account you do not need to call requestTrackingAuthorization. If something else in your app does track across companies, that decision is unchanged by this.

You do still have disclosure obligations, and they are yours rather than ours, because Apple and Google ask the publisher of record:

  • App Store privacy details. Declare a Device ID collected and linked to Analytics, plus whatever your own events carry. If you send gameplay telemetry, that is Product Interaction under Usage Data.
  • Apple privacy manifest. Add a PrivacyInfo.xcprivacy entry for NSPrivacyCollectedDataTypeDeviceID with Analytics as the purpose, NSPrivacyCollectedDataTypeLinked set to false, and NSPrivacyCollectedDataTypeTracking set to false.
  • Android. The android.permission.INTERNET permission is the only one any SDK needs. No AD_ID permission, and nothing that triggers a runtime permission dialog. Fill in the Play Console data safety form to match: device id, collected for analytics, not shared with third parties.

Ravensight itself is the processor here, not the controller. What ends up in an event payload is entirely what you chose to put there, so if you send something personal, disclose it.

SDK repositories

SDKStatusRepository
Godot Stable ravensight-godot
JavaScript Stable ravensight-js
Unity Stable ravensight-unity
Unreal Stable ravensight-unreal
C++ Stable ravensight-cpp
Odin Stable ravensight-odin
iOS Stable ravensight-ios
Android Stable ravensight-android

Every SDK implements the same protocol against the same four endpoints, with its batching and retry logic unit tested against the live API contract. If your engine is not here, the HTTP API is three headers and a JSON body.

10. Implementation doctor

Check your integration before and after you ship

Two layers watch your integration. The dashboard computes implementation health from your game's own live traffic, and a public scanner checks your source tree before you ship. Both feed the same card on your game's Overview page.

Live implementation health

Automatic, no setup. The API already sees what your integration does: requests rejected for size, event names exploding in cardinality, payloads brushing the 8KB ceiling, sessions that start but never flush an exit. The Implementation health card on Overview summarizes it over the last 7 days and tells you what to change.

ravensight doctor

A zero-dependency scanner for your project directory. It detects your engine, finds the SDK, and lints the integration statically: event name length and cardinality, oversized inline payloads, missing track calls, and credentials that must never ship inside a game build (an MCP token or a cloud key in your tree is an error; your publishable gt_live ingest key is fine).

Run it

npx github:Reality-Software-Entertainment/ravensight-doctor

# machine readable
npx github:Reality-Software-Entertainment/ravensight-doctor --json

# also submit the report to your dashboard
RAVENSIGHT_INGEST_KEY=gt_live_xxxx \
npx github:Reality-Software-Entertainment/ravensight-doctor --report

Exit code 0 on pass or warnings, 1 when any error-severity finding exists, so CI can fail the build.

In CI

GitHub Actions

- uses: Reality-Software-Entertainment/ravensight-doctor@v0
  with:
    path: .
    report: true
    api-key: ${'$'}{{ secrets.RAVENSIGHT_INGEST_KEY }}

A GitLab CI snippet ships in the ravensight-doctor repo.

The report API

The doctor submits to POST /api/v1/doctor with your X-API-Key ingest key: an engine, a summary (pass, warn or fail with counts), and up to 100 findings. One report is kept per game, newest wins, and it appears on the Implementation health card alongside the live signals.

For your coding agent

Read these docs through MCP

Give your agent searchable Ravensight documentation while it integrates your game or audits existing tracking. Documentation reads are free and require no account, API key, or prepaid balance.

This public server reads the documentation on this page. It cannot see your studio, query player data, change your project, or spend Ravensight units. The analytics MCP is a separate, authenticated service with its own metering. Your agent provider may still charge for the agent's work.

1. Connect your agent

Use this remote HTTP MCP URL, with authentication set to none:

https://docs-mcp.ravensight.io/mcp

Codex CLI

codex mcp add ravensight-docs --url https://docs-mcp.ravensight.io/mcp

Claude Code

claude mcp add --transport http ravensight-docs https://docs-mcp.ravensight.io/mcp

VS Code / GitHub Copilot: merge into .vscode/mcp.json

{
  "servers": {
    "ravensight-docs": {
      "type": "http",
      "url": "https://docs-mcp.ravensight.io/mcp"
    }
  }
}

Keep your other server entries when merging configuration. Reload the agent's tools if needed. In another MCP-compatible client, add the same URL as a remote server. In ChatGPT, use a supported custom MCP connection if your account and workspace allow it; connecting the docs does not grant access to your code.

Client setup references: Codex, Claude Code, and VS Code. Client interfaces and workspace policies may differ.

2. Ask a concrete integration question

Use ravensight-docs to find the event payload limits and Godot
session setup instructions. Read the relevant sections, cite their
links, and compare them with the SDK version installed in this project.
ToolWhat it returns
search_docs(query, limit?, section?)Up to 10 relevant records with excerpts, IDs, source links, and content revisions. An optional section narrows the search.
get_doc(id, offset?, max_chars?, revision?)A Markdown record with code examples and tables. For long records, continue at next_offset with the same document revision.

Clients that browse MCP resources can open ravensight-docs://index and the individual document resources. A section link may point to its parent section when the website has no more specific anchor. The server retrieves documentation; your agent interprets it and should check it against your installed SDK.

3. Use it with the instrumentation skill

The instrumentation skill supplies the audit and implementation workflow. This server supplies current documentation. They work together, and each remains useful on its own. The skill installer does not add MCP connections or change your agent's settings.

Freshness, limits, and troubleshooting

The catalog is generated from this page on every website build. Responses include document and catalog revisions, the last successful source check, and a stale flag. Normal refresh is within five minutes. If the source is temporarily unavailable, previously validated content may be served for up to one hour and is marked stale. After that, the server reports unavailable; read this page directly.

  • No tools: confirm the URL ends in /mcp, choose remote HTTP, and reload the connection. This service needs no bearer token. Opening the MCP URL in a browser may return 405 because MCP requests use POST.
  • Too many requests (429): pause and retry with backoff. Public capacity is shared; avoid polling or sending the entire codebase as a search query.
  • Stale or unavailable: check service health and use the ordinary docs links. A healthy transport alone does not prove telemetry delivery in your game.
  • Document changed while paging: restart at offset 0. Search again for an unknown ID. Narrow broad searches using a section from the index.

Send only documentation questions, not credentials, private source, or player data. The server does not call an AI model or store search queries in an application database. Operational request metadata may be recorded by the hosting provider. Source and deployment instructions are in the public ravensight-docs-mcp repository; the generated documentation catalog is also available without MCP.

Agent skill

Let your coding agent complete the tracking story

Audit and improve tracking in a new game or one you have already shipped. The Ravensight Instrumentation Skill guides your agent through existing events, missing player journeys, failures, retries, choices and exits.

Choose audit-only for recommendations, expand for code changes to an existing integration, or initialize for a new one. Your agent preserves useful events, checks for duplicate or misleading tracking, and produces an event catalog and coverage report with verification evidence.

1. Choose your agent

The public Ravensight Skills repository contains the skill and its references. Choose the installer flag for the agent you use in your game repository.

AgentInstaller flagHow to start
Codex--agent codex$ravensight-instrumentation
Claude Code--agent claude/ravensight-instrumentation
GitHub Copilot--agent copilotAsk it to use ravensight-instrumentation.
Other agents--agent genericAsk the agent to read the installed SKILL.md and its references.

2. Install in your game repository

With Node 20 or later, open a terminal in your game directory and run the command below. Replace codex with your agent's flag value from the table.

npm exec --package github:Reality-Software-Entertainment/ravensight-skills -- ravensight-skills --agent codex --project .

This downloads and runs the public installer. It adds skill files, preserves existing content, and leaves game code alone. Add --dry-run to preview the destination. Reload your agent's skills or restart its session if it does not discover the new skill.

Without Node, copy the complete skills/ravensight-instrumentation folder from the repository into your agent's skill directory. Keep references/ and agents/ with SKILL.md. The setup guide lists the exact directories, update and uninstall steps, and how to pin an installation to a commit.

3. Choose what the agent should do

Audit existing tracking without code changes

Use ravensight-instrumentation to audit our existing tracking.
Report missing, duplicate, or misleading events with source locations.
Do not edit application code.

Expand tracking in an existing product

Use ravensight-instrumentation to audit and expand our tracking.
Cover meaningful journeys, decisions, failures, retries and exits.
Preserve useful existing events, implement gaps, validate changes,
and update our event catalog and coverage report.

Start a new integration

Use ravensight-instrumentation to integrate Ravensight in this game.
Inspect the engine and SDK, then instrument the player journeys.

To work on selected code, name the subsystem or files in your request, for example: Limit edits to inventory and crafting; follow callers and outcomes as needed. Audit mode reviews existing choices. Expand mode implements missing coverage without duplicating useful events.

4. Review coverage and verify delivery

The agent produces an event catalog and coverage report, normally in docs/analytics/events.md and docs/analytics/coverage.md, or updates your existing documents. A chat-only audit can return its findings inline. Review the new events, retained tracking, deferred gaps, volume assumptions, and the checks the agent actually ran.

Code inspection, local execution, and events observed arriving are different evidence levels. Use a development environment for runtime verification. Installing the skill alone does not collect events, publish a build, or guarantee complete coverage of every possible player action.

ChatGPT, access and costs

For a client without local skill discovery, provide SKILL.md and its references, then explicitly ask it to follow the workflow. Supply the relevant source or a supported repository connection. Implementation requires editing tools; this pack does not install a connector or grant code access.

Local source is sufficient. Optional authorized MCP access can add live evidence and is metered; your agent provider may charge for its own work. Added events can increase event usage. The workflow respects existing collection controls and keeps event volume and payloads bounded.

Updating or troubleshooting

If the installer reports different existing content, preserve your local edits before removing the old skill folder and reinstalling. To uninstall, remove that skill folder. If live data is unavailable, the agent can continue locally and must report delivery as unverified. See the repository setup guide for manual loading and supported installation paths.

11. Studio Intelligence

What you meant, what players did, what you decided

Analytics tell you what happened. Player Reports tell you what it felt like. Studio Intelligence is where those meet a question you actually care about, and where the answer stops being a browser tab.

An investigation

You start with a question. Against it you gather evidence: analytics results, player reports, playtest findings, feedback, notes you write yourself. Every piece keeps its provenance, so months later you can see where a claim came from rather than having to trust it. When you have enough, you record the decision and the follow-up you are trying next, and that stays attached to the question rather than being lost in a chat log.

Release comparison

Inside an investigation you can put one release beside another and see the same metrics for both. Read it as what changed, not as what caused it: a comparison shows a difference between two windows, and it has no way to know what else you shipped in between.

Analysis

Asking Ravensight to analyze an investigation is a bounded AI action, metered exactly like an analyst question. It reads the evidence you gathered, not the whole account. The decision stays yours: nothing here marks a question resolved on its own.

Where it connects

A player report can be sent into an investigation from the Player Reports page. Findings the investigation produces are kept in the same studio context graph as the analyst's, so the next game starts from them, and the analyst can search them with search_studio_intelligence. A playtest finding needs no such step: once a run finishes, its worst findings already sit in the analyst's memory and in the studio graph as evidence, ready for an investigation to cite.

Background work, on a ceiling you set

The work Ravensight does without being asked each time, weekly digests, pattern synthesis and feedback enrichment, runs under a monthly budget in cents that the owner sets and that is stated against the current rate before it is accepted. It is a ceiling on spend, not a subscription: nothing renews, and switching it off stops the work. Each of the three can be enabled on its own.

Reading an investigation needs a read-only role or above. Creating one, gathering evidence and recording a decision need a member role or above. Setting the background budget is owner only.

12. Studio context

What your studio knows, kept and reusable

Analytics answers a question and then loses the answer. The studio context graph is the other half: every conclusion the analyst reaches is kept as a dated finding, owned by your studio rather than by the game that produced it.

Analyst context

Findings below are extracted by a model; analyst context is what you write yourself, and the analyst is told to trust it over its own reading of the data. There are two levels: game context (Settings, AI Analyst tab, 2,000 characters) for facts specific to one game, and studio notes (1,000 characters) for facts that hold across every game in the studio. Both are inserted into the analyst's prompt verbatim, ahead of the findings below, so a note like "levels 5 through 7 are an intentional difficulty spike" or "we ship weekly builds on Fridays" heads off a wrong conclusion before the analyst ever reaches for a tool.

Findings

When an analyst answer finishes, a cheap background model distils it into at most four standalone findings. A finding is one sentence with numbers in it, stored with the date the data was observed and a link back to the conversation that produced it, so you can always go and read the reasoning behind it.

Two deterministic guards run before anything is stored. A finding whose numbers do not appear verbatim in the answer is dropped, and a finding that restates one you already have is suppressed. Neither is a prompt instruction; both are code.

Every finding carries a status you control:

  • active, the default: extracted and in use.
  • confirmed: you vouched for it. Confirmed findings lead the game brief and outrank recency.
  • archived: it was wrong or has gone stale. It stops being used and stops being returned, but it is kept rather than deleted, because knowing what the analyst once believed is itself useful.

Patterns

Once your studio has more than one game, a weekly pass reads your active findings and proposes the lessons that held across several of them, each with the findings it was distilled from attached. A pattern is only proposed when findings from at least two different games support it, and that rule is enforced in code after the model answers, not asked for in the prompt.

Proposed patterns are shown as proposed. Nothing synthesized becomes part of what your studio knows until a person confirms it.

The design risk check

Describe something you are about to build. Ravensight retrieves your own relevant findings first and asks the model to grade the plan against them, so it is reading evidence rather than recalling anything. It answers repeat, caution or clear, with the findings that justify the verdict cited by name. A citation it cannot map back to a real finding of yours is dropped rather than shown.

This is the one part of studio context that calls a model, so it is metered exactly like an analyst question. Browsing saved context in the dashboard uses no AI units. MCP reads are metered separately.

Marketing memory

Analytics can tell you that Tuesday tripled. Only you can tell it that a video went out on Monday. A touchpoint is that record: one thing you did outside the game, written down by you, so the platform can measure what happened next.

Record one in Studio > Marketing with a kind (ad, video, stream, post, press, launch, update, sale or other), a title, when it happened, and optionally a link, a channel name of your own, a spend and some notes. Or import a spreadsheet export as CSV with a header row naming kind, title and occurred_at, plus any of url, channel, spend, notes and tags. Column order does not matter. Tags are separated by a vertical bar so a tag can contain a comma, spend is a plain amount like 129.99, and every row that validates is imported while every row that does not comes back with its line number and the reason. One bad date does not refuse the file.

Each night, and on demand from the touchpoint itself, the platform measures the lift for every game in your studio that has events. In plain words: it counts the devices whose very first event for that game arrived in the 72 hours after the touchpoint, works out how many new players a 72 hour window would have seen anyway (the average day over the previous week, times three), and reports both numbers and their ratio. If your game had no new players at all in that previous week there is no ratio, and you get an empty one rather than an invented multiple.

Read it as correlation, not proof. Two touchpoints inside the same 72 hours each show the whole lift, and a storefront feature you never recorded shows none of it. The number tells you which week to look at; you still decide what caused it. Touchpoints appear as markers on the game's history chart, on the Studio Intelligence evidence map with their strongest lift, and they can be cited as evidence in an investigation. The weekly digest names any touchpoint whose 72 hour window covers a day it calls a spike.

When filling the form in, the platform can offer a suggested kind and channel from the link's host and your own title and notes. It is only ever a suggestion: nothing is filled in for you, nothing is stored until you save, and when that helper is unavailable the form works exactly as it always does. Deleting a project keeps its touchpoints, because the money you spent and the lift it produced happened whether or not the project is still in your account.

Brainstorm

A brainstorm is a board you think on, next to a partner that has read what your studio already learned. Open one in Build > Brainstorm. A board starts with five columns, Ideas, Questions, Risks, Keep and Drop, which you can rename, re-order or add to, up to eight. A card is one thought in one of those columns, written by you or by the partner, and a card can cite what it rests on: a pattern from your studio context, one of your documents, a touchpoint, a playtest finding or a row in the sales ledger. Every citation is checked against your own studio when the card is written, so a card cannot point at evidence you do not have.

The partner reads your studio's own history before it answers: the findings across every game you have shipped, the patterns you confirmed, the touchpoints that moved players and what they cost, and what your playtests keep finding. Ask it a question and it answers in the thread, cites what it used, and can put cards on the board it is sitting at, up to twelve per question. It writes to that board and nowhere else, and nothing it writes is hidden from you: a card it adds is a card you can edit, move or drop. The thread is kept with the board, so a brainstorm you reopen next month picks up where it stopped. Attach one of your documents, a design document or an uploaded Markdown, plain text or PDF reference, and the conversation is scoped to it: the partner is told which documents this board is about and reads them by name. When you are done, promote one card or the whole board to a Design brief, which lands in Design as a document you own.

Start with what the studio knows fills a new board from your own record: your confirmed patterns, your best touchpoints by measured lift, your sales by storefront and your findings by category. The starting context it reads is a plain digest of that record and it is free, built without a model call, and you can read it beside any board. Turning it into cards is one shared AI unit, the same unit a Design chat turn uses, and the dialog names that unit before anything is spent. If the partner could not produce cards, the unit comes back and the page says the board is empty rather than claiming it was filled.

Each question to the partner is one shared AI unit. For a design question that would benefit from the deeper model, the partner may offer the deep tier as a choice with its price shown, five units from your prepaid balance and never from the included allowance, and nothing is charged unless you choose it. The board itself, its cards, its attachments and promotion are all included. What ships today is the board: there is no freeform canvas.

Sales ledger

Marketing memory says what you did. The sales ledger says what it earned, in your own numbers. A row is one storefront, one period and one line item for one title: the storefront, whether the period is a day or a month and which one, the currency, a region if the export splits by region, the line item (the base game, a DLC, an edition or a bundle, with your own name for it), and then whatever the report gave you: units and refunded units, gross, net, refunds, chargebacks, fees, payout, the price and discount at the time, wishlist adds, and a note. Record one by hand in Studio > Sales, or import a store export. Nothing is recomputed from anything else: net is what the payout report said, even when it disagrees with gross minus fees, because the report is the fact.

Importing is two steps. Upload the CSV and the platform reads the header row, matches the columns it recognises to the ledger's fields, and shows you the mapping beside the first few rows parsed exactly as the import will parse them. A column it could not place is offered with a suggestion, marked as a suggestion, and you confirm or change every mapping before anything is stored: the preview stores nothing, and the suggestion helper never decides. An amount like 4.990, which some exports mean as four thousand and others as four point nine nine, is flagged above the table so you can say which it is. A weekly export is refused with a one line reason rather than spread over seven days. Every row that validates is stored and every row that does not comes back with its line number and the reason. Importing the same file twice changes nothing; importing a corrected one updates the rows in place.

Totals are per currency, always. A studio selling in dollars and euros sees two blocks, and there is no combined figure anywhere, because a conversion rate would have to come from somewhere and would be wrong for the period it was applied to. For the same reason a monthly row is never added to a daily one: the summary says so when a group carries both, and you read the two rows apart. Nothing that nobody recorded is shown as zero.

Give a title its release date in Settings > Projects and the Sales page draws its launch curve: cumulative units and net for the first ninety days after release, from daily rows, in one currency at a time. Without a release date the curve anchors on the first recorded sale instead, and monthly rows are counted beside the chart rather than smeared across it. On Overview and Player insights, the Show units sold switch draws units per day over the players line for that game's title, so a sale and the players it brought sit on the same axis; it is off by default and costs no extra request.

Plainly: these are recorded numbers. There is no storefront integration, nothing is read from a store on your behalf, and the platform never infers a sale from telemetry. The analyst, the weekly digest, cross-game synthesis and your own agents over MCP all read the ledger you keep, with the same rule attached: minor units, never converted, a month never added to a day.

For your own agents

The same context is available over the Analytics MCP Docs MCP (free) through search_studio_context, get_game_brief, list_touchpoints, list_sales, summarize_sales, list_brainstorm_sessions, get_brainstorm_board and get_starting_context. All eight are bounded MCP reads billed to the prepaid balance, so a coding agent can pull your studio's findings, what you did to market them, what they earned and what you are thinking about next, on every task it picks up.

Who can see it

Findings are the most sensitive thing in your account: they are your conclusions about your own games, not raw numbers. The tenancy filter is part of the query rather than applied to the results, in the database read and inside the semantic search stage alike, so another studio's context is not merely hidden from you, it is never retrieved. Every member of your org can read the context graph; confirming and archiving findings needs a member role or above.

13. Source scan

The gap between what your game does and what it reports

Analytics can only answer questions about events you actually send. The source scan reads your code and your live telemetry together, and tells you where the two disagree.

How it runs

Three front doors, one pipeline. Connect GitHub and a push scans itself (below), or send your source as a zip upload up to 100 MB, or as a JSON body of { files: [{ path, text }] } up to 40 MB, which is what makes it easy to post from CI. A cheap model reads the files in batches and writes short notes on what each one does and what it reports. A stronger model then reads those notes alongside a deterministic gather of the last 30 days of your own events, and writes the findings. Neither stage is given tools.

Those notes are kept, and your source is not. A scan builds a standing model of the repository: per file, the path, a hash of its text, and our one-line note about it, plus a repository-level read of the architecture, the modules, and which telemetry the code does and does not send. There is nowhere in it to put your code. The next scan compares hashes against that model and re-reads only what changed, which is both why a rescan is priced at a floor rather than by repo size and why the findings get sharper each time: the model that writes them is looking at the whole repository, not at the diff you happened to send. Because it does read the whole repository, a very large one is quoted at its size tier instead of the floor.

Your analyst can read that model too, and so can your own agents over MCP, through get_code_brief. That is what lets an answer about a funnel that dies at step three come back with the reason: not that players quit, but that nothing in the code reports the step.

Only code is read, and only so much of it: eight source extensions, files up to 100 KB, at most 6,000 files, with dependency and build directories skipped. Binaries are detected and dropped rather than counted. Every run carries a hard token budget, so a repo that turns out larger than it looked stops at the budget and reports what it got rather than spending without limit.

Scanning on every push

Connect GitHub once and a push scans what changed, without anybody uploading anything. Open Code in the dashboard and press Connect GitHub, which installs the Ravensight app on the account or organization that holds your repositories. You choose which repositories it can see, and you can change that on GitHub at any time. Connecting is an owner action, because a connected repository can spend your balance without anybody watching.

Ravensight asks for two read permissions and no write permissions: Contents and Metadata, both read-only. That is enough to read files, the commit tree and a diff between two commits, and it is not enough to push a branch, open a pull request, comment, or change a setting. Nothing in the scanner writes to GitHub.

Then attach a repository to a game, on the same screen. One repository belongs to one game: that is what lets a push know whose telemetry to read it against. A game with a client repo and a server repo keeps a separate model of each, and a change to one is never priced as a change to the other.

Only the default branch scans. A push to a feature branch is acknowledged and ignored, on purpose: the question the scan answers is what your shipped game reports, and a branch is not that yet. If nothing happens after a push, this is the first thing to check.

What a push spends, and how to stop it

A push scan charges the balance by itself, up to $3 a day per repository. Past that ceiling the scan is queued instead and waits for somebody to approve it in the dashboard, where the price is shown before you agree to it. You can raise the ceiling per repository, or turn auto-charge off entirely with Scan every push automatically, in which case every push queues and nothing is ever charged unattended.

The ceiling is deliberately lower than the cheapest whole-repository price, and the reason is worth knowing. Usually a push is a diff, and a diff costs a dollar. Sometimes there is no diff to read: the first push after connecting, a force push, or a rewritten history all leave us nothing to compare against, so the scan reads the whole repository and is priced accordingly. That is exactly the case that must not be charged while nobody is looking, so it goes past the ceiling and waits for you.

Disconnecting is on the same screen, per repository or for the whole studio. Pushes stop immediately. Your notes are kept, because you paid for them and they are what keeps the next scan at the rescan price rather than a first-scan price, so reconnecting later does not mean buying the same reading twice. Deleting the game is what deletes them.

What you get back

Findings, not patches. Each one names a kind (instrumentation_gap or risk), a severity, the file and lines, a short evidence quote, a hypothesis and a suggestion. Nothing rewrites your code, and nothing is committed anywhere.

What it costs

The first scan of a repository is a fixed price by the size of the source that survives the filter, drawn from your prepaid balance: $5 under 250 KB, $10 under 1 MB, $25 under 4 MB and $50 under 16 MB. Past 16 MB of surviving source a scan is refused rather than priced.

Every scan after that is priced on what actually changed. We compare a hash of each file you send against the hash in our notes, and only the files that differ are read and paid for: $1 while the changed source is under 250 KB, and otherwise the tier that change set belongs to on its own. Nothing is taken on trust here, and there is no flag you can set to claim a discount. Two consequences follow, both in your favor. Resubmitting a repository with nothing changed in it is free and does not run, because there is no work to do. And a change set is measured against our notes rather than against the last submission's size, so a 900 KB edit to a 1 MB repository is priced as 900 KB of work instead of as a second full scan.

Pricing is per repository, not per game. A game with a client repo and a server repo keeps a separate model of each, and a change to one is never priced as a change to the other.

Sizing is free: ask for a quote first and you see the price, what changed, and the token estimate before any money moves. Scanning needs an admin role or above, because it spends the balance. Connecting a code host so that pushes can scan on their own is a step further and is owner only: a scan spends a quoted amount once, while a connected repository is standing permission to spend. Whether that connection is available at all depends on how the deployment you are using is configured, so treat a visible connect button as an offer rather than a promise.

If a run stops early on its token budget you pay for the source it actually read, at that size's tier and never more than you were quoted, and you keep the findings and notes it produced. If a run fails outright you are refunded in full and its notes are unwound, so the next scan is priced honestly as a first scan rather than as a cheap diff against a half-written model.

14. Design studio

Plan the next game against what you already learned

The analyst tells you what happened. The design studio is where you decide what to do about it, with your studio's own history in the room.

Documents

Write and keep your design documents here. Each one keeps its recent versions, so you can see what a draft replaced. The studio chat can propose an edit to the document in front of you, and proposing is all it does: the markdown comes back to you and nothing changes until you accept it.

The risk check

Describe something you are about to build and Ravensight retrieves your studio's relevant findings first, then grades the plan against them: repeat, caution or clear, with the findings it relied on cited. A citation that cannot be mapped back to a real finding is dropped rather than shown, so the verdict can never point at a source that does not exist. If your studio has no relevant history yet, it says so instead of inventing a verdict.

Design chat and risk checks each use one shared AI unit per completed bounded action, including internal tool steps. Failed, undelivered work is refunded. Ravensight manages provider keys; reading and editing saved documents does not use AI units.

15. Playtest

Send an AI persona through your build before a player does

Ravensight Playtest is a CLI you run against your own build. It hands your game to a handful of AI personas, each with a different way of playing, and brings back a written report per persona: what worked, what they got stuck on, and whether they would have kept playing. The personas' sessions land in the same dashboard as your real players, tagged so they never touch your real numbers unless you ask for them.

Before you start

You need Node 22 or later, a Ravensight game with an ingest key already set up, and a balance on your account. A playtest run spends from the same prepaid balance as everything else here: no card, no subscription, and nothing runs without balance to cover it.

Registering a run spends money, so it needs an admin role or above. Reading past jobs, findings and reports needs only a read-only role, and writing a brief or marking a finding needs a member role.

Playwright is an optional dependency, so login, check, init and brief work on a machine with no browser installed; only a web-driver run asks for one. The credential store is optional too, which is why a machine with no keychain still installs cleanly.

Sign in and point it at a game

The CLI never asks for a password and never holds an Anthropic key. Signing in mints a short device code, which you approve from the dashboard rather than typing anything back into the terminal.

Sign in

npx ravensight-playtest login

This prints a short code and a link. Open the link, or go to app.ravensight.io/cli and enter the code yourself, then pick which of your games the CLI should be able to touch. The terminal picks up the approval on its own once you confirm it.

The token lands in your operating system's credential store: macOS Keychain, Windows Credential Manager, libsecret on Linux. With none available it falls back to a file readable only by you, and says which store it used. For CI, set RAVENSIGHT_TOKEN and skip login entirely. logout revokes the token on the server and forgets it locally, and deliberately leaves a token that came from RAVENSIGHT_TOKEN alone, because that is probably a CI secret other jobs share. An org owner can revoke every token a member holds in that org at once from Settings.

Connect a project to a game

npx ravensight-playtest init --game <gameId>

Run this once per project. It writes a small local config file next to your code so every later command knows which game it is talking about.

Connect your build

Ravensight Playtester 0.2.4 connects browser builds, Godot projects, local desktop and mobile automation servers, and custom game bridges. Native adapters are experimental until tested against your build and device. Console builds need your own authorized tooling.

Install the current runner

npm install --global https://www.ravensight.io/downloads/ravensight-playtest-0.2.4.tgz

Choose a build type on the Playtester page for its run command. Desktop and mobile use a local Appium-compatible server. Custom bridges exchange bounded game controls through JSON-RPC, with no model access to a shell. Read the complete adapter setup and protocol guide.

Write the brief

Before the first run, a persona needs to know what your game is and what you actually want to learn. The quick brief asks for three things: your goals for the session, what would count as success, and how to get the build running, meaning the controls and how to start it.

npx ravensight-playtest brief

Four fields make a brief complete: at least one goal, what success looks like, how the game is controlled, and how to start it. The brief is versioned, so every save keeps the version before it and you can see what changed between runs. If someone else saved a newer version while you were editing, the CLI tells you rather than overwriting it. A job registered with an incomplete brief is refused, except a game-profile-only run, which does not need one. brief --show prints the current one, --open hands you the dashboard form instead, and --from <file> reads the fields from JSON for an unattended setup.

Check, then run

check confirms the CLI is signed in, your token is valid, the game is visible to it, your balance covers what you are about to ask for, and that anything the run needs locally, such as Godot or a browser, is where it expects. Run it any time something seems off, and it costs nothing.

npx ravensight-playtest check

run is the one that spends money. It prints the price before charging anything: how many persona runs, whether a game profile is included, and the total against your balance. Nothing is debited until you confirm that number, and if the price has moved since you last checked, the CLI shows you the new one instead of silently charging it.

npx ravensight-playtest run

By default a run picks two personas from the pack of eight, and you can ask for specific ones with --personas or for all of them instead. There is no product cap on how many you ask for, only a runaway-loop ceiling of 100 personas in one job. Past eight, the price comes with a note about the clock: a job has 90 minutes of wall time in total and one run can take up to 15 of them, so the later runs in a very large job may never get to play. Nothing is lost if they do not, because a run that did not play is refunded when the job settles; split it into two jobs if you want everything played. Asking twice for the same persona, or for one this game does not have, is refused before anything is charged.

--driver chooses between the web and Godot drivers, with --build-url or --godot-project naming the target, --concurrency setting how many personas play at once (two by default, and check recommends a number for your machine), --max-actions capping one persona's turns, and --upload-video and --upload-transcript adding the two opt-in artifacts. --dry-upload prints every file and byte that would be sent and sends nothing. --json and --yes are the pair CI wants, since a confirmation prompt with no terminal counts as no.

npx ravensight-playtest profile is the other billed command: it has a persona read your codebase alongside the brief, with the same price-then-confirm step, and is priced and refunded the same way a persona run is.

Exit codes are meant for CI. 0 is success, 1 a failure, 2 a budget exceeded with partial results written and uploaded, 3 a failed environment check, 4 a failed authentication, 5 a model error after retries, and 10 canceled. Treating 2 as a success with a warning is usually what you want.

Fix a finding

Attempt a fix on a branch

npx ravensight-playtest fix <jobId>/<label>

A fix is one attempt at the smallest change that removes one finding, made on a branch in your own checkout, for $5.00. The CLI checks your repository first, refusing a dirty tree unless you pass --allow-dirty, then creates a branch (--branch names your own), plans the change against actual files, edits only those, and replays the persona that found the problem against your edited working tree so the server can judge whether the same failure came back. --no-verify skips that replay and --max-actions caps the edit loop. Nothing under addons/, .godot/ or .ravensight/ is ever edited.

It never commits and never pushes. What you get is a branch, the files it changed with their line counts, the verdict, and the exact command to open a pull request. You read the diff and decide.

Two outcomes cost nothing: a fix that concluded the right edit was no edit, and a finding that turned out to be the game working as designed. Both refund the whole $5.00 when the job settles, and the ledger names which one it was. Your source never leaves your machine: the changeset that uploads carries the paths, the line counts, the verdict and the pull request text, and no diff.

When something stops halfway

A run that was interrupted, by a sleeping machine, a crashed build or your own Ctrl-C, is picked back up by resume. It keeps the runs that finished, replays the rest, and never charges twice: the registration is replayed under the job's own idempotency key, which answers with the stored job rather than pricing a new one. resume with no job id lists the jobs this project has a journal for, and --status reports without restarting anything.

npx ravensight-playtest resume
npx ravensight-playtest upload <job>

upload drains whatever finished locally but did not finish uploading. It is safe to run repeatedly, because each file is matched by checksum and one already sent is skipped. After one online fetch the content pack is cached and verified by hash, so a run survives the network going away for everything except the model calls themselves; uploads and progress reports queue and flush when the server is reachable again.

While a run plays

Each persona plays your build for as long as its budget allows, then writes a report: a markdown write-up, structured findings with severities and repro steps, and the screenshots it took along the way. Those upload automatically as each run finishes, and appear on the job's page in the dashboard.

A persona plays through your own Ravensight SDK, so its session writes real events into your events table, exactly like a player's would, tagged synthetic. Every reader in the dashboard, the analyst, run_sql, the rollups and your own MCP tools excludes those rows by default, so a pack of personas running overnight never moves your retention or your funnel numbers. Turn on the Include AI personas switch on Overview, Player insights or Events when you want to look at them on purpose, on their own or alongside real players. Those are the three pages that carry it.

A web build driven through Playwright has no SDK of its own to play through, so the CLI emits that session itself and needs the game's ingest key to do it: put it in .ravensight/config.json as ingest_key, or export RAVENSIGHT_INGEST_KEY for the run. Without one the run still completes and reports; it just sends no telemetry. A Godot build talks to the SDK it already ships, which carries its own key.

If a run never gets far enough to produce anything useful, the charge for it is refunded automatically. You are billed for runs that happened, not for runs you paid to start.

Findings, marks, and what to remember

Open a finished job from the dashboard, or jump straight to it from the terminal:

npx ravensight-playtest open <job>
npx ravensight-playtest review <job>

Each finding can be marked as you go through it: confirmed real, intended behavior, a duplicate of another finding, one you could not reproduce, wrongly rated on severity, or too vague to act on. Marking something intended offers to remember it, and remembering it turns it into a design-intent note attached to your game. The next brief a persona reads includes that note, and the next run's findings suppress the same thing again under "suppressed as intended" instead of reporting it as new.

A fix job's own page shows a Fix card above its runs: the finding it targeted, the branch, the files it changed, and the verify verdict in words. Its "Copy pull request text" button reads the same pull request body the CLI printed and copies it, so the terminal is not the only place to get it from.

How a persona plays your build

For a web build, a persona plays through a driver built on Playwright: it sees the running page, clicks and types the same way a person would, and reads back whatever your game reports.

For a Godot project, the CLI copies your project into a temporary directory, injects a driver addon into that copy only, and launches it there. Your project on disk is never modified. If you implement _ravensight_state() on a node in the ravensight_state group, the driver reads it too, so a finding can cite the exact level, menu, or scene your persona was looking at. See "Playtest mode" in the Godot SDK guide for the details.

The addon only ever activates deliberately. It needs a flag on the command line or an environment variable, it binds to localhost and nothing else, it demands a per-run token before it will answer any other call, it takes one client at a time, and it frees itself the moment any of that fails. A release export does not contain it unless the preset asks for it by feature tag.

Do not playtest a Godot game headless. Headless Godot routes no synthesized mouse or GUI input, so a click on a button does nothing and nothing takes keyboard focus. That makes headless a smoke test mode rather than a playtest mode for anything with a user interface. On a machine with no display, run a windowed Godot under a virtual framebuffer such as Xvfb instead. The CLI prints this in the run's console log when it launches headless.

Video from the Godot driver is a sequence of frames rather than a container, so stitching it into one file needs ffmpeg, and ffmpeg stays optional.

What leaves your machine

Your source code and your build never leave your machine. The prompts a persona reads, including your brief, and what it observes while playing transit Ravensight on the way to Anthropic, metered but not kept. What uploads to Ravensight is exactly the reports, screenshots, and bookkeeping named on a fixed allowlist, nothing else. The dashboard's What leaves your machine page lists that allowlist against the code that enforces it, so it never drifts out of date with what actually ships.

Retention

Reports, findings, marks, and briefs are kept for as long as the game exists. Session video and the full action transcript, both opt-in, are kept for 90 days and then dropped.

What it costs

Playtest spends from your prepaid balance, the same one as everything else on this page. Each persona run is currently $1.00, a game profile is currently $4.00, and a fix attempt is currently $5.00. The price is charged when a job registers and refunded for any run that never produced a report, so what you keep paying for is what you actually got. A fix attempt includes the persona replay that verifies it, and is refunded in full when the fix changed nothing or the finding turned out to be design intent.

Fix a finding with your own coding agent

A finding is only useful once something changes because of it, and that fix happens in your own editor or agent, not in Ravensight. With an MCP token (see Analytics MCP Docs MCP (free)), your own coding agent can find the job with list_playtest_jobs, list its findings with list_playtest_findings, read the full report with get_playtest_report, then edit the code and open a pull request itself, exactly as it would for any other change. Ravensight never writes to your repository: those three tools are read-only, and everything from there is your agent working in your own checkout with your own tools.

Getting help

Report an issue or follow along with the CLI itself at the ravensight-playtest repository, or reach us directly at support@realityse.com.