Skip to content

Netwatch

Netwatch monitors the state of hosts on the network. For each monitored host you specify a probe type, check interval, and scripts to run when the host state changes. The primary use is executing arbitrary console commands on state transitions — making it suitable for failover automation, alerting, and conditional network management.

Netwatch was expanded significantly in RouterOS 7.4. Prior versions only supported the simple (ICMP-only) probe. Entries created before upgrading retain the simple type for backward compatibility.

Netwatch periodically probes specified hosts and tracks their availability. When a host transitions between up and down, Netwatch executes the configured script. Use cases include:

  • WAN failover: switch default routes when an upstream gateway fails
  • Service monitoring: detect when a critical TCP port or HTTP endpoint becomes unavailable
  • Alerting: send email or log entries on state changes

/tool/netwatch

Monitor a host using ICMP (ping-style probes):

/tool/netwatch add host=8.8.8.8 type=icmp interval=30s

Monitor a TCP port:

/tool/netwatch add host=192.168.1.100 type=tcp-conn port=22 interval=1m

Monitor an HTTP endpoint:

/tool/netwatch add host=10.0.0.1 type=http-get port=80 interval=1m
/tool/netwatch print

Example output:

Flags: X - disabled
# NAME HOST TYPE SINCE STATUS
0 wan-gateway 203.0.113.1 icmp mar/22/2026 up
1 web-service 10.0.0.1 http-get mar/22/2026 down
PropertyDefaultDescription
hostIP address (IPv4, IPv6, or IPv6 link-local). Supports VRF: ip@vrf
typesimpleProbe type: icmp, tcp-conn, http-get, https-get, or simple
interval10sTime between probes
timeout3sMaximum time to wait for a probe response
up-scriptScript body or name to execute when status changes to up
down-scriptScript body or name to execute when status changes to down
unknown-scriptScript executed when status transitions to unknown (e.g. on first run before any probe completes, or when disabled and re-enabled)
test-scriptScript executed after every probe, regardless of status change
nameOptional name for the Netwatch entry
commentHuman-readable description
disablednoDisable this entry without removing it
start-delay0sDelay before the first probe after Netwatch starts or the router boots. Use to avoid false alarms during boot when upstream connectivity is not yet ready

Sends a series of ICMP Echo Requests (ping) per interval and evaluates RTT and packet loss against configurable thresholds. This is the most detailed probe type and provides rich statistics for use in scripts.

/tool/netwatch add host=8.8.8.8 type=icmp interval=30s
PropertyDefaultDescription
packet-count10ICMP packets sent per probe cycle
packet-interval50msDelay between packets within a probe cycle
packet-size54Total IP packet size (bytes)
thr-max1sRTT-max threshold — probe fails if any packet exceeds this
thr-avg100msRTT-avg threshold — probe fails if average RTT exceeds this
thr-stdev250msRTT standard deviation threshold
thr-jitter1sJitter threshold
thr-loss-count0Packet loss threshold (count)
thr-loss-percent0Packet loss threshold (percent)
VariableDescription
sent-countICMP packets sent in last probe cycle
response-countValid ICMP responses received
thr-loss-countLost packet count
thr-loss-percentLost packet percentage
thr-avgMean round-trip time
thr-maxMaximum round-trip time
thr-stdevRound-trip time standard deviation
thr-jitterJitter value

A simplified ICMP probe retained for backward compatibility with RouterOS 6 Netwatch entries. It supports fewer options and statistics than the icmp type. Prefer type=icmp for new configurations.

Attempts a full TCP three-way handshake to verify that a service is accepting connections.

/tool/netwatch add host=10.0.0.1 type=tcp-conn port=443 interval=1m
PropertyDefaultDescription
port80TCP destination port

Pass/fail: the probe passes when the TCP connection is established. Connection refused, timeout, or RST causes a fail.

Issues an HTTP GET request and validates the response code against a configurable range. Available in RouterOS 7.4+.

