# Strategies — server-pushed client config

Strategies let an admin push client configuration to peers centrally,
without touching each device. They are managed from the dashboard's
**Strategies** page (`/admin/#strategies`).

---

## How it works

1. **Storage.** A strategy is a row with a name and a `config_options`
   JSON object (plus an `extra` object, reserved — currently always
   `{}`). The Strategies page validates only that `config_options` is a
   valid JSON **object**; it does **not** validate the keys inside it.
2. **Delivery.** On each peer heartbeat the server resolves the
   applicable strategy and embeds it in the reply as
   `strategy.config_options`. Changes propagate within ~15 s of the
   strategy row's `modified_at` changing.
3. **Apply.** The client merges every key/value straight into its own
   options map (the same store behind "advanced settings" and the
   `--config` deploy blob). A strategy key is therefore *any* key the
   RustDesk client reads via `Config::get_option`.

### Resolution order (per peer)

The first match wins:

1. Direct peer-scoped assignment (`strategy_assignments.peer_id`)
2. Device-group assignment, via the peer's owner
3. User assignment

If nothing matches, an empty config is pushed.

### Value conventions

- **All values are strings**, even numbers (`"30"`, not `30`).
- **Boolean keys** use `"Y"` (on) / `"N"` (off). Most default to off
  when unset.
- **An empty string `""`** removes the override and lets the client
  fall back to its built-in default. (If a built-in default settings
  blob is present, an empty value instead keeps the key present.)
- Keys the client version doesn't recognize are stored, pushed, and
  silently ignored — there is **no error feedback for typos**. Verify
  against the `keys` module in `libs/hbb_common/src/config.rs` of the
  client version you deploy.

### Example

```json
{
  "enable-keyboard": "N",
  "enable-file-transfer": "N",
  "access-mode": "view",
  "image_quality": "best",
  "whitelist": "192.168.1.0/24,10.0.0.0/8",
  "verification-method": "use-permanent-password"
}
```

---

## Known config keys

The keys below are the complete set defined in the client's `keys`
module (`libs/hbb_common/src/config.rs`). Not all are equally useful in
a server-managed strategy — UI-state keys (peer tabs, toolbar, floating
window) are listed for completeness but are normally per-user.

### Access control & permissions

| Key | Values | Effect |
|---|---|---|
| `access-mode` | `full` / `view` / `custom` | Overall permission preset for incoming sessions |
| `enable-keyboard` | `Y`/`N` | Allow remote keyboard input |
| `enable-clipboard` | `Y`/`N` | Allow clipboard sync |
| `enable-file-transfer` | `Y`/`N` | Allow file transfer |
| `enable-camera` | `Y`/`N` | Allow camera access |
| `enable-terminal` | `Y`/`N` | Allow terminal access |
| `terminal-persistent` | `Y`/`N` | Keep terminal sessions persistent |
| `enable-audio` | `Y`/`N` | Allow audio |
| `enable-tunnel` | `Y`/`N` | Allow TCP tunnelling |
| `enable-remote-restart` | `Y`/`N` | Allow remote restart of the host |
| `enable-record-session` | `Y`/`N` | Allow session recording |
| `enable-block-input` | `Y`/`N` | Allow blocking local input |
| `enable-privacy-mode` | `Y`/`N` | Allow privacy mode |
| `enable-perm-change-in-accept-window` | `Y`/`N` | Allow changing permissions in the accept dialog |
| `allow-remote-config-modification` | `Y`/`N` | Allow remote side to change this host's config |
| `allow-numeric-one-time-password` | `Y`/`N` | Permit numeric one-time passwords |
| `approve-mode` | `password` / `click` / `password-click` | How incoming connections are approved |
| `verification-method` | `use-temporary-password` / `use-permanent-password` / `use-both-passwords` | Password verification mode |
| `temporary-password-length` | `6` / `8` / `10` | Length of generated one-time passwords |
| `allow-only-conn-window-open` | `Y`/`N` | Only accept connections while the connection window is open |
| `allow-auto-disconnect` | `Y`/`N` | Auto-disconnect idle sessions |
| `auto-disconnect-timeout` | minutes | Idle timeout for auto-disconnect |
| `approve-mode` | see above | (alias note: stored as `approve-mode`) |
| `enable-trusted-devices` | `Y`/`N` | Enable the trusted-devices feature |
| `allow-logon-screen-password` | `Y`/`N` | Allow password entry on the logon screen |
| `disable-change-permanent-password` | `Y`/`N` | Prevent the user changing the permanent password |
| `disable-change-id` | `Y`/`N` | Prevent the user changing the device ID |
| `disable-unlock-pin` | `Y`/`N` | Disable the unlock PIN feature |
| `enable-remote-exec` | `Y`/`N` | Allow admins to dispatch PowerShell scripts to this peer via the dashboard's **Run command** action. Server-side only — the value is checked at dispatch time, never pushed to the client. See [AGENT-API-AUTH.md](AGENT-API-AUTH.md) for the auth model. Off by default; only effective on `peer.managed=1` peers. |

