> ## Documentation Index
> Fetch the complete documentation index at: https://crosslink.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

> All configuration options

## Host configuration

```js theme={null}
createCrosslinkServer({
  application: { ... },
  mobile: { entry: "./mobile/index.html" },
  capabilities: [ ... ],
  signalingUrl: "...",
  relayUrl: "...",
  lan: { ... },
  pairing: { ... },
  networkMode: "auto",
  logger: ...
});
```

### application

Identity and branding. Crosslink-owned screens, the generated manifest and the
generated icons all come from here, so it is stated once.

| Property          | Type                          | Required | Description                                                           |
| ----------------- | ----------------------------- | -------- | --------------------------------------------------------------------- |
| `id`              | `string`                      | Yes      | Unique application identifier (reverse-domain recommended)            |
| `name`            | `string`                      | Yes      | Human-readable name                                                   |
| `version`         | `string`                      | No       | Semantic version                                                      |
| `shortName`       | `string`                      | No       | Home-screen tile label. Defaults to `name`                            |
| `icon`            | `string`                      | No       | Icon URL or path. A tile is generated from `accentColor` when omitted |
| `accentColor`     | `string`                      | No       | Actions, and the tint applied to the Crosslink mark                   |
| `backgroundColor` | `string`                      | No       | Background of Crosslink-owned screens                                 |
| `textColor`       | `string`                      | No       | Primary text. Derived from the background when omitted                |
| `appearance`      | `"light" \| "dark" \| "auto"` | No       | Forces a palette instead of deriving one                              |

See [Branding and Theming](/client/branding). There is no option that replaces
Crosslink's screens or removes its mark and attribution.

### mobile

Your mobile application, and where Crosslink should serve it. Setting `entry`
turns on the built-in bootstrap: Crosslink then owns the manifest, service
worker, icons, browser SDK, install handoff and every onboarding screen.

| Property       | Type                 | Description                                                                  |
| -------------- | -------------------- | ---------------------------------------------------------------------------- |
| `entry`        | `string`             | Path to your mobile HTML entry point                                         |
| `assets`       | `string \| string[]` | Extra directories served beside the entry                                    |
| `capabilities` | `string[]`           | Capabilities the mobile client requests at pairing. Defaults to all declared |
| `enabled`      | `boolean`            | Set `false` to serve nothing automatically and keep a custom handler         |

See [Mobile Bootstrap](/client/mobile-bootstrap).

### capabilities

Array of capability objects:

| Property         | Type                          | Required | Description                                                         |
| ---------------- | ----------------------------- | -------- | ------------------------------------------------------------------- |
| `id`             | `string`                      | Yes      | Unique identifier (dot-separated namespace)                         |
| `title`          | `string`                      | Yes      | Human-readable name                                                 |
| `risk`           | `"low" \| "medium" \| "high"` | Yes      | Risk level                                                          |
| `description`    | `string`                      | No       | Detailed explanation                                                |
| `defaultGranted` | `boolean`                     | No       | Granted by default at pairing when the client requests it           |
| `confirmEachUse` | `boolean`                     | No       | Require a fresh user confirmation on every use, not just at pairing |

### signalingUrl

`string` -- URL of the signaling server (enables QR pairing across networks). No default is hardcoded; when unset it is auto-discovered from `.crosslink-data/stack.json` if a local `npm run stack` is running, or left unconfigured.

### relayUrl

`string` -- URL of the relay server (enables connectivity behind NATs). Same auto-discovery as `signalingUrl`.

### relayUrls

`string[]` -- Ordered regional relay fallbacks. Allocation tries the first healthy
validated endpoint and re-allocates after a regional/channel failure.

### lan

| Property      | Type                                  | Description                                                                                                                                                                                             |
| ------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`     | `boolean`                             | Enable the LAN listener (default: `true`)                                                                                                                                                               |
| `port`        | `number`                              | Port to bind (default: an ephemeral port, remembered across restarts)                                                                                                                                   |
| `bind`        | `"loopback" \| "all"`                 | Bind address (default: `"loopback"`)                                                                                                                                                                    |
| `host`        | `string`                              | Address to advertise for LAN pairing when `bind: "all"`. Overrides auto-detection (first non-internal interface, unreliable with more than one active network) — also settable via `CROSSLINK_LAN_HOST` |
| `httpHandler` | `(req, res) => void \| Promise<void>` | Serves your own HTTP on the transport port. Only needed when you are *not* using `mobile.entry` — Crosslink otherwise mounts its bootstrap here                                                         |

### pairing

| Property                | Type                                                                           | Description                                                                                                                                                                                                          |
| ----------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ttlMs`                 | `number`                                                                       | Pairing code/session TTL                                                                                                                                                                                             |
| `autoApprove`           | `boolean`                                                                      | Dev convenience: skip human confirmation. Never grants above policy. Never for production                                                                                                                            |
| `approve`               | `(req: PairingApprovalRequest) => PairingApproval \| Promise<PairingApproval>` | Pairing approval callback                                                                                                                                                                                            |
| `notifyApprovalRequest` | `(req) => void \| Promise<void>`                                               | Raise a push/native notification before local approval. Delivery cannot approve by itself                                                                                                                            |
| `bootstrapUrl`          | `string`                                                                       | Published `https` origin of Crosslink's static bootstrap. Makes an installed app durable across host address changes — generate it with `host.writeStaticBootstrap()`. See [Durable Origins](/client/durable-origin) |

