Unified API Part 5: AoT – Arrivals of Things

In Part 3 of this series, I gave examples of finding the Routes of Things using the Unified API. This article focusses on the “Arrivals of Things” – how to find out when services are going to arrive on those routes.

As before, all of the API examples in this page are live, however they do not include API authentication tokens. This means that if you follow the link as is, you will be using anonymous access, which is throttled for fair use, so you may get a 403 response. We recommend for your own development that you obtain an “app_key” and “app_id” by registering here. The data in these examples will be in JSON format, so installing a JSON formatter plugin in your browser will help you read the data returned.

Ride on time

Let’s start with the most prominent example of arrivals, shown when viewing a nearby stop:

At this bus stop we can see the time-to-stop of the next services due to arrive.
At this bus stop we can see the time-to-stop of the next services that are due to arrive.

The API used for the arrivals board is the Arrivals detail on the StopPoint entity. So if you know the StopPoint id (which is a NaPTAN code) you can quickly get the arrivals of all services (Dan gave lots of tips on how to find StopPoints and their ids in Part 2 of this series – you’ll also see them in URLs as you navigate stop pages). This API can also be filtered by mode and line, which is useful for busy transport hubs that serve lots of routes.


  "stationName":"Haggerston Station / Downham Road",
  "towards":"Aldgate or Old Street",

The response tells us a number of useful pieces of information. We get the Platform-level StopPoint id and platform name, so we know exactly which platform this service will arrive at (for a simple bus stop as above, there is usually only a single “platform”, but at a bigger bus station or tube station, this can be used to retrieve additional information about the platform e.g. accessibility).

Most importantly, we get the time-to-station in seconds, and the expected arrival time in UTC. The API also provides a time-to-live, which indicates how long this prediction is valid for.

Train in vain

Let’s also look at a Tube station, to demonstrate how the unified API uses the same concepts across all modes.

Example for a Tube station
The Unified API uses the same concepts for arrivals across all modes – this is an example for a Tube station


  "currentLocation":"At Platform",
  "destinationName":"Morden Underground Station",
  "platformName":"Southbound - Platform 2",
  "stationName":"Old Street Underground Station",
  "towards":"Morden via Bank",
  // etc...

The response is very similar to the bus example – giving the same arrival time, platform and service information. With tube, additional information on the current location of the train is available. Unlike the bus example though, the vehicleId for a tube service is dynamically generated for the service. Developers should note that while train running numbers are usually unique (for each line) it is quite possible to have more than one train with the same timetable number in service during times of disruption. Some will also disappear when they enter depots or sidings as this data only shows trains ‘in passenger service’. (Hat tip: commenter John Murrell).

The API can also be used to get the arrivals for a whole line or service:

So if you really want to work out if buses really do travel in groups of threes, this is the API for you!

Time is on my side

I’ve demonstrated how easy it is to get the current departure times, so it should be easy to build a live departure board of the sort seen at bus stops, tube platforms or on our website. To keep the board up-to-date, a naïve approach would be to regularly poll the API to show the user the latest information as their service approaches. But this  would waste a lot of bandwidth on mobile devices, especially where the information hasn’t changed since the previous API call. It’s also inefficient for our API to serve: the data is difficult to cache because it’s constantly changing, and each group of users at a stop will want slightly different information. Our usual strategy of Varnish caching with horizontal scaling doesn’t really work.

A more efficient approach is to subscribe to notifications of the arrivals, which we call predictions. The Unified API provides a SignalR hub for predictions, where developers can subscribe to a line or stopPoint. They are then pushed notifications using whichever mechanism the SignalR client determines is the most efficient. Usually this is web sockets, falling back to long-polling on older browsers. The initial subscription and subsequent notifications can be seen if you open the developer tools on your browser.

It’s easy to use our SignalR client in your own application – 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 Old Street station (NaPTAN code 940GZZLUODS) on the Northern line.

$.connection.hub.url = "https://push-api.tfl.gov.uk/signalr/hubs/signalr";
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": "northern", "NaptanId": "940GZZLUODS" }];

