---
title: "Geolocation"
date: 2026-05-10
---
<!-- licenses: platform -->

runZero resolves a geographic location for every asset where it has enough information to do so, and uses those locations to power the [World Map](world-map.md), inventory search, and exports. This page describes the different sources runZero uses for ((asset geolocation)), how user-supplied location tags are interpreted, and the order in which sources are applied.

## Where locations come from

runZero builds asset locations from five independent sources during each analysis pass. Every location is recorded with provenance, so each pin on the World Map can be traced back to the specific attribute, integration, or tag that produced it.

<table>
<colgroup><col width="25%"><col width="75%"></colgroup>
<thead><tr><th>Source</th><th>Description</th></tr></thead>
<tbody>
<tr><td><code>attribute-coord</code></td><td>Paired numeric latitude/longitude attributes from integrations or imports.</td></tr>
<tr><td><code>attribute-ip</code></td><td>Egress / public IP addresses resolved through ((MaxMind)) ((GeoLite2)).</td></tr>
<tr><td><code>attribute-text</code></td><td>Discrete country / city attributes, plus free-form <code>snmp.sysLocation</code>-style strings.</td></tr>
<tr><td><code>cloud-region</code></td><td>AWS, Azure, GCP, OCI, IBM Cloud, and DigitalOcean region codes resolved to a region centroid.</td></tr>
<tr><td><code>geolite-isp</code></td><td>((GeoIP)) lookup of the asset's primary scanned IP through ((MaxMind)) ((GeoLite2)).</td></tr>
<tr><td><code>manual</code></td><td>User-supplied <a href="#manually-setting-an-asset-location"><code>geo*</code> asset tags</a>.</td></tr>
</tbody>
</table>

An asset can carry locations from more than one source at a time. For example, a cloud workload may have a `cloud-region` location from its AWS region, an `attribute-ip` location from its public NAT address, and a `manual` location set by a tag — all three appear as separate pins on the [World Map](world-map.md), each labelled with its source.

When multiple sources agree on the same coordinate the entry is de-duplicated.

## GeoIP lookups against MaxMind

runZero ships with the ((MaxMind)) ((GeoLite2)) City and ASN databases. These are used to resolve any public IP address that runZero observes for an asset into a latitude, longitude, country, subdivision (state/province), city, postal code, timezone, continent, ASN number, and ASN organization name.

Private RFC1918 and RFC6598 addresses are rejected by the lookup layer, so a private IP never produces a location.

### Primary and hinted external IPs

When an asset is scanned, runZero records the public IP it observed for that asset. The primary scanned address is looked up directly against ((GeoLite2)) and produces a location with source `geolite-isp`.

When passive sources or integrations report additional public addresses for the same asset — for example a secondary NAT address, or an alternate egress on a multi-homed device — those are also looked up. The resulting locations are recorded alongside the primary so that an asset visible at two different egress points appears in both places on the [World Map](world-map.md).

### Egress and public-IP attributes from integrations

Many integrations report the public / external / NAT IP address an asset was observed from. runZero ingests these and resolves each through ((GeoLite2)). The lookup produces both a city-level location and an ASN annotation for the pin.

The attributes consumed by the egress IP pipeline are:

| Attribute               | Set by                                          |
|-------------------------|-------------------------------------------------|
| `externalIP`            | CrowdStrike, SentinelOne                        |
| `publicIP`              | Azure (VM/database/load balancer), Microsoft Defender for Endpoint, AWS  |
| `publicIPs`             | AWS                                             |
| `natIP`                 | Google Cloud Platform                           |
| `wanIPAddresses`        | Google Workspace                                |
| `discover.externalIP`   | CrowdStrike                                     |

The full set of unique public IPs seen across these attributes is also written back to the asset as an `egressIPs` attribute, so you can query the underlying values directly.

## Cloud region codes

When an integration provides a cloud region code — for example AWS `us-east-1`, Azure `eastus`, or GCP `europe-west4` — runZero maps the code to the published centroid of that region. This gives the asset a country, subdivision (where applicable), city, and continent without requiring a GeoIP lookup.

The cloud region pipeline reads from attributes including `region`, `cloud.region`, `aws.region`, `azure.region`, `azure.location`, `gcp.region`, `gcp.zone`, `oci.region`, `availabilityZone`, `availability_zone`, `zone`, `placement.region`, and `placement.availabilityZone`. Unknown values (for example a generic `region=Northeast` tag) are ignored.

## Discrete country and city attributes

Some integrations report location as separate `country` (or `countryCode`) and `city` fields. runZero pairs these up and resolves the combination to the matching GeoNames city centroid. If only a city is present, the global highest-population match is used.