### mdns

| Property  | Type      | Description                                               |
| --------- | --------- | --------------------------------------------------------- |
| `enabled` | `boolean` | Advertise a `_crosslink._tcp` LAN candidate after startup |
| `name`    | `string`  | Local service display name                                |

mDNS results are untrusted discovery candidates, never identity evidence. The SDK
accepts only local addresses and valid app/fingerprint/version/port metadata; the
authenticated handshake still pins the host.

### groups

| Property             | Type      | Description                                  |
| -------------------- | --------- | -------------------------------------------- |
| `enabled`            | `boolean` | Register the built-in group RPC/capabilities |
| `maxGroups`          | `number`  | Maximum live host-mediated groups            |
| `maxMembersPerGroup` | `number`  | Maximum members in one star session          |
| `maxPayloadBytes`    | `number`  | Maximum host-routed group payload            |
| `inviteTtlMs`        | `number`  | Device-bound invite lifetime                 |

### security

| Property                   | Type                                      | Description                                                                 |
| -------------------------- | ----------------------------------------- | --------------------------------------------------------------------------- |
| `maxDevices`               | `number`                                  | Maximum non-revoked paired devices                                          |
| `maxActivePairingSessions` | `number`                                  | Maximum live single-use pairing sessions (default 10)                       |
| `pairingRateLimitMs`       | `number`                                  | Minimum pairing-code creation interval per caller/global key (default 5000) |
| `localNetworkOnly`         | `boolean`                                 | Reject non-local LAN socket peers                                           |
| `hybridPq`                 | `"disabled" \| "preferred" \| "required"` | Hybrid X25519 + ML-KEM-768 policy                                           |

### networkMode

`"auto" | "local-only" | "lan-and-relay" | "remote"` -- Which transports the host offers. `auto` (default) uses LAN plus whatever remote path is configured or discovered; `local-only` disables signaling, relay, tunnel, and port mapping entirely; `lan-and-relay` uses LAN plus the configured relay/signaling services; `remote` requires a working outside-the-network route and fails startup loudly if none can be established.

### remote

Direct inbound access from the internet, via a router port mapping (PCP, NAT-PMP, UPnP) or a port you forwarded by hand. See [Remote Access](/guides/remote-access).