You can play with the full demo at jsFiddle here, source code is on Github.

Something about this picture
Northern Line arrivals at Old Street station, as you can see by following the jsFiddle link above

We’d love to find out what you’re building with this data, what is most useful to you and if you feel that anything important is missing from the Unified API. Please do let us know what you think, or ask any questions you have on our arrivals data in the comments below.

Update 18/04/2016: Live tram arrivals data is available:

We have recently integrated live tram arrivals into our predictions API, using exactly the same model and query style as the tube, bus and river arrivals. You can get all the tram arrivals in a single API call, or use just for a single station as shown below.


 "id": "1158109161",
 "operationType": 1,
 "vehicleId": "2531",
 "naptanId": "940GZZCRWCR",
 "stationName": "West Croydon",
 "lineId": "tram-1",
 "lineName": "Tram 1",
 "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"
Screenshot 2016-04-18 16.51.04
The tram arrivals board at West Croydon for the Eastbound services.

(10/05/2016: Updated the signalR link to a newer demo using the latest SignalR.)


  1. Something that would be really useful for building more intelligent routing apps would be the number of Oyster taps both in and out of a station.

    I’m thinking of a scenario whereby a person wants to get from Carnaby Street to London Bridge. Current routing would suggest Oxford Circus > Green Park > London Bridge however due to significant overcrowding in the evenings at Oxford Circus the station stops new passengers entering the station and therefore it might be faster for the passenger to walk to Green Park or Bond Street.

    An API that exposes the number of taps in and out at a station for the past minute could indicate that when there is a significant drop in the number of taps into a station that the station is artificially managing passenger flow.

  2. The statement ‘And yes, those vehicleIds (train numbers and bus registration numbers) are accurate if you have a favourite vehicle!, above is not correct for the Underground – the number shown is the train number in the timetable not the vehicle number. Developers should note that while train running numbers are usually unique (for each line) it is quite possible to have more than one train with the same timetable number in service during times of disruption. Some will also disapear when they enter depots or sidings as this data only appears to show trains ‘in passenger service’.

    1. Thanks John! I will correct that – I just assumed because the bus registration numbers were accurate, the trains would be too! Just goes to show us developers should get out into the real world more.

      1. Tim,
        The train unit numbers are in the database for Vic, Jub & Northern in a different field – you can see them on TrackerNet. They should be unique. Sub surface and the other lines will follow in the next decade or two. Not sure why the public would want to track particular trains though unless it is to view their graffiti ! Things might change if we get ‘text a fault on my train’ as Northern trains and a couple of other ToCs have done (see the December Modern Railways).

        There are various oddities in the data as well (assuming you have not filtered them out) such as National Rail trains on the Wimbledon Branch. I beleive the old api also had data missing for arrivals for some stations on the North of the Circle Line – something to do with the signalling system and a kludge to get the train positions via connect radio cells I seem to remember. It would be helpful to developers to provide a list of exceptions such as these – perhaps TfL need a developers Wiki ?

  3. One thing that appears to be missing from the Unified API is how busy the vehicle is. This is certainly available on the Victoria, Northen & Jubilee lines at present and will be available on Sub-surface when they get a new signalling system. Doi f buses and boats transmit this information ? Availability of this would allow developers to provide information about crowding and allow broadcasting of alternative routes or more lightly loaded vehicles. Unfortunatly the train load weigh data transmitted is for the whole train so it is not possible to encourage people to move to carridges that are less heavily loaded. In principal this could be done but would require modifications to the train and signalling systems.

    1. You definitely have insider knowledge John! Yes we do have vehicle weight data, and I will ask our data team whether it will be possible to make this available publicly. Internally we have a Travel Demand Management programme which is looking at using this information to inform the public about the best times to travel, or even which carriage and/or exit will be most appropriate for their journey.

  4. Hello Stephen,
    There is no reply facility on the blog page you referred to so I will reply here. I think someone already mentioned that a significant drop in entries can be used to give information on station closures – the developers will need to understand the station layout – OxO has multiple entrances but one set of ticket gates while Victoria has ‘two’ entrances and two separate sets of ticket barriers one for the Victoria Line and one mostly for the district line. Since the Victoria Line entrance is closed quite often with the District barriers remaining open the data for both sets of gate lines would have to be supplied separately. No or very few exits as well as entrances could be used to detect a station closure.

    Not really sure what use the journey time data is – the data is probably time expired by the time they swipe out – in addition they can go multiple ways on some routes. Not sure it will help much with crowding but maybe someone can come up with a clever algorithm. For most regular travellers I think they go on previous experience – today will be as crowded as yesterday. The only useful information might be if there is a major perturbation to the transport system such as the closure of a National Rail Station – that alters the flows but it will be a challenge to model that in a useful way in real time.
    The journey time data is also a good inspiration for Crime Writers – the data shows an unusual flow of 26 people from Acton Town to Baker Street one Saturday but only 25 returned!
    I have not looked at the Bus data as the file is too large for Excel , since people do not swipe out of buses I am not sure how much value there is – the best measure of loading would be from the vehicle suspension if such data is available.

    Any developers will probably need quite a lot of support in terms of information on how the network actually works. Also for buses routes are diverted due to events or incidents – this information needs to be transmitted via the API so developers can take account of the changes for instance a bus being somewhere that is not on it’s route.

    1. Hi John,
      Thanks for the excellent feedback, it’s really useful for us to hear it from somebody who clearly has an in-depth understanding of our network and our data. This customer flow data is a hot topic at the moment and certainly something that will be followed up with more posts on this blog, so do watch this space.

      (A mysterious disappearance near Baker St?! If only a crime writer had come up with a detective in that area who could solve it…😉)

      1. I have manage to have a quick look at a very small sub-set of the bus data that for the 521 and I don’t beleive the numbers are correct – it shows around 500 customers an hour leaving Waterloo in the morning peak and the concensous amongst those who use the route it should be around 1500 (based on 30 buses per hour with 50 customers). I beleive a lot of people do not swipe in because of the sort of tickets / passes they are using. Certainly the buses from 08:00 to 09:00 are packed with people queuing for for the next one. Not sure how this applies to other routes but it is quite common to see people showing a ticket to the operator rather than swiping the reader on other routes I use.

  5. Thanks a lot for the post. I had a look at SignalR and integrated the JS code but I struggle with two things:

    1. Using the above code I can’t establish a connection with websockets and instead get:Error during WebSocket Handshake: Unexpected response code: 400. Long-polling works though.

    2. I can’t load the results because of what looks like a cross-domain issue: XMLHttpRequest cannot load https://push-api.tfl.gov.uk/signalr/hubs/signalr/poll?transport=longPolling…ta=%5B%7B%22name%22%3A%22predictionsroomhub%22%7D%5D&tid=9&_=1451729941423. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘https://fiddle.jshell.net’ is therefore not allowed access. The response had HTTP status code 504.

    Any ideas how to resolve this?

    1. Hi Paul, yes I see the same issue. This looks like a regression that I have passed on to our technical team. I’ll let you know when this is resolved.

    2. @Paul this issue has now been fixed and the jsFiddle is working for me again in Chrome and Safari. Can you give it another try? Thanks.

      1. Hi Tim,

        Thanks for looking into this. I’ve tried it out and it works perfectly.

        I was trying to use it to monitor bus arrivals at certain bus stops though that does not seem to be possible. At the moment I’m polling arrival predictions at regular intervals (every few seconds) with the assumption that when a bus was previously predicted to arrive within a few minutes but a few seconds later is no longer predicted to arrive it must have arrived at the bus stop in the meantime. This is of course a very crude way of doing it (and because of occasional prediction errors doesn’t work very reliably) so I was hoping to get more granular/reliable info with the notification system. I can see that you have that sort of information for the tube – is there anything similar for buses or any other idea you might have on how to realise this?

        Thanks a lot,

      2. @Paul there is a vehicleId on each bus prediction (usually the actual vehicle reg number). Does that help you track individual arrivals?

  6. Hi, Many Thanks for the working examples.

    Is there a reason for using v2.0.2 of the jQuery.SignalR library ? I occasionally get an error which has been fixed in later versions.
    ERROR : “Uncaught TypeError: Cannot read property ‘pingInterval’ of undefined”
    see: https://github.com/SignalR/SignalR/issues/2865

    Would it be possible to update the TFL CDN with the latest version ? I can’t use a local copy of the script as am getting a ‘cross domain’ URL issue.

    Best regards,

    1. Hi See-See, I have put an upgrade to jQuery on our backlog, thanks for making us aware of the issue with SignalR. Hopefully it’s just a transient error that you can work around for now? We’ll let you know when we’ve upgraded. Thanks again!

  7. Hi, great post!

    I’ve been dreaming of a unified API like this for over 2 years, since I experimented with compiling route data along the real road network and visualising live buses moving along them – in 3D! You can see that here:

    I’ve been digging through the new API and I was curious about how I can get and track information on a specific vehicle (eg. imagine you wanted to see a list of next stops and predictions for the bus you’re on right now). For example, with the old(?) Countdown API it was possible to see prediction updates for a specific vehicle using the following endpoint: http://countdown.api.tfl.gov.uk/interfaces/ura/instant_V1?RegistrationNumber=LX59DDF&ReturnList=StopCode1,EstimatedTime,ExpireTime,Baseversion,RegistrationNumber

    Can the same thing be achieved with the unified API without having to poll the entire route each time and filter out anything not related to the single vehicle ID we’re interested in?

    One other question – is it possible to get location information for vehicles yet?

    My end goal for needing vehicle-level prediction data is to use it to work out roughly where a vehicle is along the route, not in time but in actual physical location. You would save me a lot of time and pulled hair if it was possible to get either accurate vehicle position (eg. lat/lon), or instead a fractional value along the entire route linestring geometry / between the previous and current stop.

    Any suggestions you may have to work out vehicle location using the new API would be much appreciated.

    I really hope you can help – there is so much I plan to do with the new API!

    Happy to discuss this via email instead if it’s easier – rob [at] vizicities.com


    1. As a follow up (though I’d still like to hear a response to my initial comment), I’ve been digging into the new API and coding up a rough implementation to try and position buses using the available data that I can find. Unfortunately, while the API access / interface is great I’ve encountered a bunch of issues and inconsistencies with the data which basically render it unreliable at best, and useless at worst

      For example…

      – Many predictions have dramatic inconsistencies between the expectedArrival and timeToStation values – shouldn’t they at least be roughly the same?
      – Some have expectedArrival / timeToStation times for the current stop that are sooner than the previous stop – if you ordered the predictions by expectedArrival / timeToStation then it wouldn’t match the route itinerary order!
      – Some have dramatically inaccurate values for expectedArrival / timeToStation, indicating that a vehicle will only take say 7 seconds to get to this stop from the previous when, on average, others take a minute or 2.
      – A minority of predictions have incorrect Naptan values that don’t match up with any in the route itinerary – eg. the 65 bus route predictions use Naptan 49000063001 but the route is 4900063001 (one less 0)

      Without wanting to clutter the comments – who can I talk to about this, perhaps by email to start with? I’m actually working on a project with TfL right now, so if I can’t reach you here I’ll try and find a contact method through my existing connections inside TfL.

      Appreciate the help, and the otherwise brilliant new API!


      1. Hi Robin, I’m aware of vizicities and was following it when your first demo came out. We were still working on the API beta at the time, so I’m glad you appreciate what we’ve done!

        Unfortunately we don’t have a vehicle position push API, but it should be doable since we load the Countdown stream into a NoSQL DB for temporary storage before pushing it out with SignalR. I’ll add a feature request to our backlog for this. As you say, the only way to do it using the current predictions API is the method you described – fractional distance along the route based on ETA.

        With regards to your second comment, we are aware of a few inconsistencies and I will raise the ones you’ve pointed out as bugs. We’ve traditionally found the predictions API difficult to test without actually going out in the field, so any tips you’ve had for automating this would be appreciated! I’ll drop you an e-mail and then I can put you in touch with our relationship manager.

        Cheers, Tim.

      2. I’d also like this feature. I’m currently doing as you suggest, fetching all predictions and filtering on vehicle ID. Then, for tube trains, I need to find the route the train is currently on — I derive all permutations of route on that tube line, then veto any that don’t contain all the stations that the train is estimated to stop at, finally truncating the one that best matches at the final destination. It’s fairly complicated but does seem to work fairly reliably.

      3. @Amy the “predictions by vehicleId” feature is complete and working its way through QA. We’ll be summarising some of the fixes and features we have added for the developer community in a new blog post soon.

  8. Tim, I read this with much interest. Thanks for the post!

    Re actual vehicle position, how do tube vehicles work? If I want to know exact position should I do it using the current real time tube feed and conclude where the train is between stations based on latest ETA to the next station? Based on my testing this works for buses as you noted as they do send reports in between stops but not for tube since your API does not get updated when a tube is ‘stuck’ between two stops and all future stations’ arrival times get refreshed (and increased) when the tube vehicle gets to the signalling box of the next station. Is my testing correct or you actually do compare the previously estimated time for a tube to arrive at station N+1 and when this time is surpassed you without you having received a signal that the vehicle arrived at station N+1 you add more time to the arrival for this vehicle to station N+1 and all subsequent stations?



    1. I’d be interested to learn a little more about this too – currently analysing the new API myself to work out the best approach for interpolating vehicle position along the route. Pretty confident I can do this accurately with buses due to the timely updates, though I reckon it’s going to be a lot harder for trains due to the faster speeds, less timely updates and quirks with *when* arrival times are actually changed on the updated (if Caroline is right).

      Getting a further understanding of how and when this arrival data is updated specifically for trains will give me some boundaries to work within.

    2. @Caroline you may be right about the way tube arrivals are updated… We base our predictions on the Trackernet feed and I’m not actually sure if we synthesise a new prediction if the tube is late… I’ll forward this question to the Trackernet team and get back to you.

  9. Hi,

    is there any way to connect the static TfL tube schedule data (Journey Planner Timetables) and these real time feeds? For example, let’s say I have an X line train that starts from station Y at time Z. I would like to update my router that routes people from place A to place B with this piece of information; how do I connect the update that X an line train T is arriving at station Y at time Z with the static schedule? The trainID seems to be randomly generated. Should I actually drop the static schedule and just rely 100% on the real time tube arrivals feed to inform my router of all trains in London? Is it actually tracking 100% of subway trains right now (ignoring temporary technical problems of course)? Is it possible that a subway train runs but doesn’t exist in the real time arrivals feed?


    1. @Sandro unfortunately you are right – there’s no id on which to join arrivals information to the timetable information. But you can assume that all 100% of vehicles on all services are in the arrivals information! If you find that to not be the case, it’s a bug, so let us know!

    1. Hi Sam, thanks for pointing this out. I have raised this with our service desk and we are investigating the issue. Since we’ve only just started testing, perhaps you can help us: In your tests have you recorded the impact on the arrival times i.e. how much are they skewed by this latency?

  10. Hello Tim,

    I’ve been trying to use the TfL Unified API to retrieve a list of bus arrival times for night buses to display on my Android application. I’m using ‘/Line/{ids}/Arrivals’ but it returns nothing when I search for a night route (e.g. N171). Is this a known problem, or am I going about it the wrong way entirely?

    I look forward to your response.

    Nathan Odong

    1. Hi Nathan, I think the issue here is that you are looking at the “live” arrivals for a night service, during the day. When the service starts at night, I think you will see results on https://api.tfl.gov.uk/line/n171/arrivals. I think the timetable, rather than the live arrivals might be more suitable. For example: https://api.tfl.gov.uk/Line/n171/Timetable/490000235Z/to/490015429S

      Read more about Routes and Timetables here: http://blog.tfl.gov.uk/2015/10/19/unified-api-part-3-rot-routes-of-things/

      1. Thanks for your quick reply!

        When testing for night buses, I was testing during the night. Not day. But I found that wasn’t the problem. Rather it was because I was entering the ‘n’ prefix in upper case rather than lower case. Doing this obviously returned nothing when using the API call. I noticed that the prefix in ‘lineName’ is different to the one in ‘lineId’.

    1. I would like to know this as well. Hammersmith (H&C line) tube station is a good example. I’d like to know when the trains are about to leave, where they’re bound for (i.e. which line), and which platform they’ll leave from.

  11. While I’ve got your ear, can I just ask a question about tram routes?

    I may be missing something, but it seems to me that the directions (inbound or outbound) on tramlink services on the arrivals board are backwards. As they are, my validation logic rejects the route because the stops are in the wrong order. But if I swap them around, I get valid data.

    For example, consider East Croydon Tram Stop. On the arrivals board, there is a service on line 2 with headsign “Beckenham Junction”. This is tagged as line ‘tram-2’, direction ‘inbound’.

    However, when I go to fetch the route for tram-2 inbound, it finds Beckenham Junction is the first stop, not the last. But if I swap the direction (and actually fetch tram-2 outbound), it gives me a route that does match.

    Some routes have even stranger data. For instance, tram-2 outbound contains “West Croydon”, both in the orderedLineRoutes section (as NaPTAN ID 940GZZCRWCR) and also in the branch->stopPoint dictionaries that give the station name and information. But tram-2 inbound, while including 940GZZCRWCR in the orderedLineRoutes, does not contain “West Croydon” in any of the dictionaries, leaving me with an ID that I have no name or latitude/longitude for.

    Do you know if this data is likely to improve soon?

    1. Yes there is a known bug in the ordering of stopPoints in the orderedLineRoutes field in the Route API, and the workaround you describe (switching to outbound and reversing the list) is unfortunately the only solution I can suggest for now. Your second issue I will raise as a bug – every stopPointId included in the orderedLineRoutes should be included in the dictionary so that you don’t need to make further API calls to retrieve the name or lat/long. We are working to continuously improve the API, including fixes for bugs spotted by developers. I will have a blog update on this soon.

    2. As West Croydon is on the ‘loop’ and can only be served in one direction, can it be both inbound and outbound at the same time for the same route?

      At East Croydon the feed seems to show ‘West Croydon’ but at the next stop (George St.) they then change to Elmers End or Beckenham Junction. However, at the next stop (Church St.), the destination is changed again to Church St.! (I stopped watching the feed after that).

  12. For trams, comparing the expected arrival times from the API with the times on the electronic display boards at each platform, the predictions appear off. For example yesterday I was standing at the platform with the tfl.gov.uk arrival predictions saying a tram was Due, but the board saying 4 minutes. Is this disparity expected? Shouldn’t the API be delivering the predictions in sync with the platform displays?

    1. Hi George, thanks for the feedback. We haven’t noticed a disparity that large in our testing, so I’ll raise this with the service team. Which tram service and platform were you observing?

      1. Thanks Tim. I noticed this at Mitcham Junction and Wandle Park at the very least. This was before your end of April post about “live tram arrivals being added”. Maybe before they were just ETAs and hence the disparity, whereas now you’re getting the info from the same place as the platform signs? I’ll check on my way home tonight what the new average difference is.

  13. Hello,

    I’m trying to play with the api a little, and i’ve noticed that many stop points (returned using the stop point search api) return an empty data when using the arrivals api.

    Here’s an example:

    Can you please tell me if I’m doing anything wrong? (naturally, I’m sending the proper app_id and app_key and get results for some stop points…)


      1. Oh, now i get it…
        I get a list of stop points using the search api. Is there a way to get all the child stop points as well with a single request?

      2. Yes, having the same issue. Bit confusing to see which naptanId values actually give you times. Also, instead of empty data, the double entity stop should logically give you all ties for both children when used, no? Or the id types should be explained clearer.

    1. I updated the examples a while back to simply reference “https://push-api.tfl.gov.uk” (i.e. no “prod5”). This way the examples should work regardless of which production environment we are running from. Is there a reference to prod5 that I missed?

      Thanks for pointing out that the jsFiddle was broken – we updated SignalR so I needed to update a few references. This has now been fixed in https://jsfiddle.net/4bmLzjt5/122/ and updated in the article.

  14. Hello,

    That was a great blog entry. I am still confused on how from a HUB code (i.e. HUBCAW, HUBKGX), I can get the individual naptan ids for the underground stations. Is that possible? Thanks.

  15. Tim,

    Tram arrivals do not really work. They should as expected arrival the timetable data not exact times of movement (see below). Sometimes they show a predicted arrival after the time of the timestamp (in tube you never have times for past stops…).

    Can you check what is going on (the tube and bus realtime predictions do work and it’s easy to see the tram do not).


    “tflTubeArrivalPredictions” : [ {
    “expectedArrival” : “2016-06-06T15:32:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRMTP”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Merton Park”,
    “timeToStation” : 0,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:33:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRMDN”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Morden Road”,
    “timeToStation” : 46,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:35:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRPHI”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Phipps Bridge”,
    “timeToStation” : 166,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:36:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRBGV”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Belgrave Walk”,
    “timeToStation” : 226,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:38:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRMCH”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Mitcham”,
    “timeToStation” : 346,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:41:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRMJT”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Mitcham Junction”,
    “timeToStation” : 526,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:43:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRBED”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Beddington Lane”,
    “timeToStation” : 646,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:45:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRTPA”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Therapia Lane”,
    “timeToStation” : 766,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:46:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRAMP”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Ampere Way”,
    “timeToStation” : 826,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:47:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRWAD”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Waddon Marsh”,
    “timeToStation” : 886,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:49:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRWAN”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Wandle Park”,
    “timeToStation” : 1006,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:51:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRRVC”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Reeves Corner”,
    “timeToStation” : 1126,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:53:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRCTR”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Centrale”,
    “timeToStation” : 1246,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:55:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRWCR”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “West Croydon”,
    “timeToStation” : 1366,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    }, {
    “expectedArrival” : “2016-06-06T15:57:00.487Z”,
    “lineId” : “tram”,
    “lineName” : “Tram”,
    “naptanId” : “940GZZCRWEL”,
    “platformName” : “Eastbound Platform”,
    “stationName” : “Wellesley Road”,
    “timeToStation” : 1486,
    “timestamp” : “2016-06-06T15:32:12.855Z”,
    “towards” : “Elmers End”,
    “vehicleId” : “2552”
    } ]

  16. Another issue I found is that for DLR you have no vehicle ID… how can we track a vehicle moving without vehicle ID 🙂

    “$type”: “Tfl.Api.Presentation.Entities.Prediction, Tfl.Api.Presentation.Entities”,
    “id”: “-535918328”,
    “operationType”: 1,
    “vehicleId”: “”,
    “naptanId”: “940GZZDLWLA”,
    “stationName”: “Woolwich Arsenal DLR Station”,
    “lineId”: “dlr”,
    “lineName”: “DLR”,
    “platformName”: “Platform 4”,
    “direction”: “inbound”,
    “bearing”: “”,
    “destinationNaptanId”: “940GZZDLSIT”,
    “destinationName”: “Stratford International DLR Station”,
    “timestamp”: “2016-06-07T10:58:14.189Z”,
    “timeToStation”: 0,
    “currentLocation”: “”,
    “towards”: “”,
    “expectedArrival”: “2016-06-07T10:58:14.189Z”,
    “timeToLive”: “2016-06-07T10:58:14.189Z”,
    “modeName”: “dlr”

    1. Thanks Caroline. 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. I’ve also raised your issues with the inconsistent timestamps, and missing DLR vehicle id, these bugs are now on our backlog.

    2. Hi Caroline, unfortunately the source feed for our DLR arrivals (DLR Daisy) does not provide a vehicleId. The feed is so simple, just an XML version of the platform displays, that we can’t add back this information on our side.

  17. Hey guys, thanks for the great API. I noticed in my app (London Transport App) though that for Underground arrivals, the destinationName variable in the returned JSON is now blank thus my Live Arrivals doesn’t work properly anymore. When I developed my app (April-May 2016), this was working and returning the correct destination name. Has the API changed or is this a bug or a temporary issue with the data?


    Alex Crompton

    1. Hi Alex, glad you like the API! Thanks for reporting this issue, I can see that destinationName is indeed empty for all of the tube Predictions. I’ll get this investigated. In my demo, I used towards instead, does that help for now?

      1. Hi Tim, thanks for the quick reply. Using the ‘towards’ variable for the tube arrivals does indeed work. Thanks for that and thanks for investigating the reported issue.


        Alex Crompton

  18. Hi Tim, I’m pleased to see this comment thread is an ongoing dialogue. Could I follow up on a few things?

    Something I’m still not clear about – and I guess neither are some others commenting here – have all Countdown APIs now been deprecated?

    I saw stopBoard calls were turned off at the end of June, a month after public use of the Countdown site ended, but haven’t seen any announcement about whether/when the powerful and flexible “ura/instant_V1” will disappear.

    I am trying to stick with Unified API calls where possible, but have been unable to find equivalents for the following..

    1) Circle call:


    ..to find stops in a specified radius around a certain lat/lon.

    2) Status messages – by line:

    …which has way more information than:

    As well as the timed messages for future disruption, there are several ongoing messages only seen in the Countdown call. eg. Archway Gyratory roadworks and route 29 disruption.

    I fear all that useful info relating the area and interchanges with the line are all missed by developers using the Unified call. and that it’ll suddenly disappear one day leaving us without any way to even compare to see what useful service data is being lost!

    3) I’m rather mystified by the disruption call for a bus stop. In the example of old vs new here:


    I see nothing at all for that stop with new call. Am I misinterpreting the new call’s purpose?

    Referring back to your previous correspondence with Robin at vizicities…
    4) Has there been any development on the ability to pull up data by vehicleId, as was possible with the Countdown API? I had been hunting for an undocumented way to put search filters in a query string, but to no avail.

    Finally (thanks for getting this far!)..
    Who can I inform about broken stop points / incorrect data being served? I’ve tried via website and TfLBusAlerts but there are issues which don’t seem to be getting rectified.

    Thanks for all the work done so far. Looking forward to developments!

    Best Regards,


    1. From Dan:

      There are no immediate plans to deprecate the current Countdown API’s, instant or streaming.
      So for clarification there are currently several options for getting the bus prediction information:
      1) Countdown instant API – this is the original “instant” API, this is bus specific.
      2) Unified API arrivals – this is the unified version of the instant API it will contain the same data as 1) for buses but also includes all the other modes of transport, so this is a good choice if you want to make a mult-trasport-mode application.
      3) Countdown Streaming API – this is a good choice for B2B application where you want to track the predictions across the entire network.
      4) Unified API websocket arrivals – this is good for B2C application when you want to support instant update of predictions (lowest latency) on a stop/by/stop basis, e.g. you don’t want to track the entire network.
      Please also note that the Unified “mode” arrivals end point is an “instant” api for retreiving the status of all arrivals across the network, but you don’t want the complexity of dealing with a stream.

  19. I want to write a server side TFL signalR client, which can subscribe to a line or stop point and store the push notifications in a DB. All the libraries and examples are for client side and need browser support, while I need to subscribe as a client, browser-less, using PHP, NodeJS or any other server side languages. Is this possible and do you have any example code for it?

        1. We are aware of an issue with the tube arrivals which we are investigating. However, the bus arrivals are working if it’s possible for you to test with this other mode while we fix the issue?

  20. I can’t understand how to get the NaptanId. I have read part 2, but all I can get from that is an ID like “HUBFPK” for Finsbury Park station, and this does not work when trying to get arrivals data.

  21. While vehicleIds are not unique for tube trains, would it be possible for Vehicle/{ids}/Arrivals to return one answer for every train with that id? For example currently Vehicle/145/Arrivals returns a train in East Finchley on the Northern Line, while the train I want to trace is at Kilburn on the Jubilee.

    1. Thanks Kai, that’s a good suggestion. We will look into this as a feature request. We are also looking at returning all arrivals information for the vehicleId, not just the next stop.

Leave a Reply

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