Google Reader API series
- Part 1 – Programming to the API
- Part 2 – Listing API
- Part 3 – Editing API
Google have never officially released API documentation for Google Reader, so this information is unofficial and subject to change.
When I first started looking around for API docs to interface with Google Reader, this site seemed to be pretty much the only resource available. Unfortunately a lot of the information in that document is outdated, so I set about trying to figure out the API myself, with some success.
To interface with Google reader, you’ll need to collect the following things from their authentication system:
- SID – A session ID, which remains valid until you log out
- Token – Similar to a session ID, but expires quickly. Used to access direct API calls
- Cookie – An ordinary cookie that uses your SID to authenticate your session on API calls
The code samples I’m using will be in C#, but should be easily translatable to any language.
To get an SID, we send a GET request to https://www.google.com/accounts/ClientLogin with arguments service=reader&Email=[your Google username]&Passwd=[your Google password]
This will return some text with key=value pairs for LSID, SID and User. SID is the only part of this we need, so use your string library to grab this information.
Now that we have an SID we need a token. We send a GET request to http://www.google.com/reader/api/0/token with a cookie we generate from the SID. The cookie information is
- Name: SID
- Value: [your SID]
- Path: /
- Domain: .google.com
This request returns just the token text.
So here is the code I wrote for getting SID and token:
using System.IO;
namespace GoogleReader.NET
{
public class GoogleReader
{
private string _sid = null;
private string _token = null;
private Cookie _cookie = null;
private string _username;
private string _password;
public GoogleReader(string username, string password)
{
_username = username;
_password = password;
connect();
}
private bool connect()
{
getToken();
return _token != null;
}
private void getToken()
{
getSid();
_cookie = new Cookie("SID", _sid, "/", ".google.com");
string url = "http://www.google.com/reader/api/0/token";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
req.CookieContainer = new CookieContainer();
req.CookieContainer.Add(_cookie);
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
using (var stream = response.GetResponseStream())
{
StreamReader r = new StreamReader(stream);
_token = r.ReadToEnd();
}
}
private void getSid()
{
string requestUrl = string.Format
("https://www.google.com/accounts/ClientLogin?service=reader&Email={0}&Passwd={1}",
_username, _password);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requestUrl);
req.Method = "GET";
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
using (var stream = response.GetResponseStream())
{
StreamReader r = new StreamReader(stream);
string resp = r.ReadToEnd();
int indexSid = resp.IndexOf("SID=") + 4;
int indexLsid = resp.IndexOf("LSID=");
_sid = resp.Substring(indexSid, indexLsid - 5);
}
}
}
}
From here were can make interface calls (I plan to document the complete set of API calls in the very near future, but for now I’ll give a couple of examples). To add a subscription, make an HTTP POST to http://www.google.com/reader/api/0/subscription/quickadd?client=scroll with POST arguments quickadd=[url of feed]&T=[your token] and don’t forget to include your cookie. I wrote a couple of quick helper methods for making POST and GET calls first:
{
string url = string.Format("{0}?{1}", requestUrl, getArgs);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(_cookie);
try
{
return (HttpWebResponse)request.GetResponse();
}
catch
{
// handle error
return null;
}
}
private HttpWebResponse httpPost(string requestUrl, string postArgs)
{
byte[] buffer = Encoding.GetEncoding(1252).GetBytes(postArgs);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
request.Method = "POST";
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(_cookie);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = buffer.Length;
Stream PostData = request.GetRequestStream();
PostData.Write(buffer, 0, buffer.Length);
PostData.Close();
try
{
return (HttpWebResponse)request.GetResponse();
}
catch
{
//handle error
return null;
}
}
Now for the add subscription code:
{
string data = String.Format("quickadd={0}&T={1}", feedUrl, _token);
string url = "http://www.google.com/reader/api/0/subscription/quickadd?client=scroll";
HttpWebResponse response = httpPost(url, data);
if (response == null) return false;
return true;
}
We can add a label to a feed by POSTING to http://www.google.com/reader/api/0/subscription/edit?client=scroll with arguments a=user/-/label/[new label]&s=feed/[feed url]&ac=edit&T=[token] like so:
{
string data = String.Format
("a=user/-/label/{0}&s=feed/{1}&ac=edit&T={2}", label, feedUrl, _token);
string url = "http://www.google.com/reader/api/0/subscription/edit?client=scroll";
HttpWebResponse response = httpPost(url, data);
if (response == null) return false;
return true;
}
There are of course listing methods for getting feeds. So far I’ve only been able to figure out how to get feed information in JSON format, but if anyone knows how to grab XML data please leave a comment. To list items we send a GET request to http://www.google.com/reader/api/0/stream/contents/user/-/state/com.google/reading-list?ck=[current UNIX time] . Of course there are many more otpional arguments for all of these methods, which I will be documenting. Here’s the list code:
{
string url = string.Format
("http://www.google.com/reader/api/0/stream/contents/user/-/" +
"state/com.google/reading-list");
string args = string.Format
("ck={0}", getUnixTimeNow());
HttpWebResponse response = httpGet(url, args);
Stream str = response.GetResponseStream();
StreamReader sr = new StreamReader(str);
string s = sr.ReadToEnd();
// Handle JSON data in s
sr.Close();
}
getUnixTimeNow() is a small helper method I wrote for getting the current Unix time:
{
TimeSpan ts = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0));
long unixTime = (long)ts.TotalSeconds;
return unixTime;
}
This has been a small taste of what’s to come as I work my way through this API. Stay tuned for more. If you want to get hacking on it yourself, the easiest way is to download Fiddler, a great web debugging tool, and watch the HTTP requests as you use Google Reader.
Part 2 now available.
{ 28 } Comments
Hey, thanks for all of this great information. Are you still able to get your tag editing functions to work? I’ve been working on a reader client and have had a pretty smooth time other than with marking items with tags such as “read” and “starred.” Even though I seem to be replicating the necessary POST data exactly, I always get an “invalid stream name” message. Since there’s so little information out there on the unofficial API, I thought I’d ask for your thoughts. Thanks again!
Great article! Thanks much.
I’ve been trying to rewrite your code in JavaScript, so JSON format is perfect for me.
But I can’t get the getToken to work. BTW, I don’t have to worry about same domain policy.
So I parse the strings from the first request, get the SID, save it to a cookie and then request the token. But this one doesn’t go through. Any thoughts why this may be?
Never mind, I was sending the wrong cookie, should have been
document.cookie = “Name=SID;SID=#{SID};Domain=.google.com;Path=/;Expires=160000000000″;
Nope. I was mistaken. That didn’t help. I sent headers in my previous request, and all subsequent worked for a while, so I assumed cookie worked, while it actually didn’t.
So the question stays.
Hi Vitaly, sorry for my late reply but I’ve been insanely busy at university
If the request is working intermittently, have you tried renewing the token and creating a new cookie? Those tokens will expire in time. If you find a solution I’d be interested to hear it.
Hey, thanks for the more recent write up compared with that Google Code wiki. It definitely helped! I managed to get my own version working in Python.
http://github.com/askedrelic/Google-Reader-API
Just tried the first code segment (getting the sid and token)… i am getting a 403 error from the server… any ideas?
The sid is retrieved, but the token get doesn’t work.
This code was working the other day.
Just like JimBob, my code was working fine until something happened during the last week or so, it’s getting the SID but when requesting the token I get a 403 forbidden error. Anyone knows what changed and how to fix it?
Hi boys, if you are getting the 403 forbidden error is because this authentication method (SID) has been deprecated by Google. SID parameter is no longer used to let the user to authenticate himself. You have to use Auth parameter. This parameter is included into the response when you send your first request with the username and password. Look for GoogleLogin header parameter.
Hope this can help you.
HI, I’m wondering if you’ve updated this for the new OAuth process? I’m having difficulty getting functionality to work to retrieve the token from reader/api/0/token (although everything else works just fine).
Hi guys, sorry I simply haven’t had time to update the article to reflect the API changes. In the comments for part 3 ( http://blog.martindoms.com/2010/01/20/using-the-google-reader-api-part-3/ ) Andy kindly offered a solution which I intend to incorporate into this article very soon. Thanks for keeping me updated.
Hello Martin,
You’ve said:
“Hi guys, sorry I simply haven’t had time to update the article to reflect the API changes. In the comments for part 3 ( http://blog.martindoms.com/2010/01/20/using-the-google-reader-api-part-3/ ) Andy kindly offered a solution which I intend to incorporate into this article very soon. Thanks for keeping me updated.”
Any news?:)
Bye,
I actually spent a couple of hours on Tuesday trying to get my head around Google’s new OAuth system, but found it is limited in some very frustrating ways that preclude building a proper Google Reader API library. I’ll keep exploring to see what I can come up with. In the mean time Andy’s solution in part 3 will work, but I suspect not for very long. Google looks to be going OAuth for everything.
What do you think about http://code.google.com/p/devdefined-tools/wiki/OAuth?
If i understand, the authenfication processes will be changed ?
What about the part 2 (Part 2 – Listing API ) of your post?
Thanks,
hello,
from the code above, i am able to get the sid. but as i go to fetch the token with the sid it gives following error
“The remote server returned an error: (403) Forbidden”
can anyone suggest what am i suppose to do??
The article has helped alot to me, thankyou v much.
but me still stuck !!
cannot get feeds from the account which has only googlereader but no gmail account!!
I can get the feeds from the account having both gmail and googlreader but not from googlreader
Plz help!!
hi all,
i get a 403 error
function : gettoken
line : HttpWebResponse response = (HttpWebResponse)req.GetResponse();
if you have any idea
thx a lot
Do not, for one repulse, give up the purpose that you resolved to effect.
The man with a new idea is a crank until the idea succeeds.
I am also getting a 403 error. First you need to escaped any symbols in your username and password fields, otherwise you wont be able to get an SID, but I when the code tries to get a token with the SID that was geenrated, I get a 403 error on the response. Has anyone resolved this issue?
Dont think this works.
See http://groups.google.com/group/fougrapi/browse_thread/thread/e331f37f7f126c00 with the authentication changes
i want this same fuctionality in java. m not able to convert this code in java as i m totally new in field.
i want java code in core java only because i want to use this code in android.
That’s a great doc that you wrote ! Thanks to your work, Andy’s comment to support oAuth, and the “unofficial Google Reader API for Java” project, I’ve written a small Google Reader C# API using Json.Net to serialize/deserialize to proper classes.
For those who may be interested, code is available here: https://sourceforge.net/projects/greadi/
Below is new get token code:
private void getToken()
{
getSid();
web_cookie=new Cookie(“SID”, _sid, “/”, “.google.com”);
web_cookie.Expires = new DateTime(2013, 12, 31);
string url = “http://www.google.com/reader/api/0/token”;
//Result.InnerText +=”header is”+strheader;
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = “GET”;
req.ContentType=”application/x-www-form-urlencoded”;
req.Headers.Add(string.Format(“Authorization: GoogleLogin auth={0}”, _auth));
try{
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
using (var stream = response.GetResponseStream())
{
StreamReader r = new StreamReader(stream);
_token = r.ReadToEnd();
Result.InnerText+=”Token”+_token.ToString();
}
}
catch
{
Result.InnerText=”Fail to get token!”;
}
}
Hi there thanks for the great work, although im having trouble adding a feed. once ive connected, i seem to be getting a 401 exception unauthorized when trying to add a feed. any ideas?
thanks
I’m trying to implement a method that will allow a user to input the url of the feed he would like to subscribe to using the methods above (AddFeed and httpPost). however, false is always being returned. has there been any changes in the api that maybe effect the url that must be inputted for the subscription please?
thanks
Hi,
It is great to have such a detailed article, i am using it to retrieve all articles i have subscribed. but what i want to do is, read all articles which are not read yet, once i read them or parse them i want to mark it as read so that in next iteration of reading articles it wont show the once i have read.
Please let me know how i can achieve this goal using c# thanks!
{ 17 } Trackbacks
[...] Martin Doms : Using the Google Reader API – Part 1 [...]
[...] this is your first foray into using the Google Reader API then you’ll want to read my previous post which describes how to acquire a valid token and cookie, and make calls to the API. Unlike part 1 [...]
[...] Part I I went over how to program for the HTTP POST requests so for now I’ll just go over the API. [...]
[...] no official API for Google Reader yet, but many developers have begun using an unofficial API – which has been documented by developers using reverse-engineering. It was thought that we [...]
[...] the API for that service yet. Yuck. But there are a couple of people out there (like here and here) who have picked it apart using fiddler or some such [...]
[...] the best tutorial I could find online (and the one recommended by Stack Overflow users) was written for C# … WordPress runs in PHP. [...]
[...] Google Reader, or any RSS reader. Google Reader has an API, which developers could utilize to create to-print functionality [...]
[...] Google Reader does not, to my knowledge, have a public API. I got all the required information from Martin Doms. The examples have been translated to PHP. I don’t claim that this code is necessarily all [...]
[...] Martin Doms : Using the Google Reader API – Part 1 [...]
Life goes on…
In three words I can sum up all I have learned about life: It goes on….
[...] it to exactly the first url you use like this &c=CLDFmdS-mpYCcheck this out for more info. http://blog.martindoms.com/2009/…Insert a dynamic date hereCannot add comment at this [...]
[...] believe it uses the undocumented API of Google Reader. Information about the API can be found here: http://blog.martindoms.com/2009/... or here: http://stackoverflow.com/questio…Insert a dynamic date hereView All 0 CommentsCannot add [...]
[...] 这两天在给Ninayan添加Google Reader支持。Google Reader是Google众多服务中少数几个不开放官方API的服务之一,但仍然有众多第三方的客户端或官网增强辅助工具出现。好在有几个很好的人,把他们研究Google Reader的成果公布出来了,我主要参考这篇和这篇文档,再加上自己通过抓包工具观察官网的行为,现在基本已经得到实现一个Google Reader客户端所需要的所有资料。 不过现在有点头疼的是,要把Google Reader强塞到已经比较完整紧凑的架构中去,有不少需要调整的地方。比如新增一种账号类型,这种类型的账号就不同于以往的SNS账号,总之整个继承体系都被我修改过了。然后是界面交互的部分,也需要做不少的设计。 还有一点感受是,这个API不知道是不是Google本身的风格如此(我没用过Google其他服务公开的API,所以没有经验),还是说根本就没为第三方开发好好设计过,总感觉不太好用,虽然功能上都能实现,但不太方便。 [...]
[...] [2] Martin Doms : Using the Google Reader API – Part 1 [...]
[...] Martin Doms [...]
[...] Using the Google Reader API [...]
[...] 그러다가 찾은 사이트. http://blog.martindoms.com/2009/08/15/using-the-google-reader-api-part-1/ [...]
Post a Comment