Skip to content

Coverage Report ​

The Coverage Report is a passive, measured coverage map: dots on a map, coloured by signal, built from real position packets your radios already heard. It replaces the Range Test module Meshtastic firmware 2.8 removed β€” but works differently. Range Test made two nodes trade dedicated test packets. Coverage Report needs no dedicated test traffic at all: drive a node that broadcasts its position, and every receiver that hears it becomes a data point.

MeshMonitor sends nothing ​

This feature sends zero packets. It only records position packets a Meshtastic source already received over RF. MeshMonitor never pushes configuration to your survey node and never requests anything from the mesh to build this report. The only airtime cost is the survey node's own position broadcasts β€” see How to survey below for the numbers.

How to survey ​

Take one node with GPS for a drive (or walk) around the area you want to map, with position broadcast turned on. Recommended settings on that node:

  • hop_limit 0 β€” the position travels no further than direct radio range, which is what a coverage map wants to measure.
  • Smart position enabled β€” it honours hop_limit 0 rather than overriding it with the firmware default of 3.
  • Smart position minimum interval of 30 seconds or more, on a private channel only. On a channel with the default key and a preset name, the firmware raises this to at least 5 minutes at boot, and the plain position interval to at least 1 hour. Shorter than 30 seconds adds airtime without adding much coverage data. See Why a survey looks sparse.

Receiver firmware caveat: a receiving node only keeps a zero-hop (hop_limit 0) packet on firmware 2.7.20 or later β€” older firmware drops packets with hop_start == 0 before it even decrypts them. If any node in your mesh that might hear the survey drive runs older firmware, use hop_limit 1 instead. A direct copy still shows as 0 hops in the report; the cost is that each neighbour now rebroadcasts the packet once too.

Airtime cost at a 30-second position interval:

hop_limitTx per fix% of channel per hour
01~2%
12–4~4–8%
34–8~8–16%

These are rough estimates (a position packet takes about 0.5–0.6 s on LongFast) and scale with how many neighbours rebroadcast. hop_limit 3 is shown for reference only β€” it is not recommended for surveying.

The report's own Setup guidance panel (collapsed by default, below the map) repeats this same recommendation and table.

Surveying with a MeshCore node ​

MeshCore nodes report their position only in adverts, and a companion has no advert timer, so the driver sends them by hand.

  • Send zero-hop adverts only, about once every 60 seconds. In the MeshCore app, use the zero-hop advert option; on a repeater, use the CLI command advert.zerohop, never advert.
  • Never flood adverts for a survey. A flood advert is rebroadcast by every repeater in reach (up to 8 hops): with 20 repeaters that is about 9 s of channel time per advert on a US preset, 25 s on an EU preset.
  • MeshMonitor's own "Send advert" button floods, so don't use it for a survey.
  • An advert carries the node's stored advert position, not a live GPS fix. Make sure the node updates its advert location as it moves.
AdvertChannel time per advertEvery 60 s
Zero-hop, US (SF7/BW62.5)~0.4–0.5 s~0.7%
Zero-hop, EU (SF8/BW62.5/CR8)~1.1–1.3 s~1.9%
Flood, 20 repeaters in reach~9 s (US) / ~25 s (EU)15–40%

Why a survey looks sparse ​

A thin map does not always mean poor radio reach. Meshtastic firmware holds back, drops and filters position packets to save airtime. Those rules suit daily use, and a survey runs into most of them. On the map, a packet the firmware held back looks the same as a packet the radio never heard.

This section covers Meshtastic. The facts come from the firmware source (2.7.27 and 2.8.2); the files are named so you can check them.

What the survey node holds back ​

