← GeoFilter Builder

GeoFilter Docs

How it works

Geographic filtering restricts which nodes are ingested and returned in API responses. It operates at two levels:

Nodes with no GPS fix (lat=0, lon=0 or missing coordinates) always pass the filter regardless of configuration.

Configuration

Add a geo_filter block to config.json:

"geo_filter": {
  "polygon": [
    [51.55, 3.80],
    [51.55, 5.90],
    [50.65, 5.90],
    [50.65, 3.80]
  ],
  "bufferKm": 20
}
FieldTypeDescription
polygon[[lat, lon], ...]Array of at least 3 coordinate pairs defining the boundary
bufferKmnumberExtra distance (km) around the polygon edge that is also accepted. 0 = exact boundary

Both the server and the ingestor read geo_filter from config.json. Restart both after changing this section.

To disable filtering entirely, remove the geo_filter block.

Builder workflow: Save Draft, Load Draft, Download

The GeoFilter Builder lets you draw a polygon on a map and produce the geo_filter snippet without hand-editing JSON. Three buttons drive the workflow:

Drafts are stored locally in your browser only — they are not uploaded anywhere. Clearing site data or switching browsers will lose the draft. Use Download to keep a portable copy.

After pasting the snippet into config.json, restart the server and ingestor for the new filter to take effect.

Coordinate ordering

Important: Coordinates are [lat, lon] — latitude first, longitude second. This is the opposite of GeoJSON, which uses [lon, lat]. Swapping them will place your polygon in the wrong location.

Multi-polygon

Only a single polygon is supported. If your deployment area consists of multiple disconnected regions, draw a single convex hull that covers all of them, or use the largest region with a generous bufferKm value.

Examples

Belgium (bounding rectangle)

"geo_filter": {
  "polygon": [
    [51.55, 3.80],
    [51.55, 5.90],
    [50.65, 5.90],
    [50.65, 3.80]
  ],
  "bufferKm": 20
}

Irregular shape

"geo_filter": {
  "polygon": [
    [51.10, 3.70],
    [51.55, 4.20],
    [51.30, 5.10],
    [50.80, 5.50],
    [50.50, 4.80],
    [50.70, 3.90]
  ],
  "bufferKm": 10
}

Legacy bounding box

An older bounding box format is also supported as a fallback when no polygon is present:

"geo_filter": {
  "latMin": 50.65,
  "latMax": 51.55,
  "lonMin": 3.80,
  "lonMax": 5.90
}

Prefer the polygon format — it supports irregular shapes and the bufferKm margin.

Cleaning up historical nodes

The ingestor prevents new out-of-bounds nodes from being ingested, but does not retroactively remove nodes stored before the filter was configured. Use the prune script for that:

# Dry run — shows what would be deleted without making any changes
python3 scripts/prune-nodes-outside-geo-filter.py --dry-run

# Default paths: /app/data/meshcore.db and /app/config.json
python3 scripts/prune-nodes-outside-geo-filter.py

# Custom paths
python3 scripts/prune-nodes-outside-geo-filter.py /path/to/meshcore.db \
  --config /path/to/config.json

# In Docker — run inside the container
docker exec -it meshcore-analyzer \
  python3 /app/scripts/prune-nodes-outside-geo-filter.py --dry-run

The script reads geo_filter.polygon and geo_filter.bufferKm from config, lists nodes that fall outside, then asks for yes confirmation before deleting. Nodes without coordinates are always kept.

This is a one-time migration tool — run it once after first configuring geo_filter to clean up pre-filter data.