Skip to content

Triggers & Matching

A trigger is the condition that makes a Network match. When ZestSSH wants to know which environment you are in, it reads the device’s current state — IP addresses, connection type, and (if you ask) the Wi-Fi name — then walks your Networks list from top to bottom and stops at the first network whose trigger matches. That network’s overrides are what get applied when you connect.

This page covers the trigger types, how they are matched, how priority breaks ties, and the two escape hatches: forcing a network manually, and previewing a host “as” a network before you rely on it.

If you haven’t read it yet, Networks Overview explains the detect -> match -> resolve flow this page fits into.


You can attach one or more triggers to any custom network. Multiple triggers on the same network are OR’d together — the network matches if any one of them is true. That lets a single “Home” network match both your Wi-Fi name and your wired subnet, for instance.

TriggerMatches when…You provideGood for
Subnetany of the device’s IP addresses falls inside the given CIDR rangea CIDR like 192.168.1.0/24LANs, VPN address pools, wired networks
Wi-Fi network namethe connected Wi-Fi SSID exactly equals your textthe SSID, e.g. home-neta specific Wi-Fi you can name
On cellularthe device is on cellular / mobile datanothing”when I’m on the road”
Connection typethe active connection is a specific type: Wi-Fi, Ethernet, cellular, VPN, or nonepick from a dropdownbroad rules like “any Ethernet”

In the network editor these appear as four add buttons — Subnet, WiFi network name, On cellular, Connection type — so you can see every option without opening a menu first.

A subnet trigger matches when any IP address currently bound to your device sits inside the CIDR range you give it. ZestSSH ships its own small CIDR matcher (cidr.dart) that understands IPv4, IPv6, and IPv4-mapped IPv6 addresses.

How the match actually works: the CIDR’s prefix length tells ZestSSH how many leading bits matter. It masks both the network address and each of your device’s addresses down to that many bits and checks for an exact match. A /24 compares the first 24 bits (the first three octets of an IPv4 address); a /16 compares the first 16; a /32 demands an exact single-address match.

CIDRMatches addresses likeMeaning
192.168.1.0/24192.168.1.1192.168.1.254a typical home/office LAN
10.0.0.0/8anything 10.x.x.xa large private range (common on VPNs)
10.20.0.0/1610.20.0.110.20.255.254one site inside a 10.x network
100.64.0.0/10100.64.x.x100.127.x.xTailscale / CGNAT range
fd00::/8fd00:... addressesIPv6 unique-local range

The editor validates your CIDR as you type. If it can’t be parsed — a missing /prefix, an octet over 255, a prefix over 32 (v4) or 128 (v6) — the field shows an inline error and the network won’t save until it’s fixed.

Subnet is the trigger to prefer whenever you can. It is precise and, unlike a Wi-Fi name, it cannot be impersonated by a stranger’s access point.

An SSID trigger matches when the name of the Wi-Fi network you are connected to exactly equals the text you entered. Handy when a place doesn’t give you a predictable subnet but does have a recognizable network name.

Two things to know before you rely on it:

  • It is permission-gated. Reading the Wi-Fi name is a privacy-sensitive operation. On Android it requires the location permission (ACCESS_FINE_LOCATION); on iOS it requires a specific entitlement plus location access. If the permission isn’t granted, the SSID simply comes back empty and the trigger silently fails to match — it never crashes, it just won’t fire. Because reading the SSID has a cost, ZestSSH only asks for it when a network in your list actually uses an SSID trigger.
  • It can be spoofed. Anyone can stand up an access point named home-net. A rogue AP with your SSID would make this trigger match somewhere it shouldn’t. The editor shows this warning inline the moment you add a Wi-Fi trigger. Subnet matching does not have this weakness.

Rule of thumb: use a subnet trigger for anything security-sensitive, and reserve SSID triggers for convenience matching where a wrong match would be harmless.

Matches whenever the device is on cellular / mobile data (no Wi-Fi, no Ethernet). No configuration — it either applies or it doesn’t. This is the natural trigger for an “On the road” network that routes everything through a VPN or a jump host.

A slightly more general version of the cellular trigger. Instead of “cellular specifically,” you pick the connectivity class from a dropdown: Wi-Fi, Ethernet, cellular, VPN, or none. Combined with other triggers (remember, they’re OR’d), it lets you write broad rules like “any Ethernet connection uses the office profile.”


