Get the information for a UN/LOCODE

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: DE + BRV = DEBRV for Bremerhaven, Germany.

Bremerhaven port, UN/LOCODE: DEBRV
Bremerhaven port in Germany, UN/LOCODE: DEBRV

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 dataset 9501 is January 1995.
  • function.raw is 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.meaning is the human-readable translation of that raw string, so in most cases you can just use meaning directly and ignore raw.

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,0 and 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!

Start your free trial

2,500 geocoding API requests/day - No credit card required