Introduction
Unwired Labs' Geolocation API locates IoT, M2M and other connected devices from visible cell towers and WiFi networks, without needing GPS.
Authentication
Each request to Unwired's APIs needs to be authenticated with an access token.
We recommend calling these APIs from your server backend rather than from public-facing code such as JavaScript running in a browser or a mobile app, since access tokens used this way are visible to anyone inspecting the request and currently have no referrer or IP restriction to limit their use elsewhere. If you need to call an API directly from a public-facing client, proxy the request through your own backend so the token itself is never exposed. Generate access tokens on your User Dashboard, create a separate token for each application, label them accordingly - e.g. "my server" - and reissue these tokens frequently to prevent misuse.
Endpoints
Unwired Labs' APIs are hosted in two regions, each with its own base URL. Choose the region that's geographically closer to your servers for minimal latency, then send requests to the endpoint for the specific API you're calling - see Available Endpoints below.
Regions
Region 1: United States (Northern Virginia)
https://us1.unwiredlabs.com
Region 2: Europe (Germany)
https://eu1.unwiredlabs.com
Available Endpoints
Replace <region> below with us1 or eu1.
| Method | Path | Used by |
|---|---|---|
| POST | https://<region>.unwiredlabs.com/v2/process |
Geolocation |
| GET | https://<region>.unwiredlabs.com/v2/search |
Forward Geocoding |
| GET | https://<region>.unwiredlabs.com/v2/reverse |
Reverse Geocoding |
| GET | https://<region>.unwiredlabs.com/v2/timezone |
Timezone |
| GET | https://<region>.unwiredlabs.com/v2/balance |
Balance |
Geolocation
The Geolocation API helps developers locate IoT, M2M and other connected devices anywhere in the world without GPS. The device or client first sends the API data about which Cellular networks and WiFi networks it can see nearby. The API then uses Unwired Labs' large datasets of Cell towers, WiFi networks backed by numerous algorithms to calculate and return the device's location.
Getting Started
Integrating the Geolocation API comes down to three steps: send it what the device can see, read the location back, and decide what to do if the result isn't confident enough. Here's a walkthrough using a typical IoT tracker with a 2G (GSM) modem, which can see one serving cell tower and two neighbouring cells.
1. Pick a region and get a token
Sign up for a free token at my.unwiredlabs.com, then pick the region closest to your servers - us1 or eu1.
2. Send what the device can see
POST this request as JSON to https://<region>.unwiredlabs.com/v2/process. You only need to send the cells the device actually reports - a 2G tracker doesn't have WiFi or GPS, so this request only needs token, radio and cells:
{
"token":"your_API_token",
"radio":"gsm",
"cells":[
{"lac":7033,"cid":17811,"mcc":310,"mnc":410,"radio":"gsm"},
{"lac":7033,"cid":17812,"mcc":310,"mnc":410,"radio":"gsm"},
{"lac":7033,"cid":18923,"mcc":310,"mnc":410,"radio":"gsm"}
]
}
The first cell object should be the serving cell (the tower the device is connected to); the rest are neighbours. Always include radio on each cell - it's needed to correctly interpret values like cid and lac, which are read differently depending on radio type. See Cells for the full parameter list, including optional signal and ta values that improve accuracy if your modem exposes them.
If you're not sure where these values come from on your device, most GSM/2G modules expose them directly:
| Field | Typically comes from |
|---|---|
radio |
The network type the modem is registered on (e.g. gsm, umts, lte) - usually available from the modem/OS alongside the network registration info |
mcc / mnc |
The network operator's codes, often decoded from the device's IMSI or reported directly by the modem/OS |
lac |
The Location/Tracking Area Code, available via standard AT commands (e.g. AT+CREG? / AT+CGREG?) or your OS's cell-info API |
cid |
The Cell ID, reported alongside lac from the same source |
3. Read the response
The API returns the location it calculated, along with a few fields that tell you how much to trust it:
{
"status":"ok",
"balance":4999,
"lat":39.56764454,
"lon":-105.00728197,
"accuracy":1200
}
accuracy and fallback together tell you how much to trust a result. A result with fallback present is based on nearby cells or networks rather than the ones reported, so treat it as less precise even if accuracy looks reasonable.
4. Decide what to do with a low-confidence result
If you're seeing fallback often, or accuracy is worse than you need:
- Send more neighbouring cells if your device can see them - more visible cells generally means better accuracy.
- Consider enabling an additional fallback like
lacfif getting some result matters more than precision for your use case. - If nothing is available,
No matches foundis returned rather than a bad location - see Errors.
Usage
curl --request POST \
--url https://us1.unwiredlabs.com/v2/process \
--header 'Content-Type: application/json' \
--data '{"token": "your_API_token","radio": "gsm","mcc": 310,"mnc": 410,"cells": [{"lac": 7033,"cid": 17811}],"wifi": [{"bssid": "00:17:c5:cd:ca:aa","channel": 11,"frequency": 2412}, {"bssid": "d8:97:ba:c2:f0:5a"}],"address": 1}'
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://us1.unwiredlabs.com/v2/process",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/json"
),
CURLOPT_POSTFIELDS => "{\"token\": \"your_API_token\",\"radio\": \"gsm\",\"mcc\": 310,\"mnc\": 410,\"cells\": [{\"lac\": 7033,\"cid\": 17811}],\"wifi\": [{\"bssid\": \"00:17:c5:cd:ca:aa\",\"channel\": 11,\"frequency\": 2412}, {\"bssid\": \"d8:97:ba:c2:f0:5a\"}],\"address\": 1}",
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
import requests
url = "https://us1.unwiredlabs.com/v2/process"
payload = {
"token": "your_API_token",
"radio": "gsm",
"mcc": 310,
"mnc": 410,
"cells": [{"lac": 7033, "cid": 17811}],
"wifi": [
{"bssid": "00:17:c5:cd:ca:aa", "channel": 11, "frequency": 2412},
{"bssid": "d8:97:ba:c2:f0:5a"}
],
"address": 1
}
response = requests.post(url, json=payload)
print(response.text)
var settings = {
"async": true,
"crossDomain": true,
"url": "https://us1.unwiredlabs.com/v2/process",
"method": "POST",
"headers": {
"Content-Type": "application/json"
},
"processData": false,
"data": "{\"token\": \"your_API_token\",\"radio\": \"gsm\",\"mcc\": 310,\"mnc\": 410,\"cells\": [{\"lac\": 7033,\"cid\": 17811}],\"wifi\": [{\"bssid\": \"00:17:c5:cd:ca:aa\",\"channel\": 11,\"frequency\": 2412}, {\"bssid\": \"d8:97:ba:c2:f0:5a\"}],\"address\": 1}"
}
$.ajax(settings).done(function (response) {
console.log(response);
});
POST requests can be sent to the following URL:
https://us1.unwiredlabs.com/v2/process
Replace us1 with a region that's closer to your location.
Sandbox
Use the sandbox to send sample Geolocation requests.
Request
A sample JSON request body
{
"token":"your_API_token",
"radio":"gsm",
"mcc":310,
"mnc":410,
"cells":[
{
"lac":7033,
"cid":17811
}
],
"wifi":[
{
"bssid":"00:17:c5:cd:ca:aa",
"channel":11,
"frequency":2412
},
{
"bssid":"d8:97:ba:c2:f0:5a"
}
],
"address":1
}
Send the following data as a POST request in the JSON format. The token parameter is always mandatory. At least one of cells, wifi, gps or ip (with ipf fallback enabled) must also be provided so the API has data to locate against - see Cells, WiFi, GPS and Fallbacks for the requirements specific to each.
| Parameter | Description | Type | Required |
|---|---|---|---|
| token | Your API token. If you don't have one, get one free here! | string |
yes |
| id | ID of the device, in case you are in a per-device plan. This could be any unique string such as an IMEI, IMSI, phone number or a hash of any of the previous values, etc. Maximum accepted length is 20 chars, and values should only be alphanumeric (a-z, 0-9) | string |
no |
| radio | Radio type of the device. Supported values are gsm, cdma, umts, lte, nbiot and nr. Always include this for accurate results - values like cid and lac are interpreted differently depending on radio type, so an omitted or wrong radio can lead to a misread cell. See Cells for per-cell usage. |
string |
no |
| mcc | Mobile Country Code of your operator's network represented by an integer. Range: 0 to 999. An updated list of MCCs can be found here. | integer |
no |
| mnc | Mobile Network Code of your operator's network represented by an integer. Range: 0 to 999. On CDMA, provide the System ID or SID, with range: 1 to 32767. | integer |
no |
| cells | An array of cell ID objects visible to the device. Read more. | array |
no |
| wifi | An array of WiFi objects visible to the device. Read more. | array |
no |
| ip | IP address of device. Read more | string |
no |
| gps | An array of gps objects that contains GPS information about where the request data was scanned. Read more |
array |
no |
| gps_sandbox | Must be set to 0 to submit data and 1 to test in sandbox. Defaults to 1. | integer |
no |
| geolocation | Must be used along with gps object. When set to 0, response will not include any location information and requests are not charged and do not affect balance. Defaults to 1. |
integer |
no |
| address | The physical address of the returned location. Read more | integer |
no |
| accept-language | Preferred language order for showing address results. Read more | string |
no |
| fallbacks | An array of fallback options to enable or disable. Lets the API return a coarser location instead of failing outright when it can't locate the reported cells or networks directly. Read more | array |
no |
| bt | Controls how strictly locations are validated against geographic boundaries. Read more | integer |
no |
| metadata | Additional information about the request or response, if any, is returned if set to 1. Defaults to 0. Read more | integer |
no |
Cells
Each cells object contains information about a single Cell Tower.
- If you choose to include cells in your request, you can send 1 to 7 cell ID objects. If your device supports scanning for more than 7 cell objects, reach out to us and we'll increase this limit on your account. If more than the allowed limit are sent, only the first 7 cells will be considered.
- The first cell object has to be that of the serving cell, i.e. the tower the device is connected to. The others are neighbouring cell objects that are visible to the device.
cidshould be included on every cell object - without it, that cell is dropped from the request. Always includeradiotoo -cidandlacare interpreted differently per radio type, so an omitted or incorrectradiocan lead to a misread cell, especially for newer radio types like LTE and NR whosecidranges overlap with others. All other parameters mentioned below are optional or recommended, as noted in the tables below.- Parameters vary depending on the radio type. Supported radio types and their corresponding parameters are:
GSM - GSM, EDGE, GPRS, 2G
| Parameter | Description | Type | Accepted | Required |
|---|---|---|---|---|
| lac | the Location Area Code of your operator's network. | integer |
0 - 65533 |
no |
| cid | Cell ID | integer |
0 - 65535 |
yes |
| radio | Radio type of the device | string |
gsm |
recommended |
| mcc | Mobile Country Code of your operator's network. | integer |
0 - 999 |
yes |
| mnc | Mobile Network Code of your operator's network. | integer |
0 - 999 |
yes |
| signal | Signal Strength (RSSI) | integer |
-113 - -51 |
recommended |
| asu | Arbitrary Strength Unit | integer |
0 - 31 |
no |
| ta | Timing Advance | integer |
0 - 63 |
no |
| timestamp | The time this Cell data was scanned, measured in milliseconds since the UNIX epoch | integer |
no |
CDMA - 1xRTT, CDMA, eHRPD, EVDO_0, EVDO_A, EVDO_B, IS95A, IS95B
| Parameter | Description | Type | Accepted | Required |
|---|---|---|---|---|
| lac | Network ID (NID). | integer |
0 - 65534 |
no |
| cid | Base ID / Station ID | integer |
0 - 65535 |
yes |
| radio | Radio type of the device | string |
cdma |
recommended |
| mcc | Mobile Country Code of your operator's network | integer |
0 - 999 |
yes |
| mnc | System ID (SID) | integer |
1 - 32767 |
yes |
| signal | Signal Strength of the radio, measured in dBm | integer |
-100 - -75 |
recommended |
| asu | Arbitrary Strength Unit measured by the mobile phone | integer |
1 - 16 |
no |
| timestamp | The time this Cell data was scanned, measured in milliseconds since the UNIX epoch | integer |
no |
UMTS - UMTS, HSPA, HSDPA, HSPA+, HSUPA, WCDMA, 3G
| Parameter | Description | Type | Accepted | Required |
|---|---|---|---|---|
| lac | Location Area Code of your operator's network. | integer |
0 - 65533 |
no |
| cid | Cell ID | integer |
0 - 268435455 |
yes |
| radio | Radio type of the device | string |
umts |
recommended |
| mcc | Mobile Country Code of your operator's network. | integer |
0 - 999 |
yes |
| mnc | Mobile Network Code of your operator's network. | integer |
0 - 999 |
yes |
| signal | Signal Strength (RSCP) of your operator's network. | integer |
-121 - -25 |
recommended |
| psc | Primary Scrambling Code | integer |
0 - 511 |
recommended |
| asu | Arbitrary Strength Unit measured by the mobile phone | integer |
-5 - 91 |
no |
| timestamp | The time this Cell data was scanned, measured in milliseconds since the UNIX epoch | integer |
no |
LTE - LTE, 4G, CAT-M
| Parameter | Description | Type | Accepted | Required |
|---|---|---|---|---|
| lac | Tracking Area Code of your operator's network. | integer |
0 - 65533 |
no |
| cid | Cell ID | integer |
0 - 268435455 |
yes |
| radio | Radio type of the device | string |
lte |
recommended |
| mcc | Mobile Country Code of your operator's network. | integer |
0 - 999 |
yes |
| mnc | Mobile Network Code of your operator's network. | integer |
0 - 999 |
yes |
| signal | Signal Strength (RSRP) of the radio, measured in dBm | integer |
-137 - -45 |
recommended |
| psc | Physical Cell ID on LTE | integer |
0 - 503 |
recommended |
| asu | Arbitrary Strength Unit measured by the mobile phone | integer |
0 - 97 |
no |
| ta | Timing Advance | integer |
0 - 63 |
no |
| timestamp | The time this Cell data was scanned, measured in milliseconds since the UNIX epoch | integer |
no |
NB-IoT (Private Beta)
| Parameter | Description | Type | Accepted | Required |
|---|---|---|---|---|
| lac | Tracking Area Code of your operator's network. | integer |
0 - 65533 |
no |
| cid | Cell ID | integer |
0 - 268435455 |
yes |
| radio | Radio type of the device | string |
nbiot |
recommended |
| mcc | Mobile Country Code of your operator's network. | integer |
0 - 999 |
yes |
| mnc | Mobile Network Code of your operator's network. | integer |
0 - 999 |
yes |
| signal | Signal Strength (RSRP) of the radio, measured in dBm. Currently not considered at the moment. |
integer |
-137 - -45 |
no |
| psc | Equivalent to PCI in LTE. Some devices may report this as NCID or NB-IoT local Cell ID. |
integer |
0 - 503 |
recommended |
| timestamp | The time this Cell data was scanned, measured in milliseconds since the UNIX epoch | integer |
no |
New Radio - NR, 5G (Public BETA)
| Parameter | Description | Type | Accepted | Required |
|---|---|---|---|---|
| lac | Tracking Area Code or TAC of your operator's network. |
integer |
0 - 16777215 |
no |
| cid | Cell ID | integer |
0 - 68719476735 |
yes |
| radio | Radio type of the device | string |
nr |
recommended |
| mcc | Mobile Country Code of your operator's network. | integer |
0 - 999 |
yes |
| mnc | Mobile Network Code of your operator's network. | integer |
0 - 999 |
yes |
| signal | Signal Strength (RSRP) of the radio, measured in dBm. | integer |
-140 - -44 |
no |
| psc | Physical Cell ID or PCI. |
integer |
0 - 1007 |
recommended |
| asu | Arbitrary Strength Unit measured by the mobile phone | integer |
0 - 97 |
no |
| timestamp | The time this Cell data was scanned, measured in milliseconds since the UNIX epoch | integer |
no |
WiFi
Each wifi object contains information about a single WiFi Access Point.
Note: WiFi positioning is enabled for eligible deployments based on region and intended use.
If you choose to include WiFi in your request, you must send a minimum of 2 and a maximum of 15 WiFi objects in 1 request. If more than 15 WiFi objects are sent, only the first 15 will be considered.
If WiFi is not available, the
wifiobject can be omitted altogether.In accordance with our industry's privacy standards, when WiFi data is included, we require a minimum of 2 valid nearby Access Points to be sent.
| Parameter | Description | Type |
|---|---|---|
| bssid | Basic Service Set Identifier or MAC address of the Access Point. Typical format of a MAC address is xx-xx-xx-xx-xx-xx. However, the delimiter can be any of these when sent to the API: : or - or . |
string |
| channel | Channel the WiFi network is operating in (optional) | integer |
| frequency | Frequency the WiFi network is operating in (MHz) (optional) | integer |
| timestamp | The time this WiFi data was scanned, measured in milliseconds since the UNIX epoch (optional) | integer |
Fallbacks
When the API can't locate the specific cells or networks a device reports, fallbacks let it return a coarser location instead of failing outright - using signals like nearby cells sharing the same LAC/TAC, or the device's IP address. They trade some accuracy for a higher chance of getting a result at all.
| Parameter | Description | Type | Accepted | Default |
|---|---|---|---|---|
| all | Enable or disable all fallbacks. | integer |
0 or 1 |
N/A |
| ipf | Enable IP address fallback. Specify IP address of the device in the "ip" field if it's different from the device making the API call. | integer |
0 or 1 |
0 |
| lacf | Setting this to 1 enables LAC fallback. If we are unable to locate a cell, we will return an approximate location based on nearby cells that share the same LAC / TAC in our database. Setting this to 2 will return only a fallback location even if a more accurate location exists. |
integer |
0 to 2 |
1 |
| scf | Enable Short CID fallback. Adds support for devices that can only see 16-bit (short) CID of an UMTS 28-bit UTRAN CID. |
integer |
0 or 1 |
1 |
There are additional fallbacks and validations available for specific use-cases. Please drop our team a note to explore these.
GPS
Sample request with the
gpsobject
{
"cells": [{"lac": 7033, "cid": 17811, "radio": "gsm", "mcc": 310, "mnc": 410}],
"wifi": [{"bssid": "00:17:c5:cd:ca:aa"}],
"gps": [{
"source": "gps",
"lat": 39.56764858,
"lon": -105.0073312,
"accuracy": 30.0,
"altitude": 100.0,
"altitude_accuracy": 50.0,
"speed": 10.2,
"heading": 35.5,
"timestamp": 1480510819000
}],
"gps_sandbox": 1,
"geolocation": 0
}
Each gps object contains GPS location information about when and where the data in the request body was observed.
You may send multiple
gpsobjects if the device or client has multiple GPS locations.Always include
"geolocation": 0to the request body while contributing to ensure such requests are not charged and do not affect balance.Contact us before you begin sending
gpsdata since this feature has to be enabled manually.
| Parameter | Description | Type | Required |
|---|---|---|---|
| lat | The latitude of the observation (WGS 84) | float |
yes |
| lon | The longitude of the observation (WGS 84) | float |
yes |
| accuracy | The horizontal accuracy of the observed position in meters | float |
no |
| altitude | The altitude at which the data was observed in meters above sea-level | float |
no |
| altitude_accuracy | The accuracy of the altitude estimate in meters | float |
no |
| speed | The measured speed of the device in meters per second | float |
no |
| heading | The direction of travel of the device in degrees (0° - 360°) clockwise relative to true north | float |
no |
| timestamp | The time this GPS position was observed, measured in milliseconds since the UNIX epoch | integer |
no |
Notes
Address
The physical address of the returned location.
Pass a value of 1 (default) to return address, 2 to return address components - street, city, postcode, etc - separately and 0 to suppress it. If we do not have an address for a location, the API will return Not available.
| Type | Accepted | Default |
|---|---|---|
integer |
0 or 1 or 2 |
1 |
Border Threshold
The API validates location results against geographic boundaries. The border threshold parameter allows you to control how strictly this validation is applied:
| Type | Accepted | Default |
|---|---|---|
integer |
0 or 1 or 2 |
1 |
strict - Applies the strictest validation. Uses conservative filtering that may exclude some valid locations near boundaries (typically within a few hundred meters), which can result in more "No matches found" responses in these areas. Value:
0medium - Allows locations within approximately 5 KM buffer zone. Some returned locations may be in water bodies. Value:
1low - Allows locations within approximately 15 KM buffer zone. Some returned locations may be in water bodies. Value:
2
Other Notes
Don't use leading zeroes in any of the numerical values without encapsulating that value in quotes, as it is invalid JSON and the request will be discarded with
INVALID_REQUESTerror.Use double quotes (
") not single quotes (') to encapsulate strings as per JSON standards.The fields
mcc,mncare not mandatory at the top level and will be overridden by values provided in thecellsobjects.If the request contains only a CDMA element and doesn't have an MCC, the field
mcccan be omitted. The fieldradiois mandatory. Set it tocdma.If the device has multiple radios or SIM cards, you can include
radio,mcc,mncin each cell object.
Response
Sample JSON response:
{
"status":"ok",
"balance":0,
"lat":39.56764454,
"lon":-105.00728197,
"accuracy":10,
"address":"High Line Canal Trail, Littleton, Douglas County, Colorado, 80129, United States of America"
}
The response will be a JSON object and may contain the following elements. Every location is calculated from our large, continuously-updated database of cell and WiFi observations - use the accuracy and fallback fields below to gauge confidence in a given result.
| Parameter | Description |
|---|---|
| status | If the request is successful, ok is returned. Otherwise error is returned |
| message | Contains a specific error message when status is error. This field can be used for programmatic error handling. Read more |
| help | When present, may include additional context about errors for informational purposes. This field is provided for human readability and should not be used for programmatic error handling. |
| balance | Approximate remaining balance on the API token. Requests that return error are not charged. Use the balance endpoint for more accurate values. |
| balance_slots | Approximate remaining balance of device slots. Requests that return error are not charged. A value of -1 indicates an error in retrieving the slots balance. Only appears for device plans. |
| lat | The latitude representing the location |
| lon | The longitude representing the location |
| accuracy | The accuracy of the position is returned in meters |
| address | The physical address of the location |
| address_detail | The physical address of the location broken into sub-components. Read more |
| aged | Shown when the location is based on a single measurement or those older than 90 days or is an LAC fallback |
| fallback | Shown when the location is based on a fallback. Possible options include ipf, lacf, scf, cidf, ncf. |
| metadata | An object that contains additional information about the request or response, if any, and is shown when metadata is set to 1 in the request. Read more |
Address Detail
The API only returns components that have valid values for a location. Component town is normalized to city to make things simple. For more granular control, please use our Geocoding service - LocationIQ.
Components that would be returned are:
arealocalitydistrictcountycitystatecountrycountry_codepostal_code
Metadata
Sample response with the
metadataobject
{
"status": "ok",
"balance": 266647,
"lat": 39.56764858,
"lon": -105.00733121,
"accuracy": 120,
"metadata": {
"gps": {
"status": "ok",
"gps_sandbox": 0
}
}
}
When metadata is enabled, the Geolocation API returns additional information about the request or response. For example, when a gps object is sent in the request, the API response will look similar to the one on your right.
Errors
{
"status": "error",
"message": "error_message",
"balance": 0
}
When the API encounters errors, it responds with one of the following exact error messages in the message field:
Token balance over; you have used up all your requests for todayInvalid tokenNo slots availableInactive deviceWiFi access not enabledInvalid requestNo matches foundInternal server errorRate Limited Second
Error Details
| Error | Description |
|---|---|
Token balance over; you have used up all your requests for today |
Daily request limit has been exceeded. Balance is reset at midnight UTC everyday (00:00 UTC), unless you are on a custom plan with a different reset schedule. You can also upgrade your plan for more requests. |
Invalid token |
The API token is invalid or missing. Sign up at my.unwiredlabs.com to get a token. |
No slots available |
Device slot limit has been reached on your account. |
Inactive device |
This device has been marked as inactive on your device plan. Contact support to activate it. |
WiFi access not enabled |
WiFi positioning is not enabled for this account. Contact support for details. |
Invalid request |
The request is malformed or contains invalid data. Check the help field for specific details. Common causes include malformed JSON, invalid data types, or invalid parameter values. |
No matches found |
Unable to determine a location based on the provided data. This can occur when the cells, WiFi access points, or IP address sent in the request are not found in our database, or when location results failed validation checks (such as border threshold filtering). |
Internal server error |
An internal server error occurred. This is a temporary issue on our side, please retry the request. |
Rate Limited Second |
You have exceeded the per-second request limit allocated to your token. Reduce your request rate and retry. |
Best Practices
- Send every visible cell or WiFi network, not just the strongest one. More visible networks generally means better accuracy, up to the limits of 7 cells and 15 WiFi objects per request.
- Handle rate limits and server errors differently. Back off and retry on
Rate Limited Second. Don't retryToken balance over...until your balance resets - retrying won't help.Internal server erroris safe to retry, ideally with a short delay. - Turn on fallbacks deliberately, not by default. Fallbacks trade accuracy for a higher chance of getting a result - see Fallbacks for what each option does before enabling it for your use case.
- Keep tokens server-side. See Authentication for guidance on handling tokens in public-facing apps.
Geocoding
Forward Geocoding
Forward Geocoding is when you need to convert addresses (like a street address) into geographic coordinates (like latitude and longitude). You can then use these coordinates to do a number of things such as place markers on a map, calculate the distance between your office and those coordinates, send a drone over to that location, and so on.
Usage
<?php
$curl = curl_init('https://us1.unwiredlabs.com/v2/search?token=YOUR_API_TOKEN&q=SEARCH_STRING');
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_CUSTOMREQUEST => 'GET',
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo 'cURL Error #:' . $err;
} else {
echo $response;
}
import requests
url = "https://us1.unwiredlabs.com/v2/search"
data = {
'token': 'YOUR_API_TOKEN',
'q': 'SEARCH_STRING'
}
response = requests.get(url, params=data)
print(response.text)
curl --request GET \
--url 'https://us1.unwiredlabs.com/v2/search?token=YOUR_API_TOKEN&q=SEARCH_STRING'
var settings = {
"async": true,
"crossDomain": true,
"url": "https://us1.unwiredlabs.com/v2/search?token=YOUR_API_TOKEN&q=SEARCH_STRING",
"method": "GET"
}
$.ajax(settings).done(function (response) {
console.log(response);
});
GET requests can be sent to the following URL:
https://us1.unwiredlabs.com/v2/search?token=YOUR_API_TOKEN&q=SEARCH_STRING
Replace us1 with a region that's closer to your location.
Query Parameters
| Name | Description | Required |
|---|---|---|
| token | Authentication Token | Yes |
| q | Address which we want to search for | Yes |
| accept-language | Preferred language order for showing search results. Read more. | Optional |
| limit | Integer value to limit the number of returned results | Optional |
| countrycodes | Limit search to a list of countries. Read more. | Optional |
| viewbox | The preferred area to find search results. (left, right, top, bottom) | Optional |
Response
The above command returns JSON structured like this:
{
"status": "ok",
"balance": 5000,
"address": [{
"lat": "40.6892474",
"lon": "-74.0445404280149",
"display_name": "Statue of Liberty, Hudson River Waterfront Walkway, Jersey City, Hudson County, New Jersey, 10004, United States of America",
"road": "Hudson River Waterfront Walkway",
"county" : "Hudson County",
"city": "Jersey City",
"state": "New Jersey",
"country": "United States of America",
"country_code": "US",
"postal_code": 10004
}, {
"lat": "41.3438648",
"lon": "-86.3111653",
"display_name": "Statue of Liberty, Rue Guynemer, Odéon, 6e, Paris, Île-de-France, 75006, France",
"road": "Rue Guynemer",
"city": "Île-de-France",
"state": "Paris",
"country":"France",
"country_code" : "FR",
"postal_code": 75006
}]
}
| Name | Description |
|---|---|
| status | ok on success; error on error |
| balance | Balance left in the account |
| address | Array of Address objects found for the search query. Read more |
Reverse Geocoding
Reverse geocoding is the process of converting geographic coordinates into a human-readable address.
Usage
<?php
$curl = curl_init('https://us1.unwiredlabs.com/v2/reverse?token=YOUR_API_TOKEN&lat=LATITUDE&lon=LONGITUDE');
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_CUSTOMREQUEST => 'GET',
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
import requests
url = "https://us1.unwiredlabs.com/v2/reverse"
data = {
'token': 'YOUR_API_TOKEN',
'lat': 'LATITUDE',
'lon': 'LONGITUDE'
}
response = requests.get(url, params=data)
print(response.text)
curl --request GET \
--url 'https://us1.unwiredlabs.com/v2/reverse?token=YOUR_API_TOKEN&lat=LATITUDE&lon=LONGITUDE'
var settings = {
"async": true,
"crossDomain": true,
"url": "https://us1.unwiredlabs.com/v2/reverse?token=YOUR_API_TOKEN&lat=LATITUDE&lon=LONGITUDE",
"method": "GET"
}
$.ajax(settings).done(function (response) {
console.log(response);
});
GET requests can be sent to the following URL:
https://us1.unwiredlabs.com/v2/reverse?token=YOUR_API_TOKEN&lat=LATITUDE&lon=LONGITUDE
Replace us1 with a region that's closer to your location.
Query Parameters
| Name | Description | Required |
|---|---|---|
| token | Authentication token | Yes |
| lat | Latitude of the location address | Yes |
| lon | Longitude of the location address | Yes |
| zoom | Zoom value lies between 0-18. Level of detail required where 0 is country and 18 is house/building |
Optional |
| accept-language | Preferred language order for showing search results. Read more. | Optional |
Response
The above command returns JSON structured like this:
{
"status": "ok",
"balance": 5000,
"address": {
"lat": "41.3438648",
"lon": "-86.3111653",
"display_name": "Southpark Lane, Littleton, Arapahoe County, Colorado, 80120, United States of America",
"road": "Southpark Lane",
"county": "Arapahoe County",
"city": "Denver-Aurora-Lakewood",
"state": "Colorado",
"country": "United States of America",
"country_code" : "US",
"postal_code": 80120
}
}
| Name | Description |
|---|---|
| status | ok on success; error on error |
| balance | Balance left in the account |
| address | Address object found for the search query. Read more. |
Notes
Address Object
| Name | Description |
|---|---|
| lat | Latitude of the given location (decimal) |
| lon | Longitude of the given location (decimal) |
| display_name | Matched Address name for the given location |
| house_number | House Number |
| road | Road Name |
| neighbourhood | Neighbourhood |
| suburb | Suburb |
| city | City name (normalized form of city, town, village, hamlet) |
| county | County name (normalized form of county, state_district) |
| country | Country name |
| country_code | Country code |
| postcode | Postal code |
Accept Language
Preferred language order for showing search results, overrides the value specified in the Accept-Language HTTP header. Either uses standard rfc2616 accept-language string or a simple comma separated list of language codes.
- List of
Accept-Languagecodes: List of ISO 639-1 codes - Use
ISO 639-1Code (2 characters). If the language is not available, useISO 639-2Code (3 characters) from here - Default:
en
Country Codes
Limit search results to a specific country (or a list of countries). Should be the ISO 3166-1 alpha-2 code. Here is a sample:
| Country code | Country |
|---|---|
de |
Germany |
gb |
United Kingdom |
us |
United States of America |
- List of accepted country codes: Officially assigned code elements
Errors
{
"status": "error",
"message": "Error message"
}
When certain types of errors are encountered, the API responds with one of the following error messages:
| Error Message | Description |
|---|---|
INVALID_TOKEN |
The user's token set is not valid or missing |
INACTIVE_TOKEN |
The user's token is not active |
INVALID_REQUEST |
The request does not contain the required input in the specified format |
RATELIMITED_DAY |
The user has reached the daily limit allocated |
RATELIMITED_MINUTE |
The user has reached the per-minute limit allocated |
RATELIMITED_SECOND |
The user has reached the per-second limit allocated |
NO_MATCHES |
The request is valid and we could not find a proper result |
UNKNOWN_ERROR |
Due to a server error, we are unable to serve your request. You can retry this request. |
Timezone
The Unwired Labs TimeZone API provides time offset data for locations on the surface of the earth.
Usage
GET requests can be sent to the following URL:
https://us1.unwiredlabs.com/v2/timezone?token=YOUR_API_TOKEN&lat=LATITUDE&lon=LONGITUDE
Replace us1 with a region that's closer to your location.
Query Parameters
<?php
$curl = curl_init('https://us1.unwiredlabs.com/v2/timezone?token=YOUR_API_TOKEN&lat=LATITUDE&lon=LONGITUDE');
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_CUSTOMREQUEST => 'GET',
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo 'cURL Error #:' . $err;
} else {
echo $response;
}
import requests
url = "https://us1.unwiredlabs.com/v2/timezone"
data = {
'token': 'YOUR_API_TOKEN',
'lat': 'LATITUDE',
'lon': 'LONGITUDE'
}
response = requests.get(url, params=data)
print(response.text)
curl --request GET \
--url 'https://us1.unwiredlabs.com/v2/timezone?token=YOUR_API_TOKEN&lat=LATITUDE&lon=LONGITUDE'
var settings = {
"async": true,
"crossDomain": true,
"url": "https://us1.unwiredlabs.com/v2/timezone?token=YOUR_API_TOKEN&lat=LATITUDE&lon=LONGITUDE",
"method": "GET"
}
$.ajax(settings).done(function (response) {
console.log(response);
});
| Name | Description | Required |
|---|---|---|
| token | Authentication token | Yes |
| lat | Latitude of the location | Yes |
| lon | Longitude of the location | Yes |
Response
The above command returns JSON structured like this:
{
"status": "ok",
"balance": 5000,
"timezone": {
"name": "Asia/Kolkata",
"now_in_dst": 0,
"offset_sec": 19800,
"short_name": "IST"
}
}
| Name | Description |
|---|---|
| status | ok on success; error on error |
| balance | Balance left in the account |
| timezone | Timezone object found for the location. Read more |
Timezone Response
| Name | Description |
|---|---|
| short_name | Short name of the Timezone |
| offset_sec | The offset from UTC (in seconds) for the given location. Considers DST savings. |
| now_in_dst | Represents whether the zone currently observing DST or not |
| name | Timezone name of the Location |
Errors
{
"status": "error",
"message": "Error message"
}
When certain types of errors are encountered, the API responds with the following error messages:
| Error Message | HTTP Status | Description |
|---|---|---|
INVALID_TOKEN |
200 | The user's token set is not valid |
INACTIVE_TOKEN |
200 | The user's token is not active |
INVALID_INPUT |
400 | The request does not contain the required input in the specified format |
NO_RESULTS |
200 | The request is valid and we could not find a timezone for the given coordinates |
DAILY_LIMIT |
429 | The daily quota for timezone lookups has been reached |
UNKNOWN_ERROR |
500 or 503 | Due to a server error, we are unable to serve your request. You can retry this request. |
Maps
LocationIQ Maps - an offering from Unwired Labs - offers beautiful and customizable map tiles to visualize location data on your websites and apps.
Static Maps
LocationIQ Static maps - an offering from Unwired Labs - are standalone images (in JPG or PNG format) that can be displayed on web and mobile devices without the aid of a mapping library or API. Our Static Maps API returns an image in response to an HTTP request. For each request, you can specify the map's location, size of the image, zoom level, type of map. You can also place markers or draw paths at locations on the map.
Balance
The Balance API provides a count of request credits left in the user's account for the day. Balance is reset at midnight UTC everyday (00:00 UTC).
For device accounts, this endpoint also returns the number of available device slots.
Usage
GET requests can be sent to the following URL. To prevent abuse, this endpoint is rate limited at 1 request per second.
https://us1.unwiredlabs.com/v2/balance?token=YOUR_API_TOKEN
Replace us1 with a region that's closer to your location.
<?php
$curl = curl_init('https://us1.unwiredlabs.com/v2/balance?token=YOUR_API_TOKEN');
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_CUSTOMREQUEST => 'GET',
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo 'cURL Error #:' . $err;
} else {
echo $response;
}
import requests
url = "https://us1.unwiredlabs.com/v2/balance"
data = {
'token': 'YOUR_API_TOKEN',
}
response = requests.get(url, params=data)
print(response.text)
curl --request GET \
--url 'https://us1.unwiredlabs.com/v2/balance?token=YOUR_API_TOKEN'
var settings = {
"async": true,
"crossDomain": true,
"url": "https://us1.unwiredlabs.com/v2/balance?token=YOUR_API_TOKEN",
"method": "GET"
}
$.ajax(settings).done(function (response) {
console.log(response);
});
Query Parameters
| Name | Description | Required |
|---|---|---|
| token | Authentication Token | Yes |
Response
The above command returns JSON structured like this:
{
"status": "ok",
"balance_geolocation": 4500,
"balance_geocoding": 4500,
"balance_slots": -1
}
| Name | Description |
|---|---|
| status | ok on success; error on error |
| balance_geolocation | Remaining balance left in the account for geolocation requests |
| balance_geocoding | Remaining balance left in the account for geocoding requests |
| balance_slots | Remaining device slots available. Returns -1 if no slots are allocated. This field is only present for device accounts. |
Errors
{
"status": "error",
"message": "Error message"
}
When certain types of errors are encountered, our API responds with the following error messages:
| Error Message | Description |
|---|---|
INVALID_TOKEN |
The user's token set is not valid |
INACTIVE_TOKEN |
The user's token is not active |
UNKNOWN_ERROR |
Due to an unknown error, we are unable to serve your request |
RATELIMITED_SECOND |
The user has exceeded the 1 request per-second limit for this endpoint |