Google Reader API series
- Part 1 – Programming to the API
- Part 2 – Listing API
- Part 3 – Editing API
In this post I will discuss the listing API for Google reader. This encapsulates all of the calls you’ll need to list items and feeds in various ways. The table below summarizes the API URLs you’ll be using. Simply follow the table from left to right to find your target API handle. Click on a terminal item to see a summary of what it does and how to use it.
Note that for the user items I have found that substituting a dash for the user number works in every case I’ve tested, because a user needs to be logged in with a valid token to use these calls anyway.
If 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 of this series, this part is totally language agnostic.
URL structure: http://www.google.com/…
| /reader/api/0/ |
| unread-count |
| user-info |
| stream/contents/ |
| feed/[feedurl] |
| user/[userNumber]/ |
| label/[labelName] |
| state/com.google/ |
| reading-list |
| starred |
| broadcast |
| created |
unread-count
Gets a list of feeds for the current user and the number of unread items in each feed. Also returns a list of labels that the user has created.
Parameters
- allcomments=[true|false] : I’m not sure what this parameter does, please leave a comment if you figure this one out.
- output=[json|xml] : Determines the format of the response. Default: xml
- ck=[unix timestamp] : Use the current Unix time here, helps Google with caching
- client=[your client] : You can use the default Google client (scroll), but it doesn’t seem to make a difference. Google probably uses this field to gather data on who is accessing the API, so I’d advise using your own unique string to identify your software.
Sample Output (XML)
<number name="max">1000</number>
<list name="unreadcounts">
<object>
<string name="id">feed/http://www.pwop.com/feed.aspx?show=dotnetrocks</string>
<number name="count">3</number>
<number name="newestItemTimestampUsec">1255568508813466</number>
</object>
<object>
<string name="id">feed/http://rssnewsapps.ziffdavis.com/audioblogs/crankygeeks/cg.audio.xml</string>
<number name="count">1</number>
<number name="newestItemTimestampUsec">1255578279704094</number>
</object>
<object>
<string name="id">user/01723985652832499840/label/myLabel</string>
<number name="count">4</number>
<number name="newestItemTimestampUsec"> 1256030778673945 </number>
</object>
</list>
</object>
Sample Output (JSON)
"max":1000,
"unreadcounts":
[
{"id":"feed/http://www.pwop.com/feed.aspx?showu003ddotnetrocks","count":3,"newestItemTimestampUsec":"1255568508813466"},
{"id":"feed/http://rssnewsapps.ziffdavis.com/audioblogs/crankygeeks/cg.audio.xml","count":1,"newestItemTimestampUsec":"1255578279704094"},
{"id":"user/01723985652832499840/label/myLabel","count":4,"newestItemTimestampUsec":"1256030778673945"}
]
}
user-info
Gets information on the current user
Parameters
- ck=[unix timestamp] : Use the current Unix time here, helps Google with caching
- client=[your client] : You can use the default Google client (scroll), but it doesn’t seem to make a difference. Google probably uses this field to gather data on who is accessing the API, so I’d advise using your own unique string to identify your software.
Sample Output
"userId":"01723985652832499840",
"userName":"username",
"userProfileId":"123456789123456789123",
"userEmail":"username@gmail.com",
"isBloggerUser":true,
"signupTimeSec":1234515320
}
feed/[feedurl]
Gets items belonging to a particular feed.
Parameters
- ot=[unix timestamp] : The time from which you want to retrieve items. Only items that have been crawled by Google Reader after this time will be returned.
- r=[d|n|o] : Sort order of item results. d or n gives items in descending date order, o in ascending order.
- xt=[exclude target] : Used to exclude certain items from the feed. For example, using xt=user/-/state/com.google/read will exclude items that the current user has marked as read, or xt=feed/[feedurl] will exclude items from a particular feed (obviously not useful in this request, but xt appears in other listing requests).
- n=[integer] : The maximum number of results to return.
- ck=[unix timestamp] : Use the current Unix time here, helps Google with caching.
- client=[your client] : You can use the default Google client (scroll), but it doesn't seem to make a difference. Google probably uses this field to gather data on who is accessing the API, so I'd advise using your own unique string to identify your software.
Sample Output
"id":"feed/http://astronomycast.com/podcast.xml",
"title":"Astronomy Cast",
"continuation":"CLbwxoSAsZsC",
"self":[{"href":"http://www.google.com/reader/api/0/stream/contents/feed/http://astronomycast.com/podcast.xml?"}],
"alternate":[{"href":"http://www.astronomycast.com","type":"text/html"}],
"updated":1255415774,
"items":[
{
"crawlTimeMsec":"1255415774867",
"id":"tag:google.com,2005:reader/item/bfbd19b1936fcccf",
"categories":
[
"user/01723985652832499840/state/com.google/reading-list",
"user/01723985652832499840/state/com.google/fresh"
],
"title":"Ep. 156: Famous Stars","published":1253491200,
"updated":1253491200,
"enclosure":
[
{
"href":"http://feedproxy.google.com/~r/astronomycast/~5/4TPW83-0h4Y/AstroCast-090921.mp3",
"type":"audio/mpeg","length":"17610000"
}
],
"alternate":
[
{
"href":"http://feedproxy.google.com/~r/astronomycast/~3/89_Ck5HN--w/",
"type":"text/html"
}
],
"mediaGroup":{"content":[{"url":"http://feedproxy.google.com/~r/astronomycast/~5/4TPW83-0h4Y/AstroCast-090921.mp3"}]},
"summary":
{
"direction":"ltr",
"content":"This week we're going to talk about famous stars. But not those boring ..."
},
"author":"info@astronomycast.com (Fraser Cain \u0026 Dr. Pamela Gay)",
"likingUsers":[],
"comments":[],
"annotations":[],
"origin":
{
"streamId":"feed/http://astronomycast.com/podcast.xml",
"title":"Astronomy Cast",
"htmlUrl":"http://www.astronomycast.com"
}
},
{
"crawlTimeMsec":"1255415774867",
"id":"tag:google.com,2005:reader/item/008d8a870f2a9dee",
...
}]
}
Output summary
This request returns an object that contains:
- Feed id string
- Feed title string
- Continuation string - what is this? Leave a comment if you know
- Self - an array of objects which contain a link to this list
- Alternate - an array of objects which contain non-Google links to the feed (usually the author's RSS)
- Updated timestamp
- Items - an array of item objects which contain
- Crawl time - when the item was crawled by Google Reader
- Id - a unique identifier for the item
- Categories - an array of categories to which this item belongs. These appear to be user-specific
- Item title string
- Updated timestamp
- Enclosure - an array of enclosure objects. These are used mostly for podcasts/videocasts, they contain media items enclosed in the feed item. Enclosure items are composed of
- A link to the media file
- An internet media type
- Length, in bytes
- An array of alternate links to the item
- Media Group - appears to be an object storing an array of direct links to the enclosure media
- Summary - an object containing a description of the feed item and a direction (ltr or rtl) for reading. Is this direction a byte ordering hack? Someone let me know in the comments.
- Author string
- An array of users who "like" the item
- An array of comments on the item
- An array of annotations on the item
- An origin object which stores
- The stream id - this is the feed/[feedurl] that Google uses to identify the feed
- The feed title string
- The HTML url to the feed's homepage
label/[labelName]
Lists all items from a given label.
Parameters
- See feed list
Sample Output - See feed list
reading-list
List all items in the user's reading list. This is a list of all of the items from all of the user's feeds, excluding items depending on the xt (exclude target) parameter.
Parameters
- See feed list
Sample Output - See feed list
starred
List all items that the user has marked as "starred"
Parameters
- n=[integer] : The maximum number of results to return.
- ck=[unix timestamp] : Use the current Unix time here, helps Google with caching.
- client=[your client] : You can use the default Google client (scroll), but it doesn't seem to make a difference. Google probably uses this field to gather data on who is accessing the API, so I'd advise using your own unique string to identify your software.
Sample Output - See feed list
broadcast
List all items that the user has chosen to share publicly.
Parameters
- n=[integer] : The maximum number of results to return.
- ck=[unix timestamp] : Use the current Unix time here, helps Google with caching.
- client=[your client] : You can use the default Google client (scroll), but it doesn't seem to make a difference. Google probably uses this field to gather data on who is accessing the API, so I'd advise using your own unique string to identify your software.
Sample Output - See feed list
created
List all notes that the user has created.
Parameters
- n=[integer] : The maximum number of results to return.
- ck=[unix timestamp] : Use the current Unix time here, helps Google with caching.
- client=[your client] : You can use the default Google client (scroll), but it doesn't seem to make a difference. Google probably uses this field to gather data on who is accessing the API, so I'd advise using your own unique string to identify your software.
Sample Output
"id":"user/01723985652832499840/source/com.google/post",
"title":"\"post\" via iamaelephant in Google Reader",
"self":
[
{"href":"http://www.google.com/reader/api/0/stream/contents/user/01723985652832499840/state/com.google/created?n\u003d20\u0026ck\u003d1255661572704\u0026client\u003dscroll"}
],
"author":"iamaelephant",
"updated":1255661564,
"items":
[
{
"crawlTimeMsec":"1255661564095",
"id":"tag:google.com,2005:reader/item/2dc5e875a623fe5e",
"categories":
[
"user/01723985652832499840/source/com.google/post",
"user/01723985652832499840/state/com.google/broadcast",
"user/01723985652832499840/state/com.google/read",
"user/01723985652832499840/state/com.google/fresh"
],
"published":1255661564,
"updated":1255661564,
"related":
[
{"href":"http://www.google.com/reader/shared/01723985652832499840","streamId":"user/01723985652832499840/state/com.google/broadcast"}
],
"alternate":
[
{"href":"http://www.google.com/reader/item/tag:google.com,2005:reader/item/2dc5e875a623fe5e","type":"text/html"}
],
"content":
{
"direction":"ltr",
"content":"this is the note text"
},
"author":"iamaelephant",
"likingUsers":[],
"comments":[],
"annotations":[],
"origin":
{
"streamId":"user/01723985652832499840/source/com.google/post",
"htmlUrl":"http://www.google.com/reader/shared/01723985652832499840"
}
}
]
}
That's an awful lot of information for a little note, but most of it corresponds closely to item information, so if you're unsure of how to interpret a field, have a look at the output summary for the feed/[feedurl] call.
Phew! That mostly does it for the listing methods. There are some other minor calls I've left out for brevity, but most of what you'll want to achieve is in here, and I intend on releasing complete documentation when I have finished my .NET Google Reader API library. In my next post I'll discuss the POST methods so you can start altering the contents of your Google Reader list, star/un-star items, etc. Stay tuned!
By Martin Doms : Using the Google Reader API – Part 1 October 16, 2009 - 4:57 pm
[...] download Fiddler, a great web debugging tool, and watch the HTTP requests as you use Google Reader. Part 2 now available. Posted by Martin Doms on Saturday, August 15, 2009, at 11:35 am. Filed under [...]
By David Green October 21, 2009 - 4:49 am
Great article!
Do you know the API for getting the list of folders (labels)?
By David Green October 21, 2009 - 4:54 am
To answer my own question: it seems that the unread-count call returns feeds and labels together. Labels are passed back with an id as follows:
“user/-/label/Android”
By Martin Doms October 21, 2009 - 7:27 am
Ah yes thanks for reminding me David, I’ll make a note of that in the article.
By kojiishi October 22, 2009 - 2:02 pm
This link
http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI
gives answeres to some of your questions.
Both this and your page are the great resources and are the great help to me. Thanks!
By Pat Murphy November 5, 2009 - 4:04 pm
This is WONDERFUL. You have solved many problems I had with the outdated information found elsewhere on the web. Thank you so much for taking the time to post this!
By Martin Doms November 5, 2009 - 5:29 pm
You’re quite welcome, thanks for visiting
By Martin Doms : Using the Google Reader API – Part 3 January 20, 2010 - 11:09 am
[...] the client argument, which is the same as the client argument seen in all of the API calls in Part II of this series – just use a unique string identifying your own software package if in [...]
By Daniel February 5, 2010 - 10:49 am
Great work, Martin! It’s been a big help. Do you know if it’s possible to grab a user’s profile picture using their google reader UID? I can’t quite figure out the trick. The reader UID does not seem to match to anything found in the google contact data, which was my last resort.
By akaii February 14, 2010 - 1:33 am
What I can’t seem to figure out from your documentation, is how to derive the relationship between folders and feeds.
There are ways to get the items that belong to a particular group/folder/tag/label, and you can check the item data to find out all the groups it belongs to, but… how can you tell which feed belongs to which folder? Considering that the viewer UI for Google Reader lets you sort feeds into folders, there should be a way to do this, shouldn’t there?
Is there a way to either get the folders that a feed belongs to, or to get a list of feeds that belong to a folder?
By Mark March 12, 2010 - 11:10 pm
Brilliant post Martin, thanks for taking the time to do this.
I have one question though; how would I retrieve a list of read posts? I’ve tried using the reading-list and can get it to return all unread posts, but not all read ones.
Any help would be much appreciated.
Mark
By Paul March 24, 2010 - 8:38 pm
Hi
Great tutorial. Does anyone know of a way to overcome the 1000 entry limit for the atom feed for starred items?
Very grateful if someone could point me in the right direction.
Paul
By Gurpreet April 19, 2010 - 5:09 pm
How can I filter (or search) the feed results based on a keyword search, similar to how you search in google reader?
I am able to get the following results from a shared feed that I’ve made public. I actually get the same results with the following 2 URL’s (notice the first has “public” in it.
http://www.google.com/reader/public/atom/user/02147574221729223002/bundle/Fantasy%20Football%20NFL%20Articles?n=10
http://www.google.com/reader/atom/user/02147574221729223002/bundle/Fantasy%20Football%20NFL%20Articles?n=10
I wish to filter the results above based on a keyword.
When I search a folder using the search form in reader, the url shows as:
http://www.google.com/reader/view/#search/Roethlisberger//user%2F02147574221729223002%2Flabel%2FSports
If I change the reader tag to “atom”, the results are incorrect.
Thoughts?
-Gurpreet
By Justin May 7, 2010 - 1:01 pm
This is the response I get from google when trying the feed/[FEEDURL]/ API:
{“direction”:”ltr”,”id”:”feed/http://arstechnica.com/index.rssx”,”title”:”Ars Technica”,”description”:”The Art of Technology”,”self”:[{"href":"http://www.google.com/reader/api/0/stream/contents/feed/http://arstechnica.com/index.rssx?ot\u003d1273193172856169\u0026r\u003dn\u0026xt\u003duser/-/state/com.google/read\u0026n\u003d4\u0026ck\u003d1273193873\u0026client\u003diPadReader"}],”alternate”:[{"href":"http://arstechnica.com/index.php","type":"text/html"}],”updated”:1273193873,”items”:[]}
They look like key/value pairs but it’s plain text and won’t encode into a dictionary. I’m using Objective-C and I’m not sure where to go from here. So far I’ve been able to parse the XML response for unread items, but parsing the plain-text doesn’t look feasible. What is your practice?
Thanks,
Justin
By @Jason May 8, 2010 - 11:57 am
That is JSON.
There are plenty of JSON libraries for Objective-C.
By Oops May 8, 2010 - 11:57 am
I meant @Justin.
By Martin Doms May 11, 2010 - 6:08 pm
Correct, that’s JSON (Javascript Object Notation), same as in most of my examples. The API used to offer more XML responses but it looks like Google is moving almost exclusively to JSON. This is probably because it’s a more concise language, so it works better over the wire. I’m personally more of an XML fan but there are plenty of libraries for both in most languages.
By Jon May 18, 2010 - 9:58 am
Has anyone determined whether the information used to create Google Reader’s “Trends” view is exposed somewhere? The feed items have “published” and “updated” timestamps, but I wonder if there is a way to grab a timestamp from when the item was actually read or marked as read.
By Martin Doms May 18, 2010 - 11:05 am
It looks like Trends uses the API call GET /reader/trends?tz=720&ck=[unixTime]&client=[client] but it returns formatted HTML data, not JSON or XML. I don’t know why on Earth they would do this, it seems contrary to Google’s whole web philosophy.
By Andy June 30, 2010 - 9:19 pm
Martin
I’ve discovered some inconsistency with the feed/[feedurl] API request.
In your example the items contain:
“mediaGroup”:{“content”:[{"url":"http://feedproxy.google.com/~r/astronomycast/~5/4TPW83-0h4Y/AstroCast-090921.mp3"}]},
“summary”:
{
“direction”:”ltr”,
“content”:”This week we’re going to talk about famous stars. But not those boring …”
},
“author”:”info@astronomycast.com (Fraser Cain \u0026 Dr. Pamela Gay)”,
This structure is correct for some of the feeds but there are others that look slightly different. That is the “summary” for the item actually looks like this:
“content”:
{
“direction”:”ltr”,
“content”:”** ESCAPED HTML APPEARS HERE FOR THE WHOLE POST **”
},
I haven’t identified why this is different, one reason could be that I’m requesting feeds that I’ve not subscribed to in Reader.
Additionally, depending on the feed type, podcast or blogroll some elements, such as “mediaGroup”, are included and some aren’t.
By Enrico July 21, 2010 - 3:09 am
Martin Doms, You seriously rock.
1 thing I couldn’t find in your posts, and just guessed and found on my own is the subscriptions list, you can access it through http://www.google.com/reader/api/0/subscription/list
Thanks a lot for these posts.
By Mackenzie Zastrow July 27, 2010 - 9:10 pm
@Andy
I had the same problem, actually took me a while to figure out why my app wasn’t working (was using item.content.content, instead of summary). My current guess based on various feeds I’ve tested, is that if the feed offers full content, then it returns it as content… otherwise it returns it as summary.
By Troy October 28, 2010 - 4:57 pm
The continuation string is used for getting the next set of items in the feed. Set “&c=” to use it when fetching items.
For example, say you get the first 50 items from a user’s feed:
http://www.google.com/reader/api/0/stream/contents/user/-/state/com.google/reading-list?n=50
Say the continuation string is “abc”. To get the next 50 items (items 50 – 100), just add the continuation string to the same URL:
http://www.google.com/reader/api/0/stream/contents/user/-/state/com.google/reading-list?n=50&c=abc
By philwilson.org » Blog Archive » Getting your words to my kindle January 18, 2011 - 11:08 am
[...] When I star an item in google reader, it gets automatically added to scuttle tagged "readme" [...]
By 利用Google Reader API 抓全部RSS歷史資料 « Richard S.R. Han April 14, 2011 - 4:14 am
[...] 以上轉貼 Using the Google Reader API – Part 2 [...]