A laptop in a dock can be on Wi-Fi and Ethernet at the same time; a phone can have cellular up while a VPN tunnel is active. ZestSSH resolves that into a single connection type using a fixed priority that matches what people usually mean:

Ethernet > Wi-Fi > VPN > cellular > none

So a docked laptop on both Ethernet and Wi-Fi reports as Ethernet. (Bluetooth tethering is treated as cellular for matching purposes.) This only affects the Connection type and On cellular triggers — subnet and SSID triggers look at your actual addresses and Wi-Fi name regardless of the classification.

Detection re-runs automatically whenever connectivity changes — you plug in an Ethernet cable, join a Wi-Fi, drop to cellular — with a short debounce (about a second) so a flapping interface doesn’t cause churn.


Priority: what happens when several networks match

Section titled “Priority: what happens when several networks match”

Your Networks list is an ordered priority list, evaluated top to bottom. The first network with a matching trigger wins, and evaluation stops there — lower networks are never consulted, even if they’d also match.

This matters when networks overlap. Suppose you have:

  1. Office — subnet 10.20.5.0/24
  2. Corp VPN — subnet 10.0.0.0/8

At your desk you’re inside both ranges (10.20.5.x is also inside 10.0.0.0/8). Because Office sits higher, it wins, and Corp VPN only applies when you’re on some other 10.x address off-site. Put the more specific network above the broader one.

To reorder, drag the networks in the list. The Default network is pinned to the bottom and can’t be moved — it’s the catch-all that matches when nothing else does (its trigger is a built-in “always match”). Default can’t be deleted either.

SituationWhich network is used
Exactly one network’s trigger matchesthat one
Several matchthe highest one in the list
None matchDefault (the built-in catch-all)
You’ve forced one manuallythe forced one, ignoring detection (see below)

Detection is right almost all the time, but sometimes you want to override it — to test an away profile while sitting at home, or because you’re on an unusual network you haven’t taught ZestSSH about yet.

On mobile, the current-network banner at the top of the home screen shows the active profile with an Auto / Forced chip on the right. Tap it to open a picker:

  • Auto — clears any override and hands control back to detection. Choosing Auto is always safe; it’s the way out.
  • Any named network — forces that profile. The banner shows a pin icon and reads Forced to remind you detection is off.

A forced choice persists across app restarts, so you won’t get stranded on a temporary override you forgot about — but it’s always one tap back to Auto. If you force a network and later delete it, ZestSSH quietly falls back to automatic detection rather than leaving you pointing at a network that no longer exists.

When a network is forced, it beats detection everywhere the resolver runs — so every host you connect to uses that profile’s overrides until you switch back to Auto.


Previewing with “Test as this network”

Section titled “Previewing with “Test as this network””

Forcing a network changes it app-wide. When you only want to check one host against one network — “if Home were active, where would this box resolve to, and can I actually reach it?” — use Test as this network instead.

It lives on each network’s row inside a host’s Networks section (in the connection editor). It reads that row’s fully resolved effective config — the address, port, username, key, and jump route the network would produce — and runs a probe against it, without touching the global manual override or changing app state. You get two choices:

  • Test reachability — can the endpoint be reached at all (a TCP-level check)?
  • Test full connection — reachability plus authentication with the resolved credentials.

This is the safe way to confirm a new override before you depend on it in the field. See Per-Host Overrides for what each row can resolve to.


Broad network sitting above a specific one. If “Corp VPN” (10.0.0.0/8) is listed above “Office” (10.20.5.0/24), the VPN profile swallows the office match because it’s checked first and any 10.20.5.x address is also inside 10.0.0.0/8. Put the narrower CIDR higher.

Trusting an SSID trigger for something sensitive. A Wi-Fi name can be spoofed by a rogue access point, and it silently won’t match at all if location permission is missing. For anything that matters, trigger on the subnet instead.

Wrong prefix length. 192.168.1.10/24 and 192.168.1.10/32 are very different rules: the first matches the whole 192.168.1.x LAN, the second matches only that one address. If a network never seems to match, check the prefix.

Forgetting you left a network forced. A pinned/Forced profile stays put across restarts. If a host keeps resolving oddly, glance at the banner — if it says Forced, tap it and choose Auto.

Expecting SSID matching on desktop. Wi-Fi name reading is a mobile-oriented, permission-gated feature. On a wired desktop, prefer subnet triggers, which work everywhere.