## Geolocation requests

Geolocation requests are sent using POST to the following URL:

```
https://www.googleapis.com/geolocation/v1/geolocate?key=YOUR_API_KEY
```

You must specify a key in your request, included as the value of a
`key` parameter. A `key` is your application's
API key. This key identifies your application for purposes of quota
management. Learn how to [get a key](https://developers.google.com/maps/documentation/geolocation/get-api-key.md.txt).

### Request body

The request body must be formatted as JSON. If the request body is not included, the results
are returned based on the IP address of request location. The following fields are
supported, and all fields are optional, unless otherwise stated:

| Field | JSON type | Description | Notes |
|---|---|---|---|
| `homeMobileCountryCode` | `number` (`uint32`) | The mobile country code (MCC) for the device's *home* network. | *Supported* for `radioType` `gsm` (default), `wcdma`, `lte` and `nr`; not used for `cdma`. Valid range: 0--999. |
| `homeMobileNetworkCode` | `number` (`uint32`) | The Mobile Network Code for the device's *home* network. This is the MNC for GSM, WCDMA, LTE and NR. CDMA uses the System ID (SID) | Valid range for MNC: 0--999. Valid range for SID: 0--32767. |
| `radioType` | `string` | The mobile radio type. Supported values are `gsm`, `cdma`, `wcdma`, `lte` and `nr`. | While this field is optional, it *should* always be included if the radio type is known by the client. If the field is omitted, Geolocation API defaults to `gsm`, which *will* result in invalid or zero results if the assumed radio type is incorrect. |
| `carrier` | `string` | The carrier name. |   |
| `considerIp` | `boolean` | Specifies whether to fall back to IP geolocation if WiFi and cell tower signals are missing, empty, or not sufficient to estimate device location. | Defaults to `true`. Set `considerIp` to `false` to prevent fall back. |
| `cellTowers` | `array` | An array of cell tower objects. | See the [Cell Tower Objects](https://developers.google.com/maps/documentation/geolocation/requests-geolocation.md.txt#cell_tower_object) section below. |
| `wifiAccessPoints` | `array` | An array of WiFi access point objects. | See the [WiFi Access Point Objects](https://developers.google.com/maps/documentation/geolocation/requests-geolocation.md.txt#wifi_access_point_object) section below. |

An example Geolocation API request body is shown below.

```json
{
  "homeMobileCountryCode": 310,
  "homeMobileNetworkCode": 410,
  "radioType": "lte",
  "carrier": "Vodafone",
  "considerIp": true,
  "cellTowers": [
    // See the Cell Tower Objects section below.
  ],
  "wifiAccessPoints": [
    // See the WiFi Access Point Objects section below.
  ]
}
```

### Cell tower objects

The request body's `cellTowers` array contains zero or more
cell tower objects.

| Field | JSON type | Description | Notes |
|---|---|---|---|
| `cellId` | `number` (`uint32`) | Unique identifier of the cell. | *Required* for `radioType` `gsm` (default), `cdma`, `wcdma` and `lte`; *rejected* for `nr`. See the [Calculating cellId](https://developers.google.com/maps/documentation/geolocation/requests-geolocation.md.txt#calculating_cell_id) section below, which also lists the valid value ranges for each radio type. |
| `newRadioCellId` | `number` (`uint64`) | Unique identifier of the NR (5G) cell. | *Required* for `radioType` `nr`; *rejected* for other types. See the [Calculating newRadioCellId](https://developers.google.com/maps/documentation/geolocation/requests-geolocation.md.txt#calculating_new_radio_cell_id) section below, which also lists the valid value range for the field. |
| `locationAreaCode` | `number` (`uint32`) | The Location Area Code (LAC) for GSM and WCDMA networks. The Network ID (NID) for CDMA networks. The Tracking Area Code (TAC) for LTE and NR networks. | *Required* for `radioType` `gsm` (default) and `cdma`, optional for other values. Valid range with `gsm`, `cdma`, `wcdma` and `lte`: 0--65535. Valid range with `nr`: 0--16777215. |
| `mobileCountryCode` | `number` (`uint32`) | The cell tower's Mobile Country Code (MCC). | *Required* for `radioType` `gsm` (default), `wcdma`, `lte` and `nr`; not used for `cdma`. Valid range: 0--999. |
| `mobileNetworkCode` | `number` (`uint32`) | The cell tower's Mobile Network Code. This is the MNC for GSM, WCDMA, LTE and NR. CDMA uses the System ID (SID). | *Required.* Valid range for MNC: 0--999. Valid range for SID: 0--32767. |

The following optional fields are not used, but may be included if values are
available.

| Field | JSON type | Description | Notes |
|---|---|---|---|
| `age` | `number` (`uint32`) | The number of milliseconds since this cell was primary. | If age is 0, the `cellId` or `newRadioCellId` represents a current measurement. |
| `signalStrength` | `number` (`double`) | Radio signal strength measured in dBm. |   |
| `timingAdvance` | `number` (`double`) | The [timing advance](https://en.wikipedia.org/wiki/Timing_advance) value. |   |

#### Calculating `cellId`

Radio types prior to NR (5G) use the 32-bit `cellId` field for passing the network
cell ID to Geolocation API.

- GSM (2G) networks use the 16-bit Cell ID (CID) as is. Valid range: 0--65535.
- CDMA (2G) networks use the 16-bit Base Station ID (BID) as is. Valid range: 0--65535.
- WCDMA (3G) networks use the UTRAN/GERAN Cell Identity (UC-ID), which is a 28-bit integer value concatenating the 12-bit Radio Network Controller Identifier (RNC-ID) and 16-bit Cell ID (CID).  
  Formula: `rnc_id << 16 | cid`.  
  Valid range: 0--268435455.  
  **Note:** Specifying only the 16-bit Cell ID value in WCDMA networks results in incorrect or zero results.
- LTE (4G) networks use the E-UTRAN Cell Identity (ECI), which is a 28-bit integer value concatenating the 20-bit E-UTRAN Node B Identifier (eNBId) and the 8-bit Cell ID (CID).  
  Formula: `enb_id << 8 | cid`.  
  Valid range: 0--268435455.  
  **Note:** Specifying only the 8-bit Cell ID value in LTE networks results in incorrect or zero results.


Placing values outside these ranges in the API request may result in undefined behavior. The API,
at Google's discretion, may truncate the number so it fits in the documented range, infer a
correction to the `radioType`, or return a `NOT_FOUND` result without any
indicator in the response.

An example LTE cell tower object, which is part of the
[request body](https://developers.google.com/maps/documentation/geolocation/requests-geolocation.md.txt#body), is below.

```json
{
  ...

  "cellTowers": [
    {
      "cellId": 170402199,
      "locationAreaCode": 35632,
      "mobileCountryCode": 310,
      "mobileNetworkCode": 410,
      "age": 0,
      "signalStrength": -60,
      "timingAdvance": 15
    }
  ]
}
```

The response for the preceding request looks like this:

```json
{
  "location": {
    "lat": 37.7801129,
    "lng": -122.4168229
  },
  "accuracy": 180.052
}
```

#### Calculating
`newRadioCellId`

Newer networks, whose cell IDs are longer than 32 bits use the 64-bit
`newRadioCellId` field for passing the network cell ID to
Geolocation API.

- NR (5G) networks use the 36-bit New Radio Cell Identity (NCI) as is.  
  Valid range: 0--68719476735.

An example NR cell tower object, which is part of the [request body](https://developers.google.com/maps/documentation/geolocation/requests-geolocation.md.txt#body), is below.

```json
{
  ...

  "cellTowers": [
    {
      "newRadioCellId": 68719476735,
      "mobileCountryCode": 310,
      "mobileNetworkCode": 410,
      "age": 0,
      "signalStrength": -60,
    }
  ]
}
```

The response to the preceding request looks like this:

```json
{
  "location": {
    "lat": 37.7646157,
    "lng": -122.4127361
  },
  "accuracy": 1458.5570522410717
}
```

### WiFi access point objects

The request body's `wifiAccessPoints` array must contain two
or more WiFi access point objects representing *physically distinct*
stationary access point devices. The `macAddress` field is
required. All other fields are optional. The service ignores access points
that move, such as those in airplanes and trains.

| Field | JSON type | Description | Notes |
|---|---|---|---|
| `macAddress` | `string` | The MAC address of the WiFi node. It's typically called a BSS, BSSID or MAC address. | *Required.* Colon-separated (`:`) hexadecimal string. <br /> Only [universally-administered MAC addresses](https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local_(U/L_bit)) can be located using the API. Other MAC addresses are silently dropped and may lead to an API request becoming effectively empty. For details, see [Dropping useless Wifi access points](https://developers.google.com/maps/documentation/geolocation/requests-geolocation.md.txt#filter_mac). |
| `signalStrength` | `number` (`double`) | The current signal strength measured in dBm. | For WiFi access points, dBm values are typically -35 or lower and range from -128 to -10 dBm. Be sure to include the minus sign. For values greater than -10 dBm, the API returns `NOT FOUND`. |
| `age` | `number` (`uint32`) | The number of milliseconds since this access point was detected. |   |
| `channel` | `number` (`uint32`) | The channel over which the client is communicating with the access point. |   |
| `signalToNoiseRatio` | `number` (`double`) | The current signal to noise ratio measured in dB. |   |

An example WiFi access point object, which is part of the
[request body](https://developers.google.com/maps/documentation/geolocation/requests-geolocation.md.txt#body), is
shown below.

```json
{
  ...
  
  "macAddress": "f0:d5:bf:fd:12:ae",
  "signalStrength": -43,
  "signalToNoiseRatio": 0,
  "channel": 11,
  "age": 0
}
```

The response for the preceding request looks like this:

```json
{
  "location": {
    "lat": 37.7801129,
    "lng": -122.4168229
  },
  "accuracy": 180.052
}
```

## Sample requests

> [!NOTE]
> **Note:** MAC addresses can change over time. For that reason, the examples on this page may result in an error message from the API.

If you'd like to try the Geolocation API with sample
data, save the following JSON to a file:

```json
{
  "considerIp": "false",
  "wifiAccessPoints": [
    {
      "macAddress": "3c:37:86:5d:75:d4",
      "signalStrength": -35,
      "signalToNoiseRatio": 0
    },
    {
      "macAddress": "30:86:2d:c4:29:d0",
      "signalStrength": -35,
      "signalToNoiseRatio": 0
    }
  ]
}
```

You can then use [`curl`](http://curl.haxx.se/)
to make your request from the command line:

```
$ curl -d @your_filename.json -H "Content-Type: application/json" -i "https://www.googleapis.com/geolocation/v1/geolocate?key=YOUR_API_KEY"
```

The response for the preceding MAC addresses looks like this:

```json
{
  "location": {
    "lat": 37.4241173,
    "lng": -122.0915717
  },
  "accuracy": 20
}
```

### Dropping unused WiFi access points

Removing WiFi access point objects with `macAddress`es that are
either a broadcast address (`FF:FF:FF:FF:FF:FF`) or reserved by the
IANA can improve the success rate of Geolocation API calls that use WiFi as
input. If, after filtering, it can be determined that a Geolocation API call
wouldn't succeed, mitigations such as using older location signals or WiFi APs
with weaker signals can be used. This approach is a tradeoff between your
application's need for a location estimate and its precision and recall
requirements. The following filtering techniques demonstrate how to filter
the inputs, but don't show the mitigations that you may, as the application
engineer, choose to apply.

The range of MAC addresses between `00:00:5E:00:00:00` and
`00:00:5E:FF:FF:FF` are
[reserved
for IANA](https://datatracker.ietf.org/doc/html/rfc5342#section-2.1.1) and often used for network management and multicast functions,
precluding their use as a location signal. You should also remove these MAC
addresses from inputs to the API.

For example, usable MAC addresses for Geolocation can be gathered from an
array of `macAddress` strings named `macs`:
Java

```java
String[] macs = {"ff:ff:ff:ff:ff:ff", "1c:34:56:78:9a:bc", "00:00:5e:00:00:01"};
ArrayList<String> _macs = new ArrayList<>(Arrays.asList(macs));
_macs.removeIf(m -> !(!m.toUpperCase().equals("FF:FF:FF:FF:FF:FF")
                      && !m.substring(0, 8).toUpperCase().equals("00:00:5E")));
    
```
Python

```python
macs = ['ff:ff:ff:ff:ff:ff', '1c:34:56:78:9a:bc', '00:00:5e:00:00:01']
macs = [m for m in macs if (m.upper() != "FF:FF:FF:FF:FF:FF" and m[:8].upper() != '00:00:5E')]
    
```
JavaScript

```javascript
macs = ['ff:ff:ff:ff:ff:ff', '1c:34:56:78:9a:bc', '00:00:5e:00:00:01'];
macs = macs.filter(m => m.toUpperCase() !== "FF:FF:FF:FF:FF:FF"
                        && m.substr(0, 8).toUpperCase() !== '00:00:5E');
    
```

Using this filter results in only `1c:34:56:78:9a:bc`
remaining in the list. Because this list has
[fewer than 2 WiFi MAC addresses](https://developers.google.com/maps/documentation/geolocation/requests-geolocation.md.txt#wifi_access_point_object), the
request wouldn't be successful and an HTTP 404
[(`notFound`)
response](https://developers.google.com/maps/documentation/geolocation/requests-geolocation-errors#error_descriptions) would be returned.

## Geolocation responses

A successful geolocation request returns a JSON-formatted response
defining a location and radius.

- `location`: The user's estimated latitude and longitude coordinates, in degrees. Contains one `lat` and one `lng` subfield.
- `accuracy`: The accuracy of the estimated location, in meters. This represents the radius of a circle around the given `location`.

```json
{
  "location": {
    "lat": 37.421875199999995,
    "lng": -122.0851173
  },
  "accuracy": 120
}
```

The API returns a location and accuracy radius based on the input signals.
While the API can return a highly accurate location, accuracy may vary
depending on the source, number, density, and strength of available signals. You can typically expect the following accuracy radii:

- **WiFi access points** : If the request includes two or more `wifiAccessPoints`, the returned accuracy radius is typically around 20 meters. Accuracy improves with the number of access points and stronger signals (measured in dBm), with signal strengths typically ranging from -100 to -20 dBm.
- **Cell towers** : If WiFi information is unavailable or insufficient, the API uses `cellTowers` for location. Accuracy varies significantly with cell tower type, signal strength, and network density:
  - **Macro cells** (the most common type, used for wide area coverage) provide lower accuracy. The radius is typically in the range of hundreds of meters, and can be up to several thousand meters in areas with sparse cell tower coverage. *For macro cells, it is uncommon to
    achieve an accuracy radius below 100 meters.* Accuracy is generally higher for cell towers with strong signals. Strong signals are typically \> -110 dBm for LTE (signal range -140 to -55 dBm), \> -100 dBm for WCDMA (signal range -111 to -53 dBm), \> -100 dBm for CDMA (signal range -120 to -40 dBm), and \> -80 dBm for GSM (signal range -121 to -1 dBm).
  - **Small cells** (e.g., femtocells, picocells, or indoor repeaters) provide the most precise cell-based location, with accuracy radii that can be in the 10-30 meter range.
- **IP Geolocation** : If `considerIp` is `true` and no WiFi or cell tower signals can be geolocated, the API estimates location based on the request's IP address. This method provides the lowest accuracy, with radii that can be thousands of meters. See [Why is the accuracy radius very large?](https://developers.google.com/maps/documentation/geolocation/requests-geolocation-errors.md.txt#why_is_the_accuracy_radius_very_large) in the Troubleshoot guide.