The survey node skips or delays its own position broadcasts in these cases.

  • Busy channel. The node skips a position when channel use over the last minute is above 25%. For the TRACKER and TAK_TRACKER roles the limit is 40%. The node logs Ch. util >25%. Skip send (or >40%) each time. (src/modules/PositionModule.cpp, src/airtime.cpp)
  • Default channel. If position goes out on a channel with the default key and a preset name such as LongFast, the firmware raises the position interval to at least 1 hour and the smart position minimum interval to at least 5 minutes. It does this at every boot, whatever you saved. A 30-second interval works only on a private channel. (src/mesh/NodeDB.cpp, src/mesh/Default.h)
  • Large mesh. With more than 40 nodes online, the firmware stretches the interval. TRACKER, TAK_TRACKER, SENSOR and the router roles are exempt. (src/mesh/Default.h)
  • Legal duty cycle. In a region with a duty-cycle limit, such as EU_868, the node stops sending once it reaches the full limit. The lower "polite" limit does not apply to position packets. (src/mesh/Router.cpp)

Firmware 2.8 adds three more:

  • Parked node. A node that has not moved out of its grid cell, or that uses a fixed position, sends a position at most once every 6 hours. The LOST_AND_FOUND role is exempt.
  • Coarse position on public channels. On a channel anyone can decrypt, the node sends its position at no more than 15 bits of precision: a grid of roughly 700 m or coarser. A channel with precision 0 sends no position at all. (src/mesh/PositionPrecision.h)
  • Shorter reach. The firmware may lower hop_limit on position broadcasts. It never raises it.

What relays and receivers drop (firmware 2.8) ​

Firmware 2.8.0 added the Traffic Management module. Firmware 2.7 does not have it. It is on by default on every board except STM32WL, and it drops repeated positions.

A node drops a position packet only when all of these hold:

  • another node sent it,
  • it arrived on a well-known channel (default key or no key, and a preset name),
  • it falls in the same grid cell as the last position this node passed from that sender, and
  • it arrived inside the dedup window.

The default window is 18,000 seconds (5 hours). The protobuf comment says 6 hours; the firmware uses 5. For a TRACKER or TAK_TRACKER sender the window is at most 1 hour, and for LOST_AND_FOUND at most 15 minutes. A value of 0 turns dedup off. (src/modules/TrafficManagementModule.cpp, src/mesh/Default.h)

The grid cell is as large as the channel's position precision. So:

  • A moving survey node passes. Each new cell is a new position.
  • A parked survey node does not. You get one dot per spot, however long you wait there.

A dropped packet goes no further on that node. The node does not rebroadcast it, so receivers further out lose that copy. The node also does not hand it to connected apps, so MeshMonitor never sees it on that source.

The module's other features (rate limit, unknown-packet drop, NodeInfo direct response) are off by default.

What MQTT gateways miss ​

  • "OK to MQTT" off. A gateway on a public broker does not uplink packets from a node that has "OK to MQTT" turned off. A broker on a private IP address skips this check. (src/mqtt/MQTT.cpp)
  • Old gateway firmware. A gateway drops a zero-hop packet unless it runs firmware 2.7.20 or later.
  • Dedup does not stop the uplink. A 2.8 gateway still uplinks a position that its own Traffic Management module dropped. So an MQTT source can show a fix that the same node, as a radio source, does not.

What MeshMonitor cannot see ​

MeshMonitor records only the position packets a node hands over. It also skips your own node's position, packets that did not arrive over RF, replays of old packets, packets with id 0, and packets with a stale receive time.

It has no record of a packet that was never sent or that a node dropped. It cannot tell those from a packet lost to poor reach. The Likely gaps lines mark where fixes went missing, not why.

Settings for a survey ​

Change these on your own nodes, in the Meshtastic app or on MeshMonitor's Device Configuration tab. The Coverage Report changes nothing for you.

