Scott Hanselman

How to add Tweets to your blog and debugging basic JavaScript: Why did Twitter.com/JavaScript/Blogger JSONP Widget stop working?

May 13, '11 Comments [13] Posted in Javascript
Sponsored By

I have a little yellow bar at the top of my blog that is supposed to show my latest Tweet. It's a nice unobtrusive way to show that I'm out there and I'm active, and maybe if the tweet is interesting to you, you'll stop by Twitter and follow me.

However, I noticed it stopped working recently. It was blank:

image

Static picture of a list of tweetsWeird. It'd worked great for years, plural. I searched around and found a few posts on GetSatisfaction asking about it, some recent, some not recent at all. Some people are having the code work on some accounts and not others.

Unfortunately, Twitter seems to have quietly deprecated the code I was using. It's still there but there are no pages on Twitter on how to add tweets to your blog in a low-level controlled way.

Twitter wants you to visit http://twitter.com/badges and use their existing Twitter Widgets. These are very typical of other sites, in that they are boxes with your tweets in them.

For example, here's a box of Tweets to the right, however, that's a little garish for my tastes.

Here's the code I was using to show just the very first tweet on the top of page. First at the top of the page I have a div that will hold my most recent tweet.

<div id="twitter_div">
<a href="http://twitter.com/shanselman" id="twitter-link" >Latest Tweet: </a>
<span id="twitter_update_list"></span>
</div>

Then later at the bottom I have these two scripts. These are what appear to be either not supported or not advertised by Twitter anymore.

<script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script>
<script type="text/javascript" src="http://twitter.com/statuses/user_timeline/shanselman.json?callback=twitterCallback2&count=1"></script>

Now, don't use it just like that if you want to get only 1 original tweet as I do. Because it's this very code that stopped working recently. Except it stopped working sometimes. But did it?

To figure it out quickly, first I visited this URL in my browser. It returns JSON of all my tweets.

http://twitter.com/statuses/user_timeline/shanselman.json?count=1

However sometimes I get this:

[]

Yes, really. An empty JSON array. But why? Well at this moment in time my "most recent tweet" is actually a native retweet. It's not a tweet from me, it's a retweet of a YouTube video. See below?

A native REtweet next to a real tweet

Perhaps this JSON Twitter API was created before the Native Retweet was invented. But, if I tweet something fresh, at hit http://twitter.com/statuses/user_timeline/shanselman.json?count=1 again, I'll see this minimized JSON:

[{"in_reply_to_status_id":null,"text":"Testing for a blog post. Move along. This tweet never happened.","created_at":"Thu May 12 23:44:13 +0000 2011","favorited":false,"retweet_count":0,"source":"web","in_reply_to_screen_name":null,"in_reply_to_status_id_str":null,"id_str":"68823826439487488","contributors":null,"retweeted":false,"in_reply_to_user_id_str":null,"place":null,"coordinates":null,"geo":null,"in_reply_to_user_id":null,"truncated":false,"user":{"is_translator":false,"notifications":false,"created_at":"Tue May 01 05:55:26 +0000 2007","profile_sidebar_border_color":"b8aa9c","listed_count":3909,"following":true,"description":"Tech, Diabetes, Parenting, Race, Linguistics, Fashion, Podcasting, Media, Culture, Code, Ratchet.","show_all_inline_media":true,"geo_enabled":true,"profile_use_background_image":true,"profile_image_url":"http:\/\/a1.twimg.com\/profile_images\/1344567304\/image_normal.jpg","contributors_enabled":false,"verified":false,"profile_background_color":"d1cdc1","profile_background_image_url":"http:\/\/a0.twimg.com\/profile_background_images\/157325454\/twilk_background_4ca8e4832a970.jpg","screen_name":"shanselman","default_profile_image":false,"statuses_count":40900,"id_str":"5676102","default_profile":false,"friends_count":2616,"profile_text_color":"696969","lang":"en","profile_sidebar_fill_color":"b8aa9c","followers_count":36994,"protected":false,"location":"Portland, Oregon","follow_request_sent":false,"profile_background_tile":true,"favourites_count":2089,"name":"Scott Hanselman","url":"http:\/\/hanselman.com","id":5676102,"time_zone":"Pacific Time (US & Canada)","utc_offset":-28800,"profile_link_color":"72412c"},"id":68823826439487488}]

I can run it by the http://jsbeautifier.org and it looks lovely...

[{
"in_reply_to_status_id": null,
"text": "Testing for a blog post. Move along. This tweet never happened.",
"created_at": "Thu May 12 23:44:13 +0000 2011",
"favorited": false,
"retweet_count": 0,
"source": "web",
"in_reply_to_screen_name": null,
"in_reply_to_status_id_str": null,
"id_str": "68823826439487488",
"contributors": null,
"retweeted": false,
"in_reply_to_user_id_str": null,
"place": null,
"coordinates": null,
"geo": null,
"in_reply_to_user_id": null,
"truncated": false,
"user": { ..... SNIP! .....
}
}]

So, Twitter has a nice JSON API that is old and doesn't support Native Retweets but I want the most recent tweet, my way.

Bam. http://twitter.com/statuses/user_timeline/shanselman.json?count=5

Of course, if my last five tweets are all Native Retweets then it all falls part, but you get the idea.

image

If I was really serious, I could even remove @replies, only showing original tweets, remembering that this JSON API doesn't include Native Retweets in its results.

