arcnet.
DEVELOPER DOCUMENTATION

BUILD WITH
arcnet.

Use arcnet. to admit players, create rooms, discover matches, exchange messages and signal peer connections. Keep your game logic in your own backend or dedicated server.

GET STARTED

Your first connection

ArcNet separates developer accounts from game players. You manage games and service credentials in the Developer Console. Provide a public Game ID and a Player ID to the SDK. ArcNet handles transport authorization internally. If you have accounts or a trusted backend, pass your existing account ID as the Player ID.

  1. Create your developer account. Register with your email and password, then sign in.
  2. Create a workspace and game. Open the console, create an organization, then create a game with Relay mode for the simplest first test.
  3. Configure browser origins. Add the exact origin hosting your game, for example http://localhost:3000. Origins are configured per game, not per developer login.
  4. Connect your game client. Add your Game ID to the ArcNet SDK and provide your game’s Player ID when connecting. If none is provided, ArcNet assigns a temporary ID.
  5. Join a room. Create a room or use matchmaking; connect players using their own distinct Player IDs.
  6. Ship your game. The SDK handles network authorization automatically. Do not put a private service credential into a browser or Unity client.

Before you begin: ArcNet manages the networking infrastructure. Create a game service in your console, add your allowed browser origins, and use unique Player IDs from your game. Private credentials are needed only for trusted backend integrations and should never be embedded in shipped clients.

AUTHENTICATION

Player IDs and server credentials

The Game ID identifies the game. The Player ID identifies a specific player, and a previously supplied Player ID is preserved as their networking identity. Without an ID, the SDK generates a temporary one. Client-supplied IDs are not proof of account ownership; use your own authenticated backend for trusted account identities. Private sk_arc_ server credentials must never be embedded in browser, WebGL or compiled Unity clients.

GAME IDPublic identifier
GAME SECRETServer-side only
PLAYER TICKET90-second lifetime

Advanced: trusted backend player authorization

Most games do not call this endpoint directly. If you need to verify player accounts, your trusted backend can authorize a Player ID and call this endpoint. The SDK uses the resulting short-lived transport authorization internally. That token never becomes the Player ID.

Terminal: request a player ticket
curl -X POST "$ARCNET_PORTAL_URL/api/v1/tickets" \
  -H "Authorization: Bearer $ARCNET_GAME_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"gameId":"game_YOUR_ID","playerId":"player-123","displayName":"Player123"}'

Example trusted backend

Store ARCNET_PORTAL_URL, ARCNET_GAME_ID and ARCNET_GAME_SECRET in server-only environment variables. The production Portal is https://arcnet.inuv8studios.com. The following Node.js example assumes you already authenticated your game's player.

Node.js: trusted backend
// Run on your trusted game backend. Never ship the game secret to a client.
const portal = process.env.ARCNET_PORTAL_URL;
const gameId = process.env.ARCNET_GAME_ID;
const gameSecret = process.env.ARCNET_GAME_SECRET;

export async function issueArcNetTicket(authenticatedPlayer) {
  if (!authenticatedPlayer?.id) throw new Error('Player login required');

  const res = await fetch(`${portal}/api/v1/tickets`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${gameSecret}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      gameId,
      playerId: authenticatedPlayer.id,
      displayName: authenticatedPlayer.name,
    }),
  });

  if (!res.ok) throw new Error(`Ticket request failed: ${res.status}`);
  return res.json();
}
SDK

Connect from your game

The current browser SDK lives at packages/sdk-web in the ArcNet monorepo. It is usable within that repository's npm workspaces; it has not been released to the public npm registry. External developers can use the documented HTTP and WebSocket protocol or package the SDK for their project.

Provide your Game ID and existing Player ID. ArcNet automatically handles the short-lived transport credentials and gateway discovery. For staging, configure portalUrl with your Preview URL. Production uses https://arcnet.inuv8studios.com automatically. Only override portalUrl for staging or a custom deployment.

JavaScript: create and join a room
import { ArcNetClient } from '@arcnet/sdk-web';