/tool/netwatch add host=10.0.0.1 type=http-get port=80 interval=1m
PropertyDefaultDescription
port80TCP port for the HTTP connection
http-code-min100Minimum acceptable HTTP response code
http-code-max299Maximum acceptable HTTP response code
thr-http-time10sResponse time threshold — probe fails if exceeded

A response code in the range [http-code-min, http-code-max] is a pass. Any code outside that range, a connection failure, or exceeding thr-http-time is a fail.

VariableDescription
http-status-codeHTTP response code received (e.g. 200, 404)

Identical to the HTTP probe but establishes a TLS connection first. Use for monitoring HTTPS endpoints.

/tool/netwatch add host=1.1.1.1 type=https-get port=443 interval=1m

The same http-code-min, http-code-max, thr-http-time, and http-status-code options and variables apply.

Netwatch executes scripts on status transitions. Scripts can be defined as inline code or as a reference to a named entry in /system/script.

Inline scripts are set directly on the netwatch entry:

/tool/netwatch add host=8.8.8.8 type=icmp interval=30s \
up-script=":log info \"WAN gateway is UP\"" \
down-script=":log warning \"WAN gateway is DOWN\""

For longer scripts, define them in /system/script and reference them by name:

/system/script add name=wan-down source={
:log warning "WAN gateway DOWN - switching to backup"
/ip/route set [find where comment="primary-wan"] disabled=yes
/ip/route set [find where comment="backup-wan"] disabled=no
}
/system/script add name=wan-up source={
:log info "WAN gateway UP - restoring primary route"
/ip/route set [find where comment="primary-wan"] disabled=no
/ip/route set [find where comment="backup-wan"] disabled=yes
}
/tool/netwatch add host=203.0.113.1 type=icmp interval=20s \
down-script=wan-down \
up-script=wan-up

Scripts have access to probe statistics. Variables with hyphens in their names must be quoted in RouterOS scripting syntax.

VariableDescription
$hostMonitored host address
$typeProbe type
$statusCurrent status: up or down
$sinceTimestamp of last status change
$“done-tests”Total probes completed
$“failed-tests”Consecutive failed probes
VariableDescription
$“sent-count”Packets sent in last cycle
$“response-count”Packets received
$“thr-loss-count”Lost packet count
$“thr-loss-percent”Packet loss percentage
$“thr-avg”Average RTT
$“thr-max”Maximum RTT
VariableDescription
$“http-status-code”HTTP response status code

The test-script runs after every probe, whether or not the status changed. Use it to log metrics or update external state continuously:

/tool/netwatch set [find where host=8.8.8.8] \
test-script=":log debug (\"RTT avg=\" . \$\"thr-avg\")"

Netwatch automatically writes to the system log on state changes:

  • info level: Probe identification and state transition (OK→fail or fail→OK)
  • debug level: Full probe statistics and configuration

To view Netwatch log entries:

/log print where topics~"info" message~"netwatch"

You can also filter for a specific host:

/log print where message~"8.8.8.8"

Example output:

08:03:26 script,info Ping to 8.8.8.8 successful
08:10:47 netwatch,info 8.8.8.8: OK -> FAIL

To send email notifications on state changes, configure /tool/e-mail first, then call it from a script:

/system/script add name=alert-wan-down source={
:local subject "ALERT: WAN gateway unreachable"
:local body ("Host " . $host . " has been down since " . $since)
/tool/e-mail send to="[email protected]" subject=$subject body=$body
:log warning $subject
}
/tool/netwatch set [find where comment="primary-wan"] down-script=alert-wan-down

Netwatch scripts can integrate with a variety of notification systems. All examples below assume the Netwatch entry already has down-script and up-script set to the named scripts.

Configure the email tool first, then reference it from a Netwatch script:

/tool/e-mail set server=smtp.example.com port=587 \
from[email protected] user=smtp_user password=smtp_pass \
tls=starttls
/system/script add name=notify-down source={
:local subject ("ALERT: " . $host . " is DOWN")
:local body ("Host: " . $host . "\nStatus: DOWN\nSince: " . $since \
. "\nFailed probes: " . $"failed-tests")
/tool/e-mail send to="[email protected]" subject=$subject body=$body
}
/system/script add name=notify-up source={
:local subject ("RESOLVED: " . $host . " is UP")
:local body ("Host: " . $host . "\nStatus: UP\nSince: " . $since)
/tool/e-mail send to="[email protected]" subject=$subject body=$body
}
/tool/netwatch set [find where host=203.0.113.1] \
down-script=notify-down up-script=notify-up

