PHP Nike+iPod stats

A while back I got a Nike+iPod attachment for my iPod. I really love the stats the Nike web site gives you, but there is really no good way to share that data. Nike came out with some desktop widgets for Yahoo Widgets, but you still can’t easily share that with others. However, today I saw a story about a WordPress plugin that did exactly this. The catch is that it uses PHP5 and I am on PHP4, so I could not port it over. I did a bit of Googling and found that the two URLs the script made use of was all I needed. With some creative CURL use, I wrote a script from scratch that gathered the XML data. The output can be seen on the right hand side of this blog. As you can tell, even though I got it a while back, I have not done as much running as I would have liked. Recent karate-related ankle and knee injuries have kept me from pursuing this as much as I’d have liked, but I’m hoping to pick it up again, despite the cold weather. A recent subscription to Runner’s World has me enthusiastic about running again, so hopefully those stats will go up.

You can pick up a copy of the nikeplus.php version 1.0 PHP script here for use on your own site. Be sure to rename the nikeplus.pht file to nikeplus.php. You can use something like this to place it as a static HTML text object in the sidebar of the CMS of your choice:

Wishlist/Coming enhancements:

  • Cached data for quick response and reduced calls to Nike servers.
  • Goals and Challenges data.
  • Red and green theme to match the site.
  • RSS link to the actual run data.

If you have an enhancement or some code to add, feel free to email me or leave a comment!

Update 12/31/06: – I’ve posted version 1.1. Thanks to Beth Terry who pointed out in the comments below that those who have run more than 1,000 minutes or miles or whatever I was formatting with number_format would have a comma in it and thus mess up the stats. I’ve moved all number formatting into the print statements so that stats will be correctly displayed.

Update 1/3/07: – Version 1.2 is posted thanks to Eric Byers who contributed code to add caching. I’ll try to pretty it up and add the RSS, Goals, and Challenges data next.