| Property          | Type      | Description                                                                                                                                                          |
| ----------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`         | `boolean` | Default: on for `networkMode: "remote"` or when `portForwarded`/`publicHost` is set, off otherwise                                                                   |
| `externalPort`    | `number`  | Public port to request or advertise. Defaults to the LAN listener's port                                                                                             |
| `lifetimeSeconds` | `number`  | Mapping lease. Default 7200, renewed at 75% of the lease                                                                                                             |
| `autoRenew`       | `boolean` | Set false to let the lease lapse instead of renewing it                                                                                                              |
| `portForwarded`   | `boolean` | No mapping is negotiated: a port-forward rule was added in the router by hand. The public address is advertised on that word alone (`confidence: "manual"`)          |
| `publicHost`      | `string`  | Public address or dynamic-DNS hostname to advertise instead of the STUN-discovered one, so a stored endpoint survives an ISP address change. Implies `portForwarded` |

***

## Client configuration

```js theme={null}
CrosslinkClient.create({
  deviceName: "...",
  storage: ...,
  onStateChange: ...,
  onConfirmPairing: ...,
  logger: ...,
  dialTimeoutMs: ...,
  hybridPq: "preferred",
  allowPlaintextFallback: ...
});
```

### deviceName

`string` -- Device name shown to host.

### storage

`SecureStorage` -- Custom storage backend. Default (via `.create()`): IndexedDB-backed, encrypted with a non-extractable WebCrypto key when available.

### onStateChange

`(state: ConnectionState, detail?: Record<string, unknown>) => void` -- State change callback.

### onConfirmPairing

`(req: PairingConfirmRequest) => boolean | Promise<boolean>` -- Pairing confirmation.

| Property      | Type       | Description                                           |
| ------------- | ---------- | ----------------------------------------------------- |
| `sas`         | `string`   | Short Authentication String shown on both devices     |
| `hostName`    | `string`   | Host application name                                 |
| `hostFp16`    | `string`   | First 16 hex chars of the host's identity fingerprint |
| `grantedCaps` | `string[]` | Granted capabilities                                  |

### logger

`Logger` -- Custom logger implementation (must implement `trace`, `debug`, `info`, `warn`, `error`, `child`, `isEnabled` — use `consoleLogger()` from `@crosslink/core` for a ready-made one).

### dialTimeoutMs

`number` -- Max time to wait for a WebSocket to open before giving up. Default: `10000`.

### allowPlaintextFallback

`boolean` -- Only accepted by `CrosslinkClient.create()`, not the plain constructor. Allows falling back to unencrypted storage when WebCrypto/IndexedDB is unavailable.

***

## Environment variables

| Variable                  | Default             | Description                                                                                                                                     |
| ------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `CROSSLINK_SIGNALING_URL` | *(auto-discovered)* | Signaling server URL                                                                                                                            |
| `CROSSLINK_RELAY_URL`     | *(auto-discovered)* | Relay server URL                                                                                                                                |
| `CROSSLINK_SECRET_KEY`    | *(none)*            | Passphrase for encrypted file storage                                                                                                           |
| `CROSSLINK_DATA_DIR`      | `.crosslink-data`   | Dev tokens and local stack config (`@crosslink/dev-tokens`). A host's identity and device store go under its `storageDir` config field instead. |
| `CROSSLINK_LAN_HOST`      | *(auto-detected)*   | Address advertised for LAN pairing (`lan.bind: "all"`); set on a multi-network host so phones/tablets get an address they can actually reach    |

***

## Service configuration

Both services read configuration from CLI flags (`--port`, `--host`, `--auth-token`) or the environment variables below; `PORT`/`HOST` win over a positional/flag port, and an explicit token always wins over the per-machine dev token fallback.

### Signaling (`services/signaling`)

| Variable                    | Default                   | Description                                                         |
| --------------------------- | ------------------------- | ------------------------------------------------------------------- |
| `PORT`                      | `8081`                    | HTTP/WebSocket server port                                          |
| `HOST`                      | `0.0.0.0`                 | Bind address                                                        |
| `CROSSLINK_SIGNALING_TOKEN` | *(per-machine dev token)* | Shared secret hosts must present to register presence               |
| `CROSSLINK_REGION`          | *(none)*                  | Advertised in `/health` for operators                               |
| `CROSSLINK_REDIS_URL`       | *(none)*                  | Redis/Redis-TLS URL for shared presence, codes, and pub/sub routing |

### Relay (`services/relay`)

| Variable                        | Default                   | Description                                                  |
| ------------------------------- | ------------------------- | ------------------------------------------------------------ |
| `PORT`                          | `8082`                    | HTTP/WebSocket server port                                   |
| `HOST`                          | `0.0.0.0`                 | Bind address                                                 |
| `CROSSLINK_RELAY_TOKEN`         | *(per-machine dev token)* | Shared secret hosts must present to allocate a channel       |
| `CROSSLINK_RELAY_CLIENT_TOKEN`  | *(none)*                  | Shared secret clients must also present, if set              |
| `CROSSLINK_RELAY_MAX_CLIENTS`   | `8`                       | Max concurrent clients per relay channel                     |
| `CROSSLINK_RELAY_MAX_CHANNELS`  | `1024`                    | Max allocated channels on the process                        |
| `CROSSLINK_RELAY_MAX_BYTES`     | *(unlimited)*             | Lifetime bytes per channel                                   |
| `CROSSLINK_RELAY_BYTES_PER_SEC` | *(unlimited)*             | Token-bucket bandwidth per channel                           |
| `CROSSLINK_RELAY_PUBLIC_URL`    | *(none)*                  | Validated public HTTPS URL for this region                   |
| `CROSSLINK_RELAY_REGIONS`       | *(none)*                  | JSON region catalog (`id`, HTTPS `url`, optional `priority`) |

***

## TypeScript configuration

Both SDKs ship with TypeScript declarations. No `@types` packages needed.

```json theme={null}
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2022"
  }
}
```
