Archived: Unified API: The Tram Network

Following the addition of the Capital’s tram network to the Tube map for the first time earlier this month, we’ve made some improvements to the trams data in our API. The representation of the Tram network has been merged from four individual lines down to a single line. This makes Trams easier to interpret for customers, and consistent with other rail modes like London Overground.

Screenshot 2016-06-06 15.18.57.png
Use the tram? Add it to your favourites!

In the previous design, Trams had its own disruption map and service board. Now, Tram disruptions will be highlighted and shown as part of the rail network bringing all of the rail modes together. This slightly changes the way the tram mode is represented in the Unified API.

This blog entry focuses on the tram mode, its single line, and all of the ways it is exposed through the API. We’ll shed some light on one of the less well-known parts of the TfL network, and show how easily it can be incorporated into any multi-modal transport application.

One line

The single line identifier for the merged tram line is “tram” and it has a mode of “tram”. That makes getting the status and disruptions very simple*.

 "id": "tram",
 "name": "Tram",
 "modeName": "tram",
 "disruptions": [],
 "created": "2016-06-03T12:36:55.397Z",
 "modified": "2016-06-03T12:36:55.397Z",
 "lineStatuses": [
   "statusSeverity": 10,
   "statusSeverityDescription": "Good Service",
   "validityPeriods": []

You can also use the “tram” line id to retrieve information about the tram routes, their timetables and to plan journeys. In these examples, we are using the StopPoint id for West Croydon, which we can find with a search.

Screenshot 2016-06-06 16.51.59.png
Planning a journey from West Croydon to Elmers End.

Tram results are automatically included in Journey Planner results, if the route makes sense. If needed, you can force Journey Planner to only use trams with the mode parameter:,walking

 "journeys": [
 "startDateTime": "2016-06-06T17:29:00",
 "duration": 40,
 "arrivalDateTime": "2016-06-06T18:09:00",
 "legs": [
 "duration": 7,
 "instruction": {
 "summary": "Walk to Wellesley Road Tram Stop",
 "detailed": "Walk to Wellesley Road Tram Stop",
 "steps": [
 "description": "George Street for 134 metres",
 "turnDirection": "STRAIGHT",
 "streetName": "George Street",
 "distance": 134,
 "cumulativeDistance": 134,
 "skyDirection": 435,
 "skyDirectionDescription": "North",
 "cumulativeTravelTime": 118,
 "latitude": 51.37391747675,
 "longitude": -0.09850458644,

Nothing but green lights

Arrivals work the same way as they did previously, and in line with the other modes. You can get all the tram arrivals in a single API call, or for a single station as shown below. Using the StopPoint id for West Croydon, 940GZZCRWCR, the arrivals board looks like this:

Screenshot 2016-06-07 11.38.57.png
The West Croydon tram stop departure board.


Using the same StopPoint id on the Arrivals API, we can retrieve the data for the departure board.

 "id": "1158109161",
 "operationType": 1,
 "vehicleId": "2531",
 "naptanId": "940GZZCRWCR",
 "stationName": "West Croydon",
 "lineId": "tram",
 "lineName": "Tram",
 "platformName": "Eastbound Platform",
 "direction": "inbound",
 "bearing": "",
 "destinationNaptanId": "940GZZCRELM",
 "destinationName": "Elmers End",
 "timestamp": "2016-04-18T16:03:27.728Z",
 "timeToStation": 0,
 "towards": "Elmers End",
 "expectedArrival": "2016-04-18T16:03:00.657Z",
 "timeToLive": "2016-04-18T16:03:00.657Z",
 "modeName": "tram"

Using our SignalR endpoint, you can subscribe to push notifications of tram arrivals. On the client, you just need to include the hubs JavaScript, and this will give you a connection object, which allows you to subscribe to a prediction “room” for a line or stop. The callback provided to showPredictions will be called whenever a new prediction is made available. In the code snippet below, we initialise the connection and subscribe to the notifications for West Croydon station on the “tram” line.

$.connection.hub.url = "";
var hub = $.connection.predictionsRoomHub;
// when we receive a push notification we will update the board...
hub.client.showPredictions = updateBoard;
$.connection.hub.start().done(function() {
  // here we subscribe to Old Street on the Northern Line
  var lineRooms = [{ "LineId": "tram", "NaptanId": "940GZZCRWCR" }];

There is a full demonstration at jsFiddle, source code is on Github.

Screenshot 2016-06-06 15.06.44.png
A jsFiddle demonstration of a tram status board at West Croydon.

As always, we love to hear what you are building with the API, or if you have any questions, let us know in the comments.

* As always, the API usage examples in this blog are anonymous, so the quota is strictly limited. For a real application, developers should register for an API key.


  1. This seems a slightly odd development, as it now means that we are presenting the data back in a different way to what is actually on the trams themselves (given that they have the route number on them, and the individual routes are still on the map). Do we still have a way to tie the routes back to the route numbers the user is presented with?

    More generally, is there a way to tie the arrivals data to the route its associated with? The api only gives us inbound and outbound, which is a lot less useful once there are four different inbound routes on the same id.

  2. Tim,

    As I said in a comment earlier this week — Tram times are the timetable times and not accurate arrival times based on movement.

    Not sure how come disruptions are discovered if the realtime API does not track movement times…

    Can you help?

    Perhaps the bug I reported and you acknowledged (“We are aware of some problems with our source data feed for trams having a much higher latency than the feed used for the platform displays.”) has been resolved? Otherwise there is no use to the tram feed I am afraid… we can just present to users timetable data…

    Thanks again.

    1. Hi Caroline, disruptions are manually entered into a backend system by the operations team and exposed in our API via the endpoint. In other words, the disruption system is not linked to the realtime tracking system, except by its human operators. This is broadly true for all other modes – tube, bus, river etc.

      I will raise again the issue of arrival times being out of sync, this is an issue we are still looking to resolve. Thanks.

    2. Just to update you on the latency issue. After Tim reported this, we have heard back from the trams team:
      “We are aware that there is a 1-4 minutes latency in the trams arrivals feed and are working hard with our supplier to fix the problem. We will let you know via this blog when the issue has been resolved.”
      Rory O’Neill, Director, London Trams

  3. I would like to point out some issues that my users pointed to me and please bare with because I may be asking stupid questions. I am a junior developer who created Croydon TramTime and some of the feedback that I have received was that most of the arrivals were incorrect. However I am using your API to get the expected arrival and time to station. I guess these information are not the same as the information provided by the board at the tram stops. Why is that?

    1. Thank you for the feedback. We are aware of an issue with the data provided to us for tram arrivals. This _should_ be the same information as provided by the board at the tram stops, as is the case for bus, tube, river modes, but there is a defect causing latency on the feed which we are investigating.

      1. Hi Tim,

        I would like to know if there’s any update regarding the latency on the tram arrivals feed. I guess it is not solved yet, however I would like to know if there’s at least a predefined timetable which I could use in the mean time as it would be more accurate than the arrivals. I have tried to use the timetable API but with the changes made to the tram API, it’s not possible to get the timetables for the trams. Also (this may not be relevant) I have noticed that Google maps is able to get the trams timetable and it is pretty much accurate. Could you please tell me where I can find this API?


Leave a Reply

Your email address will not be published. Required fields are marked *