The problem
You have a UN/LOCODE and want to lookup the information associated with it.
Overview
UN/LOCODE is a system of codes maintained by the United Nations to
uniquely identify locations critical for logistics. The five character codes
provide a simple way for all parties in the supply chain to unambiguously
refer to locations.
Each code splits into two parts: a 2-letter country code,
followed by a 3-letter identifier. For example:
Bremerhaven port in Germany, UN/LOCODE: DEBRV
DE + BRV = DEBRV
for Bremerhaven, Germany.
Converting a UN/LOCODE like
DEBRV
into the corresponding information about that
code is a useful functionality.
You can use the
OpenCage geocoding API
to find the information associated with UN/LOCODEs.
Simply send an API request with the query
q=LOCODE:DEBRV
You can test our geocoding API manually on our demo page.
Background
The United Nations publishes a list of UN/LOCODES twice per year.
The most recent list contains over 115,000 codes, and there is a variety of
information associated with each code.
Please see the excellent
UN/LOCODE Wikipedia page
for a detailed description of the type of data available
For UN/LOCODEs we return the following information in the
annotations
portion of the geocoding API result.
"UN/LOCODE" : {
"code" : "DEBRV",
"date" : "9501",
"function" : {
"meaning" : [
"port",
"rail terminal",
"road terminal",
"airport"
],
"raw" : "1234----"
},
"lat" : 53.5505392,
"lng" : 8.5851945,
"name" : "Bremerhaven",
"name_wo_diacritics" : "Bremerhaven"
},
A couple of these fields are worth explaining:
-
date is in$code YYMM format and reflects when this entry was last reviewed/updated in the official UN/LOCODE dataset9501is January 1995. -
function.rawis an 8-character string from the official UN/LOCODE spec, where each position flags a function of the location (port, rail terminal, road terminal, airport, postal exchange, etc). A digit means the function applies, a dash means it doesn't.function.meaningis the human-readable translation of that raw string, so in most cases you can just usemeaningdirectly and ignoreraw.
Caveats
There are a few points you should note when working with UN/LOCODEs
via the OpenCage geocoding API.
- Please see the official API documentation section dealing with UN/LOCODEs.
- UN/LOCODEs data quality is variable. Even in the best case the codes are associated with only a single coordinate point. Precise geographic boundaries are not provided.
- Searching for specific UN/LOCODEs is available to all API users. We also provide information about the nearest relevant UN/LOCODE as an annotation for all geocoding results to paying customers who request it. So potential customers can evaluate this feature before purchasing we've enabled it for all users for locations in Luxembourg specifically.
- Some codes have no coordinates at all in the official data, so we're unable to resolve a location for them. This affects about 2% of codes. Always check the response before assuming a result was found (see the code example below).
-
A few codes in the official data have obviously wrong coordinates like
0,0and thus we discard them.
Code example
Here's a small example of making a request to the
OpenCage geocoding API in Python to determine information about the code
DEBRV.
from opencage.geocoder import OpenCageGeocode
from pprint import pprint
api_key = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(api_key)
locode = 'DEBRV'
results = geocoder.geocode('LOCODE:' + locode)
# always check we actually got a result back - about 2% of codes
# can't be resolved to a location, per the caveats above
if results:
unlocode = results[0].get('annotations', {}).get('UN/LOCODE')
if unlocode:
pprint(unlocode)
else:
print('no UN/LOCODE annotation on this result')
else:
print('no results found for LOCODE: ' + locode)
# {
# 'code': 'DEBRV',
# 'date': '9501',
# 'function': {
# 'meaning': [
# 'port',
# 'rail terminal',
# 'road terminal',
# 'airport'
# ],
# 'raw': '1234----'
# },
# 'lat': 53.5505392,
# 'lng': 8.5851945,
# 'name': 'Bremerhaven',
# 'name_wo_diacritics': 'Bremerhaven'
# }
# reverse geocoding example
# NOTE: the nearest-UN/LOCODE annotation on ordinary reverse geocoding
# results (rather than looking up a LOCODE directly) is a paid feature
# Contact us if you're interested.
# It is enabled for testing on all locations in Luxembourg, so you can
# try it without a subscription.
results = geocoder.reverse_geocode(-32.0497, 115.7421)
result = results[0]
if (result['annotations']['UN/LOCODE']):
pprint(result['annotations']['UN/LOCODE'])
# {
# 'code': 'AUSFT',
# 'date': '1601',
# 'function': {
# 'meaning': [
# 'road terminal'
# ],
# 'raw': '--3-----'
# },
# 'lat': -32.03,
# 'lng': 115.77,
# 'name': 'East Fremantle',
# 'name_wo_diacritics': 'East Fremantle'
# }
Further reading
Happy geocoding!
2,500 geocoding API requests/day - No credit card required