// Game ID comes from your ArcNet Console. No private key or ticket helper.
// Use the same playerId assigned by your game's user/account system.
const client = await ArcNetClient.connect({
  gameId: 'game_YOUR_PUBLIC_ID',
  playerId: 'player-123',
  // portalUrl: 'https://YOUR-STAGING-PREVIEW.vercel.app', // staging only
});

console.log('Player ID:', client.playerId);
const { roomId } = await client.matchmake({ topology: 'relay', capacity: 4 });
await client.join(roomId);
client.chat('Hello from arcnet.');

For a second player, call ArcNetClient.connect with the same Game ID and that player's own Player ID, then use join(roomId). A Player ID identifies a session participant. Keep it consistent between sessions if your game has accounts.

Unity: connect with your existing Player ID

C#: ArcNetService
// ArcNetSettings asset: set Game ID once in the Unity Inspector.
// Keep private game secrets on a trusted server, never in this asset.

service.SetPlayerId("player-123");
yield return service.Connect(null, connected => {
    if (!connected) Debug.LogError("Could not connect to ArcNet");
});

// After connection, create or join a room using ArcNetService.

If your game has account authentication, integrate its trusted backend to prevent players from claiming another account's Player ID. Game IDs are public; server credentials remain private.

MATCHMAKING

Rooms and matchmaking

createRoom() always creates a new room. matchmake() looks for a compatible room and can create one if none is found. You can select Relay, P2P, Turn-based or Dedicated topology only when that mode is allowed by your game settings.

JavaScript: matchmaking and relay
// Use a new, unexpired ticket for each player.
const result = await client.matchmake({ topology: 'relay', capacity: 4, region: 'auto' });
await client.join(result.roomId);

// Relay messages are untrusted data, not validated game outcomes.
client.relay({ action: 'wave' });

// Disconnect when leaving a room.
client.close();

Rooms currently allow 2 to 32 players and expire after 24 hours. Matchmaking is a basic room directory, not a skill-ranking or tournament system. A room's WebSocket connection uses a separate, single-use ticket with a roughly 30-second lifetime.

Verify two-player connectivity

After deploying the Portal and Edge, you can run the included examples/relay-two-player-smoke.mjs from the ArcNet repository with Node.js 22+. It requests distinct tickets for two players, creates a Relay room, connects both clients and verifies message delivery.

Terminal: local two-player smoke test
# Set these privately in your shell or trusted local environment.
export ARCNET_PORTAL_URL="https://arcnet.inuv8studios.com"
export ARCNET_EDGE_URL="https://arcnet-network-edge-production.arcnet-network-edge.workers.dev"
export ARCNET_GAME_ID="game_YOUR_ID"
# Prompt without echoing the secret, then export it.
read -rs ARCNET_GAME_SECRET; echo; export ARCNET_GAME_SECRET
node examples/relay-two-player-smoke.mjs
unset ARCNET_GAME_SECRET
REFERENCE

HTTP API

Portal endpoints run on the ArcNet service. Networking endpoints use the ArcNet gateway address returned by the player ticket API.

Developer portal API

MethodPathPurpose
POST/api/v1/ticketsIssue a signed player ticket from a trusted backend using the private game secret
POST/api/v1/introspectValidate a player ticket from a trusted game server
GET/api/v1/games/:idRead an active game's public metadata with permitted authorization
GET, POST/api/console/orgsList or create developer workspaces (session required)
GET, POST/api/console/gamesList or create game services (session required)
GET, PATCH/api/console/games/:idRead or update a game configuration
GET, POST, DELETE/api/console/games/:id/secretsManage private game credentials
GET/api/console/games/:id/healthView your game's dedicated-server report (session and membership required)
POST/api/v1/games/:id/heartbeatReport your own server status (private server credential required)

Networking Edge API

MethodPathPurpose
POST/v1/roomsCreate a room with a game:connect ticket
POST/v1/matchmakeFind or create a matching room
GET/v1/rooms/:id/infoRead room status for the authorized game
POST/v1/rooms/:id/ticketIssue a room WebSocket ticket
GET + Upgrade/v1/rooms/:id/connectOpen room WebSocket with room ticket in the query string
POST/v1/iceGenerate ICE/TURN configuration when TURN is enabled
HTTP: room creation and joining
POST /v1/rooms
Authorization: Bearer <90-second game:connect ticket>
Content-Type: application/json