33 thoughts on “PHP Nike+iPod stats

  1. For those that don’t already know. You don’t need the Nike+ shoes to use this gadget. Go to Runner’s World to see what kind of foot you have (the wet test) and get a shoe that supports your type of foot. Or if you can take any old sneaker, strap the sensor onto the laces and hit the road. See Podophile for more details.

  2. sadly, your script, which i think is my favorite, since it’s text, and can be manipulated, doesn’t work. It seems to crash my website every time I try to use it.

  3. Hi. I love your script, but I had to fix a problem before I could use it. I was getting these results:

    Distance: 85.94
    Total Run: 1,159.29 mins
    Average: .01 min/mile

    Clearly, that average is wrong. I poured over the script and wracked my brains until my smart husband suggested taking out number_format. Suddenly, it worked, and I got the right answer.

    I put number_format back in only in the print section.

  4. Beth,
    The number_format is only there to take off everything after the second digit after the decimal point. However, this is my fault for not having run more than 1,000 minutes. =) I’ve fixed this. Thanks for pointing it out.

    I think it’s very important that the script be manipulatable to cure these kinds of things since all servers are different. Glad to see you got it working, though.

  5. I had it working, but upon refresh I just get the “Failure to authenticate” message. (Which I also see on your site.) Any ideas?

  6. The Nike server does not seem to like the frequent requests. This data really needs to be cached, especially since you’re not likely to run more than a max of 2-3 times a day. If I change this to cache once an hour that will make things happier since it will go from requesting X times per day (once per click) to 24 times a day. It would also never show the “Failure” message since it could show the old data upon failure and then have the chance to get the data again on the next hour.

    To get around this for now, just refresh and it should show correct the next time. I’m hoping to get a chance to work on it this weekend when I want to start running again. I just have to shake this bronchitis first. =)

  7. Actually, both yours and mine seem to be displaying fine now. I think it was actually a problem with Nike’s site altogether. I had real trouble logging in to their site and several times I got a “Too much traffic! Go away later!” page. But the cache must not have been working correctly, because I did get the data to display properly once before the Nike site crashed. I’ll take a look at it this weekend too and see if I can suggest anything. Thanks for putting this together though – it’s a great idea!

  8. I’ve been successful in pulling data from the site about challenges and goals in XML so I will be working that into the script Saturday. It works very much like what we have been doing, so it will be very much cut and paste with a little additional logic.

  9. My husband and I had a go at the code last night, and we decided to run the script as a cron job once a night (as opposed to every hour – I don’t run that often!). I also tweaked the display of the times and units a bit. (Note: metric units should be kilometers, not meters.) I also made a wizzy looking badge to display the stats based on the look of the Nike+ site. You can see it in the sidebar on my blog. My husband was also able to sniff the location of the complete run data file, so I’m hoping to update it to show the most recent run information as well. I’ll post my code once it’s finished. Thanks for the kickstart!

  10. No problem! =) That’s a good looking badge. I’d definitely love to see any code you want to contribute. I should have more this weekend, so a new script should be available then. I can work in any changes during that time. I also have the location for run data and challenge details that I will be working in. That all depends on a token that must be pulled from the site, but it is unique to each person and never changes.

    BTW, with the caching in the most recent script you should be able to let the script run each time someone loads the page as it will only refresh from the Nike site once an hour. I think those 24 hits a day will be better than the 10,000+ per day that I was hitting Nike with during a peak a few days back. =)

    My goal in giving out the code is to get people running. The social aspects of the web can encourage people to see that badge update every day or so. This tech is just a tool to get people into some healthy living.

  11. Excellent, some good feedback, and potentially more help. I’m itching to get my hands on the code after Ernie works on it this weekend, and add some of the run/goal data to it also.

    Basically you should be able to almost completely replicate the Nike+ site, but you can let anyone see it now.

    The one thing I probably will add is an ability to show how many runs per week you are averaging, and compiled stats based on things like that, things Nike+ isn’t doing yet.

  12. Oh, and one other thing.

    How I implemented the caching, if it doesn’t get a valid file back from Nike+, it uses the one it had previously cached. Granted it will hit Nike+ on each load, but as soon as it gets a valid one, it will cache it up again.

    Hopefully that makes sense. Basically it means your data could be outdated if NIke+ goes down, but you should always have stats available.

  13. Where are you getting the API from. Would you mind shareing your AIP source so that we can contribute also.

  14. Great I look forward to it. I grabbed the URLs out of the downloaded code and tried a few common extensions to get the Service API or WSDL but had no luck. Curious how did you stumble upon it?

    I left an email on the comment I would love if you would email me the URL to the service def inion. I’m really anxious to start playing around (yes I’m a dork!).

  15. I didn’t see your email anywhere, but I just posted the first article. Note that the Nike site is really flaky today and might not give you much joy.

  16. Actually, I’m getting “unable to login from locale” when I hit the login call, is this still working OK for you?

  17. Nike seems to be changing something on the site for working with their widgets. This is breaking things for a lot of people. Will have to ride this out to see what comes out the other end after their changes. I’ll analyze the situation in a few more days.

  18. I seem to be getting old data when I use this.. I’ve been playing around with debugging the flash, and I found the following links that work, but I was wondering if you have any info, etc. I want do some development against this site, but it seems to be slow and flaky at times.$$ppmp01&locale=en_us”;

  19. I’m getting “login from locale not allowed” when I type the login URL directly into my browser.

    Has anyone found out what has changed? I haven’t had stats on my web site in days.

  20. If you have the script that uses caching you should still have data displayed. I won’t know what has changed until new widgets come out since Nike hasn’t published the API. They’ve basically shut things off for the old way of logging in – their own widgets still cannot log in. Now they put up the message “We are upgrading your widget right now, but we will have it running as fast as we can. Upgrade.”

    I did look at and confirmed that they are able to get my data, as I’ve never logged in there before. I’m still trying to figure out. It may be a case of faking out a certain browser (iTunes) which can just be added as a header to the CURL scripting.

  21. Gosh, it’s always the simplest things. I’ve fixed the script and gotten it running again. It seems that Nike got rid of the external_profile_login and put in a requirement for generate_pin. Another thing to watch for is that CURL does not create the cookie.txt file. Once you touch that, cookies will actually be stored in it, although they seem to change anyway the next time the script runs. It is possible the widgets were doing this all along anyway.

    So, I ran some wireshark traces to see how the Goals widget interacts with the Nike servers. Interestingly, it appears that Nike solved some of their server issues by using Akamai. But the real revelation was how it interacts, pretending that it is Mozilla 5.0, and receiving the BSESSIONID cookie.

    Right now Nike has take down their servers for maintenance, but once I can again verify that the script works I will post the new code. Should be in my AM. Good night!

  22. Great work, I’ll be watching for the change. I need to login to grab some extra run data.

  23. Thank you! Thank you! I have stats again! I didn’t have any data displayed because I was still using version 1.1, the version without caching, when Nike made the login change. I didn’t switch to the version with caching until after, so I have had no stats for a couple of weeks.

  24. Mark, this looks great. It does everything I’d like to see in my run data. I hope you don’t mind if I adapt some of that to our script. What I would like to do is make mine more standalone so that it can be used anywhere, but also so that a WordPress plugin can “include” it and make it work there.

Comments are closed.