Skip to main content

unifi-cli

codecov

CLI for UniFi Network controller with an interactive TUI dashboard. Designed for both human operators and AI agents.

Quick start

# Install (pick one)
cargo install unifi-cli        # From source
uvx unifi-cli --help           # Run without installing (via uv)
pip install unifi-cli           # Via pip

# Configure
unifi config init               # Interactive setup (prompts for host + API key)

# Use
unifi clients list              # List connected clients
unifi devices list              # List network devices
unifi tui                       # Interactive dashboard

Generate an API key in your controller under UniFi Network → Integrations. Ubiquiti documents the current flow in Getting Started with the Official UniFi API.

Installation

From crates.io

cargo install unifi-cli

From PyPI

pip install unifi-cli
# or run without installing:
uvx unifi-cli clients list

From GitHub releases

Pre-built binaries for Linux (x64, arm64), macOS (x64, arm64), and Windows (x64) on the releases page.

Configuration

Run unifi config init for interactive setup, or configure manually:

Environment variables

export UNIFI_HOST=https://unifi.example.com
export UNIFI_API_KEY=YOUR_KEY
# Optional for lab controllers with self-signed or otherwise invalid TLS certs:
export UNIFI_ACCEPT_INVALID_CERTS=true

Config file

Linux: ~/.config/unifi/config.toml. macOS: ~/Library/Application Support/unifi/config.toml. Windows: %APPDATA%\unifi\config.toml.

unifi config init writes a new file and renames it over any existing config instead of writing in place, so a failed write leaves the previous config intact. On Linux and macOS the new file is created with mode 0600, since it holds an API key and optionally a Protect password. Because the credentials go straight into a file that is already 0600, they are never readable by another local account, not even for the moment between the write and a chmod. On Windows the file inherits its directory's ACL.

host = "https://unifi.example.com"
api_key = "YOUR_KEY"
# Optional; defaults to false.
accept_invalid_certs = false

Multi-controller profiles

[profiles.home]
host = "https://home.example.com"
api_key = "KEY_1"

[profiles.office]
host = "https://office.example.com"
api_key = "KEY_2"
unifi --profile office clients list
# or: UNIFI_PROFILE=office unifi clients list

CLI flags

unifi --host https://unifi.example.com --api-key YOUR_KEY clients list

Priority: CLI flags > environment variables > config file.

TLS certificates are verified by default. For a local controller with a self-signed certificate, pass --accept-invalid-certs, set UNIFI_ACCEPT_INVALID_CERTS=true, or set accept_invalid_certs = true in the config file. Only use this on trusted networks because it weakens protection for API keys, passwords, session cookies, and stream URLs.

When unifi config init cannot verify the controller's certificate, it offers to trust the controller and saves accept_invalid_certs = true for you.

Destructive commands

clients block, clients unblock, clients kick, devices restart, devices upgrade, ports cycle and protect rtsps delete all ask before they act. On a terminal you get a yes/no question naming the target; declining exits 2 with kind: confirmation_required and sends nothing. When stdin is not a terminal there is nobody to ask, so they refuse with the same error unless you pass --yes, which skips the question everywhere.

unifi schema marks exactly these commands confirmation_required: true, so a caller can tell them apart from mutating commands that act immediately (devices locate, clients set-fixed-ip, protect rtsps create) without hardcoding the list.

TUI dashboard

unifi tui                       # Launch interactive dashboard

If the controller is not configured or rejects the saved API key, the dashboard offers guided configuration in place. Press Enter or a, complete the secure prompt outside the alternate screen, and the dashboard resumes automatically.

Real-time dashboard with:

  • Client list with bandwidth, connection info, and signal strength
  • Device overview with status and firmware versions
  • Event feed from the controller
  • Client actions: kick, block/unblock, lock/unlock AP
  • Device actions: restart, upgrade firmware, locate LED
  • Filter clients by name with /

