Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Production checklist

This page gathers the items you will tick off one by one before going live. Each item comes with a short reason and links to the relevant page. Review the list once before launch and again after every major change.

1. Network and hosting

  • Everything is HTTPS. Session cookies have the __Secure- prefix and carry the Secure flag; a session cannot be established over plain HTTP. Sockets are opened with wss://. If you use http://localhost in local development, verify your browser’s localhost exception.
  • Browser call path chosen. Either the game’s domain is in an environment’s domain list and the game calls Open Play directly (the server sends CORS headers; the game and Open Play must be subdomains of the same registrable domain, otherwise the SameSite=Lax session cookie is not sent), or the game calls the API from under its own domain through a reverse proxy (architecture and hosting).
  • The proxy forwards these headers as they are: Authorization, Cookie (and Set-Cookie in the response), Origin, x-crx-env, x-csrf-token, Idempotency-Key, If-Match, x-crx-schema-version, Sec-WebSocket-* (including subprotocol and extension negotiation). It does not strip the response headers (x-csrf-token, Deprecation, Retry-After, ETag).
  • The WebSocket upgrade is open on the proxy, the Upgrade/Connection headers are forwarded, and the connection can stay idle for at least 5 minutes (the server does the idle close itself: limits).
  • The request body limit is at least 2 MiB. The server rejects anything above 2 MiB with 413; your proxy should not set a lower limit.
  • Timeout: the proxy’s response-header wait time does not cut off long operations (Open Play’s own gateway uses 65 s).
  • The client IP is forwarded. The rate limits on the identity endpoints depend on the client IP. If the proxy does not add X-Forwarded-For, all players gather in a single bucket (for example guest opening is 30 per minute). If multiple proxies are chained, the operator must define the trusted proxy blocks.
  • The panel path is closed to the internet. The /v1/panel/* path returns 404 on the public gateway; the panel is reached only from the management network or from a separate domain.
  • Caching: API responses that carry a cookie or Authorization are not put in a shared cache (CDN). Only public, content-addressed responses (/v1/assets/{sha256}, /v1/model-files/{sha256}) and catalog responses that carry an ETag are subject to an appropriate caching rule.

2. Environments and domains

  • You use separate environments for development, staging, and live; data is not shared.
  • Each environment’s domain is defined in the panel (Game settings: environments); this is the allowed Origin list.
  • The correct environment ID (the x-crx-env value) is in the client configuration; the live client does not point to the staging environment.
  • Only the needed modules are on (modules). A disabled module returns 404 module_disabled; every module you leave on is an attack surface.
  • Sign-in methods are configured in the panel (guest, email, Google); the methods you do not use are off (Sign-in methods).

3. Keys and secrets

  • Server keys are only on the server. They are not in the client bundle, the mobile app, the WebGL build, or the repository (security).
  • A separate key per environment and service; the keys have been given an expiry date.
  • If you use a client key, you have verified that you know which endpoints it can call; player operations are done with the player session (endpoints).
  • A key rotation rehearsal was done: second key, rollout, revoke the old one.
  • Keys and tokens are not in the logs; Authorization, Cookie, and x-csrf-token are filtered.
  • The webhook secret is in your receiver’s secret manager; because it is shown only once at registration, it has a backup.

4. Replay safety and concurrency

  • Every call that grants money, items, rewards, or sends a command carries an Idempotency-Key; the key is generated once and used exactly on repeats (idempotency).
  • On an uncertain outcome (timeout, network drop), the command is completed with the same key, not a new one, or with the result query.
  • Calls that write a shared resource send If-Match/expectedVersion; on 409 the state is re-read.
  • There is exponential backoff + jitter on 429, 503, and network errors; Retry-After is respected (rate limits).
  • Error handling is by status code; the plain-text message is not parsed (errors).

5. Player identity

  • The session-loss flow is set up: session refresh when 401 arrives, otherwise sign in again; a separate screen for a banned account (sessions and CSRF).
  • The guest identity’s storage behavior and the upgrade flow to email or Google are set up (guest progress is kept with the upgrade).
  • Your game server verifies the access JWT with the JWKS, checking the expiry and environment fields (server verification).
  • The identity rate limits (guest 30/min, email sign-in 5/min, sign-up 10/min, per IP) can carry your expected launch traffic; a load test was done if needed.

6. Realtime

  • The client uses the SDK or implements the protocol (ticket, Origin, subprotocol) completely (protocol).
  • Reconnect: a new ticket on every connection, exponential backoff, Join with the last cursor on durable streams, Join without a cursor on ResyncRequired (reconnect).
  • There is a “Continue” screen for idle close (4100); a keep-alive input is sent on pause screens.
  • The frame rate is below 40/s; the limit of 4 tabs/sockets per player is known.
  • The notification and chat sockets cannot be opened directly from the browser (header restriction); inbox polling or the REST endpoints are used (realtime overview).

7. Plugins

  • The schema digest (schemaSha256) of the plugin you use is written into your release manifest and the bindings were generated with this digest (bindings).
  • A digest comparison (at startup or in CI) is done after a server update.
  • The plugin’s state in the environment is enabled (Plugins); this is the first place to look for an unexpected 403 forbidden.
  • A migration task was opened for calls that carry the Deprecation header (versioning).

8. Webhooks

  • The endpoint is https; the signature is verified on every request, the timestamp window is checked, and deduplication is done with X-Crx-Event-Id (security).
  • The receiver returns a fast 2xx (queues the work); there is a monitoring plan for deliveries that end up failed (DLQ) after 10 attempts (Webhooks and event queue offers only monitoring, there is no resend); you have a way to make up for missed events by reading the relevant resource with REST.

9. Observability and operations

  • Your request log has the status code, duration, called path, and (on plugin endpoints) x-request-id; there are no secret values.
  • You have an alert for the 5xx and 429 rate; it was verified that 503 + Retry-After responses are retried.
  • Panel admin accounts are personal and two-factor authentication is on (Panel operators).
  • The operation history is reviewed regularly; the safety switches are in their default position (if you changed them deliberately, the reason is recorded).
  • The SDK version is pinned exactly (no ^); upgrades are followed from the changelog (versioning).

10. Final rehearsal before launch

  1. Run the end-to-end flow in a staging environment similar to the live one: sign-in, reward, purchase, socket connection, connection drop, and reconnect.
  2. Deliberately send the same request twice with the same Idempotency-Key; verify that the second response returns the same result.
  3. Revoke a server key once and observe the switch to the second key.
  4. Send a request with a wrong signature to your webhook receiver; verify that it rejects it.
  5. Do a trial on the identity endpoints that imitates your launch traffic; look at the 429 rate.

If problems come up, see the troubleshooting page.