The country fields consumed are: `country`, `countryCode`, `country_code`, `host.country`, `host.countryCode`, `host.location.country`, `host.location.countryCode`, `discover.country`, `discover.countryCode`, `custom.country`, and `site.country`.

The city fields consumed are: `city`, `host.city`, `host.location.city`, `discover.city`, `custom.city`, and `site.city`.

## Free-form location strings

Free-form location strings from SNMP and integrations are parsed best-effort. The parser strips address noise — house numbers, suite/floor markers, PO boxes, postal codes, street suffixes like `St`, `Ave`, `Blvd` — and matches the remaining trailing tokens against the bundled ((GeoNames)) tables.

The free-form attributes consumed are: `location`, `host.location`, `site.location`, `custom.location`, `location.address`, `snmp.sysLocation`, and `shodan.snmp.location`.

This is best-effort by design. SNMP `sysLocation` has no standardized format, and many devices report a campus or rack identifier rather than an address. When the parser cannot anchor the string to a known city, region, or country, no location is recorded.

## Manually setting an asset location

You can pin an asset to a specific geographic location by setting one of the `geo*` tags below. Each tag has a fixed shape, and the value tells runZero where the asset is. The location appears on the [World Map](world-map.md), in exports, and in queries the next time metrics are recalculated for the asset.

<div class="alert alert-info">
<svg class="alert-icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>
<div class="alert-body">

Manual `geo*` tags do not take effect immediately. They are picked up the next time runZero recalculates metrics for the asset, which happens automatically as part of normal task processing (scans, integration syncs, and scheduled metrics tasks). To force the change to apply right away, go to **Dashboard → Recalculate metrics**.

</div>
</div>

> **TL;DR** — set one tag. Use `/` to separate fields.
>
> ```
> geoCity = Austin/TX/US
> geoCity = Springfield/IL/US
> geoLatLng = 30.2672/-97.7431
> ```

### Available tags

