Tiny terminal CLI for managing devices on an eero mesh network from a real shell.
Wraps eero-api (the most actively maintained reverse-engineered Python client as of May 2026) and adds:
- A two-step, non-interactive SMS auth flow that survives across separate shell invocations
- Filtered device listing (regex + MAC prefix + online/offline)
- Single and bulk device blocking
- An honest writeup, in this README, of what eero's API will and won't let you do — saving you the half-day I spent figuring it out
pipx install git+https://github.com/solomonneas/eero-cli
# or, from a clone:
pipx install .Requires Python 3.12+ (inherited from eero-api).
The eero API uses a two-step SMS/email login. Both halves are non-interactive so they work in any wrapper that can't drive input() (Claude Code's ! shell, scripted setup, etc.):
# Step 1: trigger the SMS / email
eero auth +15551234567 # phone
# or
eero auth you@example.com # email
# Step 2 (after the code arrives, within 30 minutes):
eero auth --code 123456Session token is written to ~/.config/eero/session.json (mode 0600). Re-run eero auth any time to start over.
The underlying eero-api library auto-clears any persisted session whose session_expiry is None when it loads — but login() legitimately leaves expiry None until verify() runs. Single-process auth works fine; cross-process auth would lose the partial state on read. eero-cli works around this by stamping a 30-minute placeholder expiry between the two calls.
eero devices # list everything
eero devices --filter '^iphone' # regex over nickname/hostname
eero devices --mac 'BC:24:11' # MAC prefix
eero devices --offline # only stale entries
eero devices --online # only currently connected
eero block <mac-or-id> # block a device (works on online devices)
eero block <mac-or-id> --unblock # reverse it
eero block-cleanup '^bc24' # bulk-block matching offline devices
eero block-cleanup '^bc24' -y # skip confirmation promptblock-cleanup defaults to offline-only and skips already-blocked devices. Pass --include-online to widen the net.
The eero REST and GraphQL APIs do not expose any mutating operation on offline devices. We verified this end-to-end:
DELETEon/2.2/networks/<nid>/devices/<did>returns404(also tested/2.0/,/2.1/,/2.3/,/3.0/API version prefixes; PATCH and OPTIONS too)PUTwith{"forget": true}/{"is_forgotten": true}/{"remove": true}returns200but silently no-opsPOSTto/devices/<id>/forget,/forget,/remove,/bulk_forgetall return404block_deviceagainst an offline device returns200but does not flip theblacklisted,paused,dropped, or any other state field- The eero web admin SPA (
insight.eero.com) ships 215 GraphQL mutations; none match*Forget*,*Delete*Device*, or*Remove*Device*(onlyBlockDevicesNetwork,EditDeviceNickname,EditDevicePaused,ToggleEeroBuiltinOnDevice,UnblockDevicesNetwork,UpdateDeviceSecondaryWan)
The mobile app's "Forget Device" button must use either a private/internal channel or be local-only display state. No public reverse-engineered library — 343max/eero-client, fulviofreitas/eero-api, schmittx/home-assistant-eero, or erikh/eero — exposes device removal either.
If you need to actually delete an offline device:
- Open the eero mobile app, tap the device, three dots → "Forget Device". Eero auto-culls truly stale entries after ~30 days, so doing nothing also works.
- Or capture the real call via mitmproxy on your phone (left as an exercise; PR welcome if you find it).
eero-api by Fulvio Freitas — modern async client, version 4.1.3 at time of writing. Picked over the older 343max/eero-client (last code push Feb 2024) because it's actively maintained, ships proper file-based credential storage, and has a clean async surface.
MIT. See LICENSE.