Live port monitor

unifi devices ports aa:bb:cc:dd:ee:ff --live   # Real-time port stats

Commands

Clients

unifi clients list                          # List connected clients
unifi clients list --wired                  # Wired clients only
unifi clients list --wireless --name tasmota  # Filter by type and name
unifi clients list --watch                  # Auto-refresh
unifi clients list --fields name,ssid,ip    # Project specific fields (see `unifi schema`)
unifi clients show aa:bb:cc:dd:ee:ff        # Show client details
unifi clients top                           # Top clients by bandwidth
unifi clients block aa:bb:cc:dd:ee:ff       # Block a client
unifi clients unblock aa:bb:cc:dd:ee:ff     # Unblock a client
unifi clients kick aa:bb:cc:dd:ee:ff        # Disconnect a client
unifi clients set-fixed-ip MAC IP [--name]  # Set DHCP reservation

Devices

unifi devices list                            # List network devices
unifi devices list --watch                    # Auto-refresh
unifi devices show aa:bb:cc:dd:ee:ff          # Show device details
unifi devices ports aa:bb:cc:dd:ee:ff         # Show switch/router ports
unifi devices restart aa:bb:cc:dd:ee:ff       # Restart a device
unifi devices upgrade aa:bb:cc:dd:ee:ff       # Upgrade firmware
unifi devices locate aa:bb:cc:dd:ee:ff        # Blink locate LED
unifi devices locate aa:bb:cc:dd:ee:ff --off  # Stop blinking

Ports

Find which switch port a device is plugged into, then power-cycle just that port instead of rebooting the whole switch:

# Which port is my Pi on? Matches by name (case-insensitive substring),
# MAC, or IP.
unifi ports find garage-pi
unifi ports find aa:bb:cc:dd:ee:10

# Inspect it: PoE mode, class, voltage, current, and what's attached
unifi ports show aa:bb:cc:dd:ee:ff 5

# Bounce PoE on that port only, leaving the rest of the switch untouched
unifi ports cycle aa:bb:cc:dd:ee:ff 5