| Tag                  | Shape                                                               | Example                              |
|----------------------|---------------------------------------------------------------------|--------------------------------------|
| `geoLatLng`          | `lat/lng`                                                           | `geoLatLng = 30.2672/-97.7431`       |
| `geoContinent`       | continent name or two-letter alias (`EU`, `NA`, ...)                | `geoContinent = Europe`              |
| `geoCountry`         | country (see [Country values](#country-values))                     | `geoCountry = US`                    |
| `geoRegionCountry`   | `region/country`                                                    | `geoRegionCountry = TX/US`           |
| `geoRegion`          | `region/country` or a single token (state, country, or continent)   | `geoRegion = Texas`                  |
| `geoState`           | alias of `geoRegion`                                                | `geoState = TX/US`                   |
| `geoProvince`        | alias of `geoRegion`                                                | `geoProvince = Ontario`              |
| `geoCity`            | `city/country` or `city/region/country`                             | `geoCity = Austin/US`                |

You only need to set **one** tag per asset. If you set more than one, runZero uses whichever tags match their shape. Tags whose values do not match their expected shape are silently ignored — runZero will not guess.

### When to use which tag

* Use **`geoLatLng`** if you have exact coordinates from a CMDB, building floor plan, or GPS source.
* Use **`geoContinent`** when you only know the continent.
* Use **`geoCountry`** when you only know the country.
* Use **`geoRegionCountry`** when you know the country and the state/province/region but not the city.
* Use **`geoRegion`** (or its synonyms `geoState` / `geoProvince`) when you want runZero to accept any plausible region-ish value: a `region/country` pair, a unique state name (`Texas`, `Ontario`, `Bavaria`), a country code, or a continent.
* Use **`geoCity`** in every other case. The two-field form is enough for major cities; use the three-field form to disambiguate names like `Springfield`, `Portland`, or `Cambridge`.

### Field separator

The separator between fields is always a forward slash (`/`). The characters `-`, `.`, `,`, and `_` are **not** field separators because they appear inside real city and region names — `Winston-Salem`, `St. Louis`, `Stratford-upon-Avon`, `St-Lawrence`.

```
geoCity = Austin/US                   ✓  city/country
geoCity = Austin TX US                ✗  no separators
geoCity = Austin-TX-US                ✗  hyphen is part of names, not a separator
geoCity = Austin,TX,US                ✗  comma is part of names, not a separator
```

If you set a tag through the UI or API and the value contains spaces, runZero stores those spaces as underscores. The parser treats `_` and a space identically inside a field, so `geoCity = San Francisco/CA/US` and `geoCity = San_Francisco/CA/US` parse identically.

### Country values

Any of these forms work for the country field:

| Form                | Examples                                          |
|---------------------|---------------------------------------------------|
| ISO 3166-1 alpha-2  | `US`, `DE`, `GB`, `JP`                            |
| ISO 3166-1 alpha-3  | `USA`, `DEU`, `GBR`, `JPN`                        |
| English name        | `United States`, `Germany`, `Japan`               |
| Common alias        | `UK` and `Britain` (both → `GB`)                  |

Country values are case-insensitive. When an alias is recognized, runZero normalizes it to the ISO alpha-2 code shown on the map.

### Region values

Region values are state, province, or admin region names. runZero recognizes both short codes and full names for the countries below; for other countries, runZero accepts the [GeoNames admin1 code](https://www.geonames.org/) directly (often a numeric value like `02` or `16`).

| Country         | Examples of accepted region values                            |
|-----------------|---------------------------------------------------------------|
| United States   | `TX`, `Texas`, `CA`, `California`                             |
| Canada          | `ON`, `Ontario`, `BC`, `British Columbia`, `Québec`           |
| Australia       | `NSW`, `New South Wales`, `VIC`, `Victoria`                   |
| United Kingdom  | `England`, `Scotland`, `Wales`, `Northern Ireland`            |
| Ireland         | `Connacht`, `Leinster`, `Munster`, `Ulster`                   |
| New Zealand     | `Auckland`, `Canterbury`, `Wellington`                        |

If runZero does not recognize the region, the asset still resolves at the country level — the region tag is informative but never blocking.

### City matching and GeoNames

City and region matches are performed against the bundled ((GeoNames)) data. The matcher is fuzzy: `St. Louis`, `St Louis`, `St-Louis`, `Saint Louis`, and `saint_louis` all resolve to the same record. The canonical GeoNames spelling is what shows on the map and in exports, so your tag values do not need to be perfectly formatted to look right.

When a city name is ambiguous (`Springfield`, `Cambridge`, `Portland`), use the three-field form to disambiguate:

```
geoCity = Springfield/IL/US      ✓ disambiguated
geoCity = Springfield/MO/US      ✓ different city
geoCity = Springfield/US         ⚠ resolves to whichever Springfield is largest
```

### Examples {#geo-keyword-examples}

Pinning a corporate office:

```
geoCity = Austin/TX/US
```

A device with exact coordinates:

```
geoLatLng = 30.2672/-97.7431
```

A subnet known to be in Germany but unknown city:

```
geoCountry = DE
```

A device in a region but unknown city:

```
geoRegionCountry = Bayern/DE
```

### What happens if the value is wrong?

Each tag has a fixed shape and a strict matcher. When the value does not fit the shape — or names a place that runZero's bundled GeoNames data does not recognize — the tag produces no manual location, and no manual pin is shown on the map for that asset.

This is intentional. To debug:

1. Confirm the field separator is `/`, not `-`, `.`, or `,`.
2. Confirm the country value resolves (try the ISO alpha-2 code).
3. For `geoCity`, try the three-field form to disambiguate the city.
4. As a last resort, use `geoLatLng` with explicit coordinates.

## Searching by location in the asset inventory

The asset inventory supports a `geo` keyword (with synonyms `geo_within` and `geo_radius`) that matches assets whose geolocation falls inside a circular area:

```
geo:<lat>,<lon>[,<radius>]
```

* `<lat>` and `<lon>` are decimal degrees (`30.2672,-97.7431`).
* `<radius>` is optional and defaults to **50 km**. Supply a number followed by `km`, `mi`, or `m` (for example `25km`, `15mi`, `5000m`). Plain numbers are treated as kilometres.
* The radius is clamped between 1 metre and 1,000 km.

Examples:

```
geo:30.2672,-97.7431              # within 50 km of downtown Austin
geo:30.2672,-97.7431,25km         # within 25 km
geo:52.5200,13.4050,100mi         # within 100 miles of Berlin
geo_within:51.5074,-0.1278,5km    # synonym
```

Match is true if **any** location source on the asset falls inside the circle. This means a workload with both a cloud region centroid and a public IP egress in the same metro area matches the same `geo:` query.

The same `geo:` keyword is available on the [services inventory](search-query-services.md).

## When locations are refreshed

Asset locations are recalculated on every analysis pass. Each source's previously recorded locations are replaced by the new ones, so stale data — for example a `cloud-region` attribute that an integration stopped reporting — is removed automatically on the next pass.

If you change a `geo*` tag value, the new location will appear on the next analysis pass and not before.