### Network & connectivity

| Key | Values | Effect |
|---|---|---|
| `custom-rendezvous-server` | host | ID/rendezvous server address |
| `relay-server` | host | Relay server address |
| `api-server` | URL | API server address |
| `key` | string | Server public key |
| `ice-servers` | string | ICE servers for WebRTC |
| `direct-server` | `Y`/`N` | Enable direct IP access listener |
| `direct-access-port` | port | Port for direct IP access |
| `enable-udp-punch` | `Y`/`N` | Enable UDP hole punching |
| `enable-ipv6-punch` | `Y`/`N` | Enable IPv6 hole punching |
| `disable-udp` | `Y`/`N` | Disable UDP (force TCP) |
| `allow-websocket` | `Y`/`N` | Allow WebSocket transport |
| `allow-insecure-tls-fallback` | `Y`/`N` | Allow falling back to insecure TLS |
| `enable-lan-discovery` | `Y`/`N` | Allow discovery on the local network |
| `whitelist` | IPs/CIDRs | Comma/space/`;`-separated allow-list; empty = allow all |
| `allow-https-21114` | `Y`/`N` | Use HTTPS on port 21114 |
| `use-raw-tcp-for-api` | `Y`/`N` | Use raw TCP for the API connection |
| `allow-hostname-as-id` | `Y`/`N` | Allow using the hostname as device ID |
| `proxy-url` | URL | Proxy server URL |
| `proxy-username` | string | Proxy username |
| `proxy-password` | string | Proxy password |

### Display, codec & quality

| Key | Values | Effect |
|---|---|---|
| `view_style` | `original` / `adaptive` | Remote display scaling |
| `scroll_style` | `scrollauto` / `scrollbar` | Scroll behaviour |
| `image_quality` | `best` / `balanced` / `low` / `custom` | Image quality preset |
| `custom_image_quality` | `10`–`4095` | Custom quality value |
| `custom-fps` | `5`–`120` | Custom frame rate |
| `codec-preference` | `auto` / `vp8` / `vp9` / `av1` / `h264` / `h265` | Preferred video codec |
| `enable-hwcodec` | `Y`/`N` | Enable hardware codec |
| `enable-abr` | `Y`/`N` | Enable adaptive bitrate |
| `i444` | `Y`/`N` | Use YUV 4:4:4 (true colour) |
| `av1-test` | `Y`/`N` | Enable AV1 test path |
| `zoom-cursor` | `Y`/`N` | Zoom the remote cursor |
| `show_remote_cursor` | `Y`/`N` | Show the remote cursor |
| `follow_remote_cursor` | `Y`/`N` | Follow the remote cursor |
| `follow_remote_window` | `Y`/`N` | Follow the remote active window |
| `show_quality_monitor` | `Y`/`N` | Show the quality monitor overlay |
| `show_monitors_toolbar` | `Y`/`N` | Show the monitors toolbar |
| `collapse_toolbar` | `Y`/`N` | Start with the toolbar collapsed |
| `view_only` | `Y`/`N` | Open sessions view-only by default |
| `touch-mode` | `Y`/`N` | Enable touch mode |
| `displays_as_individual_windows` | `Y`/`N` | Show each remote display in its own window |
| `use_all_my_displays_for_the_remote_session` | `Y`/`N` | Use all local displays for the session |
| `use-texture-render` | `Y`/`N` | Use texture rendering |
| `allow-d3d-render` | `Y`/`N` | Allow Direct3D rendering |
| `enable-directx-capture` | `Y`/`N` | Use DirectX for screen capture |
| `allow-always-software-render` | `Y`/`N` | Force software rendering |
| `allow-linux-headless` | `Y`/`N` | Allow headless mode on Linux |