Send alerts to a Telegram chat using /tool/fetch with the Telegram Bot API. Replace YOUR_BOT_TOKEN and YOUR_CHAT_ID with your actual values.

/system/script add name=telegram-down source={
:local botToken "YOUR_BOT_TOKEN"
:local chatId "YOUR_CHAT_ID"
:local msg ("\xF0\x9F\x94\xB4 HOST DOWN\nHost: " . $host \
. "\nSince: " . $since \
. "\nFailed probes: " . $"failed-tests")
/tool/fetch url=("https://api.telegram.org/bot" . $botToken \
. "/sendMessage") \
http-method=post \
http-header-field="Content-Type: application/json" \
http-data=("{\"chat_id\":\"" . $chatId . "\",\"text\":\"" . $msg . "\"}") \
output=none
}
/system/script add name=telegram-up source={
:local botToken "YOUR_BOT_TOKEN"
:local chatId "YOUR_CHAT_ID"
:local msg ("\xE2\x9C\x85 HOST UP\nHost: " . $host \
. "\nRecovered: " . $since)
/tool/fetch url=("https://api.telegram.org/bot" . $botToken \
. "/sendMessage") \
http-method=post \
http-header-field="Content-Type: application/json" \
http-data=("{\"chat_id\":\"" . $chatId . "\",\"text\":\"" . $msg . "\"}") \
output=none
}
/tool/netwatch set [find where host=203.0.113.1] \
down-script=telegram-down up-script=telegram-up

POST a JSON payload to any webhook endpoint (Slack, ntfy.sh, custom systems):

/system/script add name=webhook-down source={
:local webhookUrl "https://hooks.example.com/services/XXXX/YYYY/ZZZZ"
:local payload ("{\"text\":\"HOST DOWN: " . $host . " since " . $since . "\"}")
/tool/fetch url=$webhookUrl http-method=post \
http-header-field="Content-Type: application/json" \
http-data=$payload output=none
}

For ntfy.sh or a self-hosted ntfy instance:

/system/script add name=ntfy-down source={
:local topic "my-router-alerts"
/tool/fetch url=("https://ntfy.sh/" . $topic) \
http-method=post \
http-header-field="Title: Host Down" \
http-data=("Host " . $host . " is unreachable since " . $since) \
output=none
}

When external services are unavailable or unnecessary, write structured log entries:

/system/script add name=log-down source={
:log warning ("NETWATCH DOWN host=" . $host . " since=" . $since \
. " failed=" . $"failed-tests")
}
/system/script add name=log-up source={
:log info ("NETWATCH UP host=" . $host . " recovered=" . $since)
}

Filter these entries later:

/log print where message~"NETWATCH"

Avoid false alerts while the router is establishing connectivity after a reboot. Use start-delay to hold off the first probe:

/tool/netwatch set [find where host=203.0.113.1] start-delay=60s

This delays the first probe by 60 seconds, giving PPPoE, DHCP, or BGP sessions time to come up before Netwatch begins evaluating host reachability.

This example monitors a primary WAN gateway. When it becomes unreachable, Netwatch disables the primary default route and enables a backup. When the gateway recovers, traffic automatically returns to the primary path.

Assume:

  • Primary WAN: interface ether1, gateway 203.0.113.1
  • Backup WAN: interface ether2, gateway 198.51.100.1
  • Both routes exist in the routing table with comments for easy identification

Step 1: Add the routes

/ip/route add dst-address=0.0.0.0/0 gateway=203.0.113.1 comment=primary-wan distance=1
/ip/route add dst-address=0.0.0.0/0 gateway=198.51.100.1 comment=backup-wan distance=2 disabled=yes

Step 2: Create the failover scripts

