Bobbie Smulders Freelance Software Developer

Using the TomTom Live Traffic API

Live traffic in TomTom

Update June 2016: TomTom has published official documentation: TomTom Developer Portal

As of late, I’ve been commuting to work on a very congested part of the Dutch highway network. I’ve been using the free online TomTom Live Traffic to see if there are jams on the motorways, major roads or secondary roads. To date, it is by far the best traffic measurement tool I stumbled upon. It updates every two minutes, also works inside cities and has the most accurate information.

I would have loved to use the traffic information for other purposes, like a nice widget or to gather statistical information, but the API appears to be accessible to large corporations only. So it’s time to pull out Firebug!

Using the Firebug extension in Firefox, I managed to track down some information about the API. The Live Traffic website frequently queries a web service, gathers the traffic information in plain readable JSON and updates the traffic icons on the map. The JavaScript source is heavily minimized and obfuscated, but a JavaScript Beautifier can make it a tad more readable. The source shows use that some standard frameworks are used: jQuery, Sizzle JS and OpenLayers.

So what have I figured out so far?

Request URI
The request URI for traffic information is similar to the sample below:

Let’s dig a little deeper:
/lbs/services                            // Location based services
/trafficIcons                            // Traffic icons
/3/s3                                    // Render style, can be s1, s2, s3 or night
/6790043.579195,                         // Bottom-left latitude
511655.515558,                           // Bottom-left longitude
6859219.089793,                          // Top-right latitude
631967.398079                            // Top-right longitude
/11                                      // Amount of zoom
/1424943614435                           // Timestamp of request
/json                                    // Type of output, can be xml, json or jsonp
?key=w7wd5devk7b9ejxfpx5jct48            // API key
&projection=EPSG900913                   // Type of coordinate system, can be EPSG900913 or EPSG4326
&language=en                             // Language of descriptions: nl/Dutch, en/English
&style=s3                                // Style: s1 = unknown, s2 = Routeplanner, s3 = Live Traffic
&expandCluster=true                      // Send clustered points</pre>

JSON response
Using this request the following data is returned:

"stationary traffic","f":"Driebergen J20","t":"A12","l":700,"dl":234},
"ic":6,"ty":3,"cs":0,"d":"stationary traffic","f":
"Croeselaan (Westplein\/U100)","t":"Vondellaan (Croeselaan\/U100)","l":
6809564.5},"ic":6,"ty":3,"cs":0,"d":"stationary traffic","c":
"earlier accident","f":"Veenendaal-West - N233 (A12)","t":
"Maarn - N227 (A12)","l":4400,"dl":1612,"r":"A12\/E35"}]}}

So what does it all mean? After playing around with various samples, I figured out it uses the following JSON scheme:

    "tm": {
        "@id": "",		// Current time as Unix timestamp
        "poi": [		// Single or cluster of incidents
                "id": "",	// Unique jam identifier
                "p": {		// Coordinates of jam
                    "x": 0.0,	// Longitude
                    "y": 0.0	// Latitude
                "ic": 0,	// Type: 1 = unknown, 3 = accident cleared, 6 = traffic jam, 7 = roadwork, 8 = accident, 9 = long-term roadwork, 13 = unknown
                "ty": 0,	// Severity: 0 = no delay, 1 = slow traffic, 2 = queuing traffic, 3 = stationary traffic, 4 = closed
                "cbl": {	// Cluster's bottom-left
                    "x": 0.0,	// Longitude
                    "y": 0	// Latitude
                "ctr": {	// Cluster's top-right
                    "x": 0.0,	// Longitude
                    "y": 0	// Latitude
                "cs": 0,	// Amount of clustered (sub) points
                "cpoi": [ {} ],	// Clustered (sub) jams
                "d": "",	// Description				
                "f": "",	// From: Jam starting point
                "t": "",	// To: Jam ending point
                "r": ""		// Road name
                "l": 0,		// Length of delay in meters
                "dl": 0		// Duration-length of delay in seconds
                "c": ""		// Cause of accident            

The JSON format is actually very easy. You have the “poi” node which contains an array of all the traffic jams. These traffic jam items contain various information bits about the traffic jam, like the length, duration, cause, location, start and end.

But sometimes, several jams are clustered into one icon. This happens when a lot of traffic jams have formed in one area. When this happens, the clustered traffic jams are put in the “cpoi” array and the amount of traffic jams is put in the “cs” field. We also get a “cbl” and a “ctr” field with coordinates, presumably the cluster’s bottom-right and top-left coordinates. The “f”, “t”, “r”, “dl” and “c” fields are all hidden when the poi is a clustered traffic jam, these are only available on a non-clustered traffic jam.

Some pointers: The “cpoi” array is limited to 30 traffic jams, but the “cs” field will always display the actual amount. The expandCluster parameter in the request URI ensures that the cpoi array is filled with data. When the expandCluster parameter is false, the cpoi array will be an empty array.

Building an application

Based on the URI and JSON scheme, I built a small Ext JS based web application to gather the traffic information based on a form containing the user input. Within the application I used the Proj4js library to convert the EPSG:900913 coordinates to WGS84 coordinates.

Screenshot of Tom Tom Live Traffic API Example web application Screenshot of Tom Tom Live Traffic API Example web application

The web application can be downloaded from the associated Github repository. Feel free to mess about with the application, like gathering statistics or creating widgets.

If you have any questions, don’t hesitate to use the comments section.

Disclaimer: This is not an official API, I am not a TomTom representative and I am not responsible for any mess you create. Use the API responsibly.