### Input

| Key | Values | Effect |
|---|---|---|
| `reverse_mouse_wheel` | `Y`/`N` | Reverse mouse-wheel direction |
| `swap-left-right-mouse` | `Y`/`N` | Swap mouse buttons |
| `trackpad-speed` | `10`–`1000` | Trackpad speed (percent) |
| `edge-scroll-edge-thickness` | `20`–`150` | Edge-scroll trigger thickness |

### Recording, files & clipboard

| Key | Values | Effect |
|---|---|---|
| `allow-auto-record-incoming` | `Y`/`N` | Auto-record incoming sessions |
| `allow-auto-record-outgoing` | `Y`/`N` | Auto-record outgoing sessions |
| `video-save-directory` | path | Directory for recordings |
| `enable-file-copy-paste` | `Y`/`N` | Allow file copy/paste |
| `file-transfer-max-files` | number | Max files per transfer request |
| `one-way-file-transfer` | `Y`/`N` | Restrict file transfer to one direction |
| `sync-init-clipboard` | `Y`/`N` | Sync clipboard at session start |
| `disable_clipboard` | `Y`/`N` | Disable clipboard |
| `disable_audio` | `Y`/`N` | Disable audio |
| `one-way-clipboard-redirection` | `Y`/`N` | One-way clipboard redirection |
| `lock_after_session_end` | `Y`/`N` | Lock the host after a session ends |
| `privacy_mode` | `Y`/`N` | Enable privacy mode for the session |

### Printer

| Key | Values | Effect |
|---|---|---|
| `enable-remote-printer` | `Y`/`N` | Enable remote printing |
| `printer-incomming-job-action` | string | Action for incoming print jobs (note: key is spelled `incomming`) |
| `allow-printer-auto-print` | `Y`/`N` | Allow automatic printing |
| `printer-selected-name` | string | Selected printer name |

### Update behaviour

| Key | Values | Effect |
|---|---|---|
| `enable-check-update` | `Y`/`N` | Check for updates |
| `allow-auto-update` | `Y`/`N` | Allow automatic updates |

### Power & session

| Key | Values | Effect |
|---|---|---|
| `keep-screen-on` | string | Keep the screen on |
| `keep-awake-during-incoming-sessions` | `Y`/`N` | Keep host awake during incoming sessions |
| `keep-awake-during-outgoing-sessions` | `Y`/`N` | Keep client awake during outgoing sessions |
| `allow-ask-for-note` | `Y`/`N` | Prompt for a session note |
| `pre-elevate-service` | `Y`/`N` | Pre-elevate the service |
| `register-device` | `Y`/`N` | Register the device with the API server |

### UI visibility / branding lockdown