{"topology":"relay","capacity":4,"region":"auto"}

// Returns: {"ok":true,"roomId":"room_...","joinUrl":"https://.../ticket"}

POST /v1/rooms/room_ID/ticket
Authorization: Bearer <same unexpired game:connect ticket>

// Returns a short-lived WSS connection endpoint.
PROTOCOL

WebSocket messages

Once connected, send JSON packets with v: 1 and a supported type. ArcNet attaches the true sender ID to relayed events; you cannot claim another player's identity by setting from.

WebSocket: packets and events
// Client to room, after opening the WSS endpoint issued by /ticket:
{"v":1,"type":"PING"}
{"v":1,"type":"CHAT","text":"Hello"}
{"v":1,"type":"RELAY","data":{"action":"wave"}}
{"v":1,"type":"SIGNAL","to":"player-2","signalType":"offer","data":{}}

// Server events: WELCOME, ROOM_STATE, PONG, CHAT, RELAY, SIGNAL, PEER_LEFT

Limits in the current Edge implementation include 8 KB incoming frames, 300 characters per chat message, 4 KB serialized relay payloads and approximately 60 messages per second per connection. Relay and peer packets remain untrusted; your authoritative game server must validate gameplay outcomes.

ARCHITECTURE

Choose your networking model

Relay

Clients exchange messages through ArcNet room WebSockets. Useful for getting started; the relay does not validate physics or scores.

Peer to peer

ArcNet provides WebRTC signaling. Direct data channels need peer-side WebRTC logic, and reliable fallback requires TURN credentials.

Dedicated authority

Your own server owns the simulation and validates tickets. ArcNet does not host your game process; you may configure a WSS endpoint and send authenticated health reports from your backend.

Turn-based

Use rooms and messages for turn notifications. Validate moves and rules on your game backend.

DEDICATED SERVERS

Your server's health status

Dedicated-server health is scoped to your own game and workspace. First save a valid WSS endpoint in the Game Service page. From your trusted dedicated server, send a signed heartbeat every 30 seconds using one of that game's active server credentials.

Trusted server: dedicated heartbeat
# Run on your trusted dedicated server every 30 seconds.
# ARCNET_GAME_SECRET is a SERVER credential, not a player ticket.
curl -X POST "$ARCNET_PORTAL_URL/api/v1/games/$ARCNET_GAME_ID/heartbeat" \
  -H "Authorization: Bearer $ARCNET_GAME_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"status":"online"}'

Report online when accepting players, downtime when degraded or undergoing maintenance, and offline during controlled shutdown. A fresh report is valid for 90 seconds; missing reports display Downtime for up to 5 minutes, then Offline. A server that has never reported shows Awaiting heartbeat.

ArcNet does not probe arbitrary customer URLs. These statuses are server-reported and may be stale or inaccurate if a customer's service is misconfigured or dishonest. Only authorized members of your workspace can view them.

SUPPORT

Troubleshooting

SymptomCheck
Sign-in failsVerify the developer account, BETTER_AUTH_URL, and the database's Better Auth tables
Dashboard fails to loadVerify all ArcNet database migrations are applied to the database set by DATABASE_URL
INVALID_CREDENTIALVerify Game ID, private secret, and the portal credential pepper; generate a new secret if compromised
UNAUTHORIZEDCheck the player ticket type and lifetime, and request a fresh ticket if necessary
ORIGIN_DENIEDAdd the exact browser origin to the game's allowed origins in the console
TURN_NOT_CONFIGUREDConfigure TURN credentials before testing WebRTC relay fallback
Room WebSocket rejectedRequest a fresh room ticket and connect promptly; room tickets cannot be reused

Keep credentials private: Never place sk_arc_ secrets, database URLs, or signing keys in browser bundles. For Unity WebGL embedded in a React shell, one browser networking connection can deliver updates to the Unity presentation layer.

READY TO INTEGRATE?

Create your first game service.

OPEN DEVELOPER CONSOLE