/system/script add name=wan-failover-down source={
:log warning "Primary WAN DOWN - activating backup route"
/ip/route set [find where comment="primary-wan"] disabled=yes
/ip/route set [find where comment="backup-wan"] disabled=no
:log info "Backup WAN route is now active"
}
/system/script add name=wan-failover-up source={
:log info "Primary WAN UP - restoring primary route"
/ip/route set [find where comment="backup-wan"] disabled=yes
/ip/route set [find where comment="primary-wan"] disabled=no
:log info "Primary WAN route restored"
}

Step 3: Configure Netwatch to monitor the primary gateway

/tool/netwatch add \
name=primary-wan-gw \
host=203.0.113.1 \
type=icmp \
interval=10s \
timeout=3s \
thr-loss-percent=50 \
down-script=wan-failover-down \
up-script=wan-failover-up \
comment="Primary WAN gateway health check"

Step 4: Verify

/tool/netwatch print
/log print where message~"WAN"
EventAction
Primary gateway packet loss exceeds 50%down-script runs, backup route activates
Primary gateway becomes reachable againup-script runs, primary route restores
Each probe cycleStatus and timestamps visible in /tool/netwatch print

Using Routing Distances Instead of Disabling Routes

Section titled “Using Routing Distances Instead of Disabling Routes”

An alternative approach keeps both routes active at all times and uses Netwatch scripts to change the distance value. The backup route is always present in the routing table; the scripts make it preferred by temporarily giving it a lower distance than the primary.

Step 1: Add both routes — primary preferred by default

/ip/route add dst-address=0.0.0.0/0 gateway=203.0.113.1 comment=primary-wan distance=1
/ip/route add dst-address=0.0.0.0/0 gateway=198.51.100.1 comment=backup-wan distance=10

Step 2: Create scripts that change the primary route’s distance

/system/script add name=wan-dist-down source={
:log warning "Primary WAN DOWN - raising primary route distance"
/ip/route set [find where comment="primary-wan"] distance=20
:log info "Backup WAN now preferred (distance 10 < 20)"
}
/system/script add name=wan-dist-up source={
:log info "Primary WAN UP - restoring primary route distance"
/ip/route set [find where comment="primary-wan"] distance=1
:log info "Primary WAN restored to preferred path (distance 1)"
}

Step 3: Attach scripts to Netwatch

/tool/netwatch add \
name=primary-wan-gw \
host=203.0.113.1 \
type=icmp \
interval=10s \
thr-loss-percent=50 \
down-script=wan-dist-down \
up-script=wan-dist-up

Both routes remain visible in /ip/route print at all times, which makes it easy to inspect the current failover state without checking whether a route is disabled. The disable/enable approach (above) is equivalent in function; the distance approach is preferred when you want both paths visible for monitoring or when using tools that enumerate active routes.

  1. Verify the host IP is correct: /ping 203.0.113.1
  2. Check firewall rules — ICMP may be blocked on the target or a transit device
  3. For TCP probes, verify the service is listening on the specified port
  4. Increase timeout for hosts with high latency
  5. Confirm routing to the target exists: /ip/route print where active=yes
  1. Check the script name is spelled correctly: /system/script print
  2. View script execution errors: /log print where topics~"script"
  3. Verify the netwatch entry has the script assigned: /tool/netwatch print detail
  4. Test the script manually: /system/script run wan-failover-down
  1. Increase interval to reduce sensitivity to momentary packet loss
  2. Raise thr-loss-percent threshold for ICMP probes — require sustained loss before declaring down
  3. Increase timeout to allow more time for slow responses
  4. Use type=tcp-conn targeting a specific service port rather than ICMP, which may be rate-limited
  1. Reduce the number of monitored entries
  2. Increase interval — frequent probes add measurable load on busy routers
  3. Reduce packet-count for ICMP probes to send fewer packets per cycle
  • /tool/ping — Manual connectivity test
  • /tool/traceroute — Path analysis and hop latency
  • /system/script — Script management
  • /ip/route — Routing table management
  • /tool/e-mail — Email notification configuration
  • /log/print — View system log