ports find's output feeds directly into show and cycle: device_mac and port_idx are the switch's MAC and port index, not the attached device's. A name is ambiguous only when it matches more than one device that's actually on a switch port; that returns kind: conflict (exit 6) listing the candidates rather than guessing. Other client records sharing the name (a device's WiFi interface reporting under the same name as its wired one, say) don't cause a conflict if they're not themselves on a port. A device that has moved between switch ports appears once per port it has ever used, with a connected field distinguishing its current port from stale history.

ports show exposes the port's PoE telemetry: poe_mode, poe_class, poe_voltage, poe_current, poe_good, and the MAC of the attached device (attached_mac). The controller keeps a port's last connection record after the device is unplugged, so attached_mac is set only when the controller affirms the record is live. The MAC is still reported as attached_last_seen_mac and the controller's own flag as attached_connected (true, false, or null when the firmware does not report it), so a caller can tell "gone" from "not reported". The text output renders the three cases as aa:bb:cc:dd:ee:ff, - (last seen aa:bb:cc:dd:ee:ff) and unknown (last seen aa:bb:cc:dd:ee:ff). Nothing that has been unplugged is ever presented as currently attached.

ports cycle is destructive. On a terminal it shows what is about to lose power and asks for confirmation; when piped it requires --yes and otherwise exits 2 with kind: confirmation_required. It reads the port table first, then refuses without ever sending the power-cycle command when:

  • the port is not PoE-capable (an SFP+ port, say) → kind: conflict, exit 6
  • the port's PoE is administratively off → kind: conflict, exit 6
  • the port isn't currently delivering PoE (poe_enable: false) → kind: conflict, exit 6
  • the device has no such port index → kind: not_found, exit 4

The off interval (how long the port stays unpowered) is chosen by the switch firmware, not by this CLI. The power-cycle command takes only the target port, with no duration parameter, on either the legacy endpoint or the Integration API, so the interval isn't configurable and varies by device model and firmware version. IEEE 802.3 PoE detection timing imposes a floor regardless: expect the port to sit dark for roughly 1-2 seconds at minimum before power returns.

List ports for one device, or across every device:

unifi ports list aa:bb:cc:dd:ee:ff
unifi ports list --limit 20 --fields port_idx,poe_power

ports list returns the paginated {items, total, limit, offset} envelope used by the other list commands. unifi devices ports <MAC> remains an alias for unifi ports list <MAC>; it keeps its original bare-JSON-array shape for backward compatibility, and both emit the same per-row fields, including device_mac and device_name.

Port forwards

unifi port-forwards list
unifi port-forwards show plex

Events

unifi events list                           # Recent controller events
unifi events list --limit 50                # Last 50 events

Networks

unifi networks list                         # List all networks
unifi networks                              # Same thing
unifi networks show IoT                     # DHCP, DNS, mDNS, and cellular-backup details

System

unifi system health                         # Show subsystem health
unifi system info                           # Show controller info

WAN

unifi wan list                              # Show uplinks and failover state

Configuration

unifi config init                           # Interactive setup
unifi config check                          # Verify connectivity and API key

Shell completions

unifi completions zsh --install             # Install zsh completions
unifi completions bash --install            # Install bash completions
unifi completions fish --install            # Install fish completions

Agent-friendly design

unifi-cli is designed to work well with AI agents and automation scripts.

Automatic JSON output

When stdout is not a terminal (piped or redirected), output switches to JSON automatically:

# Human at terminal: formatted table
unifi clients list

# Agent piping output: JSON automatically
data=$(unifi clients list)

# Force JSON mode
unifi --json clients list

Clean stdout/stderr separation

Data goes to stdout. Messages go to stderr. Piping always captures clean data:

unifi clients list > clients.json     # stdout: JSON, stderr: "66 clients"
unifi --quiet clients list            # Suppress stderr messages

Structured mutation responses

unifi --json clients block aa:bb:cc:dd:ee:ff
# {"action": "block", "mac": "AA:BB:CC:DD:EE:FF", "status": "ok"}

Runtime schema introspection

unifi schema    # Dumps all commands, arguments, output fields as JSON

Distinct exit codes

Code kind Meaning
0 - Success
1 general_error General error (including transport failures)
2 config_error Configuration or usage error
2 confirmation_required A destructive command ran without --yes and without a TTY
3 auth_error Authentication error (401/403)
4 not_found Not found (404)
4 unsupported The controller does not serve this endpoint at all: it answered a JSON endpoint with HTML (how UniFi OS reports an application it does not have) or rejected the endpoint itself (how UniFi Network reports one the firmware has dropped); unlike not_found there is no other identifier or parameter worth trying
5 client_error The controller rejected the request itself (4xx other than 401/403/404/408/429); retrying it unchanged cannot help
5 retry_later The controller invited a retry (429 rate limited, 408 request timeout); back off and send the same request again
5 api_error The controller failed to serve the request (5xx); may be transient
6 conflict The request cannot succeed against the resource's current state, refused locally before any API call

unifi schema publishes the same table under errors, with a retryable flag per kind, so an agent can branch on it without parsing prose.

Development

make check      # Lint and test
make test       # Run tests
make install    # Build and install

License

MIT

Releasing

Vership owns versioning, changelog generation, release commits, and tags. See the release runbook for the verified workflow and recovery policy.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

unifi_cli-0.4.2.tar.gz (199.1 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

unifi_cli-0.4.2-py3-none-win_amd64.whl (3.5 MB view details)

Uploaded Python 3Windows x86-64

unifi_cli-0.4.2-py3-none-manylinux_2_28_x86_64.whl (3.6 MB view details)

Uploaded Python 3manylinux: glibc 2.28+ x86-64

unifi_cli-0.4.2-py3-none-manylinux_2_28_aarch64.whl (3.4 MB view details)

Uploaded Python 3manylinux: glibc 2.28+ ARM64

unifi_cli-0.4.2-py3-none-macosx_11_0_arm64.whl (3.4 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

unifi_cli-0.4.2-py3-none-macosx_10_12_x86_64.whl (3.5 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file unifi_cli-0.4.2.tar.gz.

File metadata

  • Download URL: unifi_cli-0.4.2.tar.gz
  • Upload date:
  • Size: 199.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for unifi_cli-0.4.2.tar.gz
Algorithm Hash digest
SHA256 5089194c8e59463592f0d205cc18647a3b2b4a4724841a8ce7e8c2f71e68e965
MD5 d26c204df496ceb578d5794cad3bfc71
BLAKE2b-256 70bbb9414df5f9e8840e4624e7fdea9b9c821b925c240ed899c49f6feb0792f1

See more details on using hashes here.

File details

Details for the file unifi_cli-0.4.2-py3-none-win_amd64.whl.

File metadata

  • Download URL: unifi_cli-0.4.2-py3-none-win_amd64.whl
  • Upload date:
  • Size: 3.5 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for unifi_cli-0.4.2-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 061e397d3863e8419e64951a13723e4fbddfbaea85ab276267a7415f5bc6f509
MD5 5574b23ed8addd401cc587762163aca2
BLAKE2b-256 b2b1dc9fb6c77972ac7e59eb4ccb0e9d26c6b7935f0b641ea7858c567df53d25

See more details on using hashes here.

File details

Details for the file unifi_cli-0.4.2-py3-none-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for unifi_cli-0.4.2-py3-none-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 bbb167cf8624622698b0b05c8c57399639d2ee0523333201f91dcd0912b93860
MD5 bbc8cf7527bdbed53311e0e8e8f7f0f9
BLAKE2b-256 766407e847c9018efea5ab299186cd940ad52851453c9c4bda17f2613b5f18af

See more details on using hashes here.

File details

Details for the file unifi_cli-0.4.2-py3-none-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for unifi_cli-0.4.2-py3-none-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 13d5c141be00bc82fe5548cb7d6ce892e76bf214591958e94c90c1065d517475
MD5 c64918876fc3395ec48b5ff67465c54f
BLAKE2b-256 cecd6fecce7468baafabffb74160161136d8454e9954d07b552a14b3b4378eaf

See more details on using hashes here.

File details

Details for the file unifi_cli-0.4.2-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for unifi_cli-0.4.2-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 88fa84a4b4d1e0240b1c25e3745d27c19f5a239c68183f9731268a9b022222c3
MD5 0a06667b5bb26986ac6dca43f339e1b6
BLAKE2b-256 f272e95d55de699b4dac802ea30044b86085ce16e2df42c0b50ca1855f619a76

See more details on using hashes here.

File details

Details for the file unifi_cli-0.4.2-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for unifi_cli-0.4.2-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 1b27163fef96dace2d8f65b6c837ba062425d0947666aaa7c5cea14eab1858e1
MD5 289d8e0e639a971c43734564731a77e1
BLAKE2b-256 a2afb4d534f87e82fd59c4baa4130ff9b708d2a45a0b0ce11522700ae8b3819f

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.4.2 This release

6 files

0.4.1

6 files

0.4.0

6 files

0.3.5

6 files

0.3.4

6 files

0.3.3

6 files

0.3.2

6 files

0.3.1

6 files

0.3.0

6 files

0.2.3

6 files

0.2.2

6 files

0.2.1

6 files

0.2.0

6 files

0.1.7

6 files

0.1.6

6 files

0.1.5

6 files

0.1.4

6 files

0.1.3

6 files

0.1.2

6 files

0.1.1

6 files

0.0.4

6 files

0.0.1

1 file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page