SettingFor a surveyWhy
Survey channelA private channel (your own key) that carries position, on the survey node and on each receiverAvoids the 1-hour and 5-minute floors, the 15-bit limit and receiver dedup
RoleTRACKER on the survey node for the driveRaises the busy-channel limit to 40% and skips the large-mesh stretch
Smart position minimum interval30 s, on a private channel onlyThe firmware raises it to 5 minutes on a default channel
Position dedup window (Traffic Management, receivers on 2.8)Leave alone. Set 0 only for a parked test, then put it backA moving node already passes; 0 lets every repeat through and costs the mesh airtime
Override duty cycleDo not changeIt breaks the legal airtime limit for your region
Traffic Management rate limitDo not changeOff by default; it does not affect a survey

Do not trade the mesh for a denser map

Turning on Override duty cycle can break radio law in your region. A very short position interval on a public channel takes airtime from everyone on it, and the firmware raises it to 5 minutes anyway. Use a private channel, keep hop_limit 0, and put the node back to its usual role and settings after the drive.

Troubleshooting by symptom ​

What you seeLikely causeWhat to do
One dot per parked spotThe node did not leave its grid cell. Smart position sends nothing while it sits still; on 2.8 the 6-hour parked floor and receiver dedup apply tooExpected. Move the node, or use a private channel for a parked test
Dots every 5 minutes or moreThe survey node sends position on a default channel, so the firmware raised the intervalMove the survey to a private channel, then reboot the node
Dots snapped to a coarse gridThe channel's position precision is low, or a 2.8 node limited it to 15 bits on a public channelUse a private channel with full precision
No dots on one 2.8 source, others fineThat node's Traffic Management module dropped the repeatsUse a private channel; for a parked test, set that node's dedup window to 0 and put it back after
MQTT gateways missing"OK to MQTT" is off on the survey node, the gateway firmware is older than 2.7.20, or MQTT recording is off for that sourceTurn on "OK to MQTT" on the survey node; check Settings β†’ Coverage recording
Dots stop in a busy areaThe node skipped sends above 25% channel useCheck the node log for Skip send; use the TRACKER role for the drive

Reading the report ​

Open Analysis & Reports from the dashboard sidebar, then click the Coverage Report card.

Filters ​

  • Time range β€” presets (1 h, 6 h, 24 h default, 3 days, 7 days) or a custom from/to range with an Apply button. Nothing refetches until you click a preset, click Apply, or click Refresh.
  • Sender β€” narrow to one survey node, or leave on All. Type to search by name or id; each entry shows the sender's name, id, and how many fixes it produced in the current window.
  • Receivers β€” every receiver that has heard anything in the retention window, grouped by source and sorted by how many receptions each has. Each row is marked Local (your own radio) or Gateway (an MQTT gateway). Search by name or !id, use Select all / Select none, or tick a whole source group at once. All are selected by default.
  • MQTT recording status β€” each MQTT source shows Recording or Off. When it's off, Turn on in source settings opens that source's toggle.
  • Hops β€” Any, or an exact hop count 0–7. Check Up to this many hops to turn it into a ceiling instead of an exact match.
  • Colour by β€” SNR (default) or RSSI.
  • View β€” Dots (one per fix) or Grid (see below), with a cell size of 100 m, 250 m, 500 m or 1 km for the grid.
  • Export β€” download the loaded receptions as CSV or GeoJSON (see below).
  • Refresh β€” re-runs the current filters against the latest data. The report does not poll in the background.

The map ​

Each dot is one physical position fix. Its colour is the best (highest) reading among the receptions currently in scope β€” with one receiver selected, that receiver's own reading. Receiver locations are drawn as larger, distinctly outlined markers with a permanent name label.