I found some code on BarneyB's blog that is a modification of Twitter's original code. He mentions in the comments that he's removing replies in his code. I just took his code and stop the code as soon as a valid original non-replied tweet is found. In this case, I search the 5 tweets I requested that were returned from Twitter. If it turns out I reply a lot and get an empty payload, maybe I'll increase that number.

The conclusion here is that this code still "works," it just doesn't see Native Retweets:

<div id="twitter_div">
<a href="http://twitter.com/shanselman" id="twitter-link" >Latest Tweet: </a>
<span id="twitter_update_list"></span>
</div>

Then later...

<script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script>
<script type="text/javascript" src="http://twitter.com/statuses/user_timeline/shanselman.json?callback=twitterCallback2&count=1"></script>

My issue was that I want a single tweet, specifically the first original, non-native-retweet, non-reply tweet. I solved it by taking BarneyB's @reply-filtering code and adding a check that breaks out of the loop. I ask Twitter for 5 tweets, but as soon as I find one from that lists of candidates, that's the one. Feel free to View Source if you like, or just be aware of the limitation of Twitter's (possibly deprecated) JSONP API.

It was a trivial but fun lunch hour, indeed.

UPDATE: Great comment below from Dave Ward. He points out that I could have my cake and eat it too by using the new API and a "include_rts" flag like this:

https://api.twitter.com/1/statuses/user_timeline.json?screen_name=shanselman&include_rts=true&count=10&callback=twitterCallback2

Thanks Dave!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Friday, May 13, 2011 12:24:53 AM UTC
I love posts like this. Out of the blue, yet, relevant.

-SM
Friday, May 13, 2011 1:17:41 AM UTC
Thanks for the comment. Makes my day.
Friday, May 13, 2011 1:44:01 AM UTC
You can use the include_rts option to include native retweets, but it doesn't seem to work on the older API that you're using here. Try this instead:

https://api.twitter.com/1/statuses/user_timeline.json?screen_name=shanselman&include_rts=true&count=10&callback=twitterCallback2

I compared its result with the API call you're currently using, and the only change is the addition of a native retweet that was missing from the old one: http://encosia.com/attachment/1115/

Friday, May 13, 2011 1:53:10 PM UTC
If it weren't for the include_rts flag I'd simply start a while loop retrieving first 1, then 5, then 15 then 30 etc. tweets until a non-empty JSON result was returned. That way it wouldn't break should you have 5 native retweets in a row. Ofcourse you'd need a little safeguard limit (like; 100 or so) to stop the while-loop should be be retweeting like crazy.
Friday, May 13, 2011 2:10:39 PM UTC
when i call the url : https://api.twitter.com/1/statuses/user_timeline.json?screen_name=shanselman&include_rts=true&count=10&callback=twitterCallback2

response is:
twitterCallback2({"request":"\/1\/statuses\/user_timeline.json?screen_name=shanselman&include_rts=true&count=10&callback=twitterCallback2","error":"Rate limit exceeded. Clients may not make more than 150 requests per hour."})

is it normal ? I do not think so.
Friday, May 13, 2011 4:06:09 PM UTC
... and yet for me, at this particular moment in time, your "Latest Tweet" is still empty. Not sure where the disconnect is, but I thought you should know I'm still seeing one.
Friday, May 13, 2011 5:15:29 PM UTC
Interesting, so this API is being rate limited. I'll need to add some caching, I think, or hack their stupid badge?
Friday, May 13, 2011 5:35:29 PM UTC
Your tweet bar is still blank!

use this post to fix it..

http://www.hanselman.com/blog/HowToAddTweetsToYourBlogAndDebuggingBasicJavaScriptWhyDidTwittercomJavaScriptBloggerJSONPWidgetStopWorking.aspx

recursion :)
Ram
Friday, May 13, 2011 5:51:56 PM UTC
Ram - LMAO! Twitter's down, believe it or not. ;)
Friday, May 13, 2011 7:10:07 PM UTC
The rate limiting on unauthenticated requests to the API is per requesting IP, not per site/script/screen_name/etc. So, someone who has made too many unauthenticated requests in the last hour will be rate limited on any site that makes client-side Twitter requests, but that won't affect other visitors who aren't rate limited.

Since the rate limiting is isolated to a few users, I punted on the server-side caching approach myself, and append my latest status in a way that doesn't look broken if something goes wrong with the API call. So, a handful of people each day probably don't see my latest update, but they'll also never know there was an issue.

My script is here, if anyone's interested: http://encosia.com/blog/includes/encosia.js?v=4
Saturday, May 14, 2011 5:56:36 PM UTC
Scott and Dave,

Thanks for digging into the Twitter consumption logic and sharing what you found! I decided to go for it on 4th and 1 instead of punting (risky, I know, but sometimes devs need all four plays to get a first down too) and wrote a post about how to consume the Twitter feed server-side in ASP.NET MVC 3.
Write a Twitter user timeline controller action in MVC3
Friday, May 20, 2011 5:02:47 AM UTC
I was really fond of twitter integration some times ago. Most of the new things which twitter used to release had been integrated with my blog. But my blog traffic isn't that good and I don't think am getting more followers or anyone making something out of my tweets. I opted out. Also twitter doesn't provide any good analytics tool so I couldn't find the influence of it.
Wednesday, June 08, 2011 11:05:03 AM UTC
Fantastic ! I m really very gratitude to ur site to give a chance for sharing blog with us.
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.