| Key | Values | Effect |
|---|---|---|
| `hide-security-settings` | `Y`/`N` | Hide the Security settings tab |
| `hide-network-settings` | `Y`/`N` | Hide the Network settings tab |
| `hide-server-settings` | `Y`/`N` | Hide the Server settings tab |
| `hide-proxy-settings` | `Y`/`N` | Hide the Proxy settings tab |
| `hide-remote-printer-settings` | `Y`/`N` | Hide remote-printer settings |
| `hide-websocket-settings` | `Y`/`N` | Hide WebSocket settings |
| `hide-stop-service` | `Y`/`N` | Hide the "stop service" control |
| `hide-tray` | `Y`/`N` | Hide the system-tray icon |
| `hide-powered-by-me` | `Y`/`N` | Hide "powered by" branding |
| `hide-username-on-card` | `Y`/`N` | Hide username on peer cards |
| `hide-help-cards` | `Y`/`N` | Hide help cards |
| `hideAbTagsPanel` | `Y`/`N` | Hide the address-book tags panel |
| `main-window-always-on-top` | `Y`/`N` | Keep the main window on top |
| `theme` | `light` / `dark` / `system` | UI theme |
| `lang` | language code | UI language |
| `remote-menubar-drag-left` | `Y`/`N` | Allow dragging the left remote menubar |
| `remote-menubar-drag-right` | `Y`/`N` | Allow dragging the right remote menubar |
| `enable-confirm-closing-tabs` | `Y`/`N` | Confirm before closing tabs |
| `enable-open-new-connections-in-tabs` | `Y`/`N` | Open new connections in tabs |
| `disable-group-panel` | `Y`/`N` | Hide the group panel |
| `disable-discovery-panel` | `Y`/`N` | Hide the discovery panel |

### Address book

| Key | Values | Effect |
|---|---|---|
| `sync-ab-with-recent-sessions` | `Y`/`N` | Sync address book with recent sessions |
| `sync-ab-tags` | `Y`/`N` | Sync address-book tags |
| `filter-ab-by-intersection` | `Y`/`N` | Filter address book by tag intersection |

### Deep links

| Key | Values | Effect |
|---|---|---|
| `allow-deep-link-password` | `Y`/`N` | Allow passwords in deep links |
| `allow-deep-link-server-settings` | `Y`/`N` | Allow server settings in deep links |

### Preset values (deploy/provisioning)

These pre-fill fields during enrollment/deploy rather than gating behaviour.

| Key | Effect |
|---|---|
| `display-name` | Device display name |
| `avatar` | Device avatar |
| `default-connect-password` | Default connection password |
| `remove-preset-password-warning` | Suppress the preset-password warning |
| `preset-user-name` | Pre-fill username |
| `preset-strategy-name` | Pre-fill strategy name |
| `preset-device-group-name` | Pre-fill device group |
| `preset-device-username` | Pre-fill device username |
| `preset-device-name` | Pre-fill device name |
| `preset-note` | Pre-fill session note |
| `preset-address-book-name` | Pre-fill address-book name |
| `preset-address-book-tag` | Pre-fill address-book tag |
| `preset-address-book-alias` | Pre-fill address-book alias |
| `preset-address-book-password` | Pre-fill address-book password |
| `preset-address-book-note` | Pre-fill address-book note |

### Android / mobile

| Key | Values | Effect |
|---|---|---|
| `show-virtual-mouse` | `Y`/`N` | Show the virtual mouse |
| `show-virtual-joystick` | `Y`/`N` | Show the virtual joystick (also set `show-virtual-mouse`) |
| `disable-floating-window` | `Y`/`N` | Disable the floating window |
| `floating-window-size` | string | Floating-window size |
| `floating-window-untouchable` | `Y`/`N` | Make the floating window non-interactive |
| `floating-window-transparency` | number | Floating-window transparency |
| `floating-window-svg` | string | Floating-window SVG icon |
| `enable-android-software-encoding-half-scale` | `Y`/`N` | Half-scale Android software encoding |

### UI state (normally per-user — listed for completeness)

`remoteMenubarState`, `peer-sorting`, `peer-tab-index`, `peer-tab-order`,
`peer-tab-visible`, `peer-card-ui-type`, `current-ab-name`,
`enable-flutter-http-on-rust`, `allow-remote-cm-modification`.

---

## Notes & caveats

- The list above reflects the client `keys` module at documentation
  time. Newer clients may add keys; older clients will ignore keys they
  don't know. There is no negotiation — match the doc to the client
  version you actually deploy.
- Some keys also exist as hbbs/hbbr command-line flags
  (`custom-rendezvous-server`, `relay-server`, `key`, …). Pushing them
  via a strategy overrides the client's local value; it does not change
  the server.
- The `extra` object on a strategy row is reserved and currently always
  `{}` — there is no UI to populate it.
- For the overall configuration picture see
  [CONFIGURATION.md](CONFIGURATION.md#strategies-server-pushed-config).