Click a dot to see every reception of that fix within your current filter: receiver name, SNR, RSSI, whether it arrived direct or relayed (with the hop count and the relaying node's short ID), and the distance between the fix and that receiver. RSSI can be blank ("β€”") when the receiving firmware didn't report it; SNR is blank the same way. A path shows as Unknown rather than a hop count when the packet's zero-hop bitfield isn't present β€” that happens on firmware older than 2.5.0.

The legend shows the same four signal bands (Excellent / Good / Fair / Poor) used elsewhere in MeshMonitor, plus No data. For a fix heard with one or more hops, the colour reflects the last relay's link, not a straight line back to the original sender β€” the dot's position is the sender's, but its colour describes the hop that actually reached the receiver you're looking at.

A truncation banner appears if a window returns more than the report will load (about 10,000 rows); narrow the time range or filters to see the rest. An empty state explains that only receptions recorded since you upgraded to a MeshMonitor version with this feature appear β€” there is no backfill from data collected before that.

Likely gaps ​

Pick one sender and the map draws dashed lines between consecutive fixes where the next fix arrived much later than expected: a likely dead zone. Hover a line to see how long the gap was and roughly how many fixes went missing.

  • Expected interval: the sender's usual spacing between fixes, taken from its recent fixes (at least 5 spacings, 15 s to 15 min). With fewer, it assumes 30 s for Meshtastic and 60 s for MeshCore.
  • What counts as a gap: a spacing longer than 2.5 Γ— that interval and longer than 60 s, but no more than 30 minutes (longer is treated as a break in the drive), where the sender moved at least 200 m. A node parked in one spot isn't a dead zone: smart position sends nothing while it sits still.
  • Gaps count against the receivers you have ticked, so unticking a receiver can reveal gaps that another receiver was covering.

Summary ​

Below the map, the Summary shows fixes heard, receptions, and best and worst SNR and RSSI. With one sender picked it adds fixes heard against fixes expected, the interval it used, and the number of likely gaps.

The Receivers table lists each receiver with the fixes it heard, its median SNR, and its furthest direct (0-hop) reception.

The Distance vs SNR chart plots every direct reception whose receiver position is known, one colour per receiver (the seven busiest, then "Other"). Above about 3,000 points it shows an even sample and says so.

Grid view ​

Grid replaces the dots with square cells. Each cell is coloured by the median of the best reading of each fix inside it, which evens out repeated drives over the same roads. Hover a cell for its median and fix count.

Export ​

CSV and GeoJSON download exactly what the report has loaded, after your filters and privacy rules. If the report hit its load limit, the export is limited too and says so. Names that start with =, +, - or @ are escaped in the CSV so a spreadsheet won't treat them as formulas.

Opening from node details ​

A node's details panel (Meshtastic and MeshCore) has a Show coverage link. It opens this report with that node as the sender for the last 24 hours. The same view can be shared as a link: /reports?report=coverage&sender=<id>&range=24h.

What gets recorded ​

Meshtastic radio (RF) sources record receptions always. A position packet that arrived over MQTT on a radio source is skipped, since an MQTT-relayed copy's SNR isn't your radio's own reading.

MQTT sources (broker and bridge) record only when you turn it on, per source, under Settings β†’ Coverage recording for that source. It is off by default. Once on, every gateway that uplinks a position packet becomes a receiver, with the SNR and RSSI that gateway measured, so one drive can show what every gateway in the area heard.

MeshCore companion sources record adverts that carry a position, always. Each advert's signature is checked first; an advert that fails the check, or an older advert re-sent later (for example a shared contact), is not recorded. Your companion's own advert coming back is skipped too. Repeater serial sources don't record.

MeshCore Observer sources record only when you turn it on, per source, under Settings β†’ Coverage recording, off by default. Each observer shows as its own receiver, labelled Observer. How many rows an observer feed adds hasn't been measured yet, and the toggle says so.

For MQTT sources:

  • Volume: a regional feed adds about 12,000–14,000 rows a day (about 90,000–100,000 rows, 35–50 MB, over 7 days of retention). A world-wide msh/# feed can reach about 1 million rows a day and several GB a week. There is no cap beyond retention; the toggle asks you to confirm.
  • Not recorded: a gateway's own position, packets a gateway reports it got over MQTT or UDP, packets with a stale receive time (more than 10 minutes old, from a wrong gateway clock or a late queue flush), and gateways on your ignore list.
  • Missing nodes: nodes that turn off "OK to MQTT" aren't uplinked by gateways on public brokers, so they never appear.
  • Rows only start from when you turn recording on; nothing is back-filled.

MeshMonitor stores one row per distinct path: the same fix heard directly and heard again relayed through a different neighbour are two separate rows, because they describe two different links. An exact repeat of the same path (a retransmission of the identical packet through the identical relay) collapses into the one row already stored β€” first copy wins, later copies aren't merged in.

Retention ​

Open Global Settings β†’ Coverage Report to set how many days of receptions are kept, from 1 to 90, default 7. This is a single, deployment-wide setting, not a per-source one. An hourly background sweep deletes rows older than the configured window. Lowering the value deletes older data on the next sweep, and that cannot be undone β€” the settings field warns about this before you save.

Receptions inside a saved survey are kept past this window until the survey is deleted (see below).

Saved surveys ​

A survey is one sender over one time window, with a name, optional notes and an optional broadcast interval. Save one to keep a drive past the retention period and come back to it later.

  • Start survey starts a live survey for the selected sender now. It runs until you press Stop survey, and ends on its own after 24 hours.
  • Save as survey saves the time range you're looking at, up to 7 days.
  • Picking a survey from the Survey list sets the sender, the time window and the receivers you had ticked when it was saved. If you gave it a broadcast interval, gap detection uses that instead of guessing.
  • Edit changes the name, notes or interval; Delete removes the survey. Its receptions stay recorded and go back to the normal retention sweep.
  • A survey can be shared as a link: /reports?report=coverage&survey=<id>.

Who can do what: anyone logged in who can see the sender on a map can save a survey for it. Only the person who created a survey, or an admin, can edit, stop or delete it. You see your own surveys plus any survey whose sender you can see; visitors who aren't logged in see none. Each user can keep 50 surveys, with 500 across the install, and a sender can have only one live survey at a time.

What's kept: every reception of the survey's sender inside its time window, on every source, whatever receivers were ticked when it was saved. Deleting a source, or purging its nodes, still removes that source's receptions; the survey stays and shows what's left.

Backups include saved surveys and the receptions inside their windows. Other receptions are not backed up.

Heard between your sources ​

If you run more than one source, one of your radios can be the survey sender and another the receiver. The report marks those fixes:

  • In the Sender picker, a sender that is one of your own sources reads "our source", followed by that source's name.
  • Cross-source only (shown once such a sender exists) keeps just the fixes one of your sources sent and another heard.
  • Under the summary, Heard between your sources lists one row per receiver: "12 fixes from Radio A heard by Radio B over 24h", with how the copy arrived (RF, or MQTT gateway (RF) when a gateway's radio heard it) and the median and best SNR.

Two radios on different LoRa presets cannot hear each other over RF, so expect no RF rows between them. A gateway row can still appear.

You only see this when you can read both sources. If you can read just one, its rows look like any other and nothing names the other source.

Privacy ​

A position only appears on the Coverage Report if it would also appear on the Map Analysis positions layer: hidden-from-map nodes, private overrides you don't hold the permission to view, and channels without "view on map" enabled are all excluded, using the same checks as /api/analysis/positions. You also need read permission on a source to see its receivers, senders, or receptions at all β€” a source you can't read contributes nothing to the report.

MeshCore positions follow the same rule as the MeshCore map: the node must be a known contact of that source, and you need view on map permission for the source (admins have it everywhere). A MeshCore node the source doesn't know never appears, even for an admin.

  • Analysis & Reports β€” the workspace this report's card lives in
  • Map Analysis β€” the positions layer this report reuses the same visibility rules from
  • Packet Monitor β€” the opt-in per-source packet logs, a different feature with its own retention model
  • Global Settings β€” where the retention window is configured