My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
GoogleReaderAPI  

Document-API
Updated Feb 4, 2010 by gissehel@gmail.com

Note : This document is totally unofficial. You should not rely on anything on this document is you need an exact information. Google Reader API has not officially been released. This document has been made mainly by reverse engeneering the protocol.

Requierements

Google Reader API require :

  • http client
  • GET and POST support
  • Cookie support
  • https client

https is only required for identification with Google to get the string called SID. You can rely on an external tool to connect with https and give you SID. If you do, https won't be required.

Cookie support is only required to pass to all pages the current SID, proof of identification. If are able to change add lines in headers, cookie support is not required anymore.

Google Reader API may require :

  • http client
  • GET and POST support
  • external tool to get SID (using https)
  • putting SID into header

Glossary

  • SID : Session ID. SID is generated each time you login to Google (any service). The SID is valid until you logout.
  • user ID : a 20 digits string used by google reader to identify a user. You don't really need to know it. You can always do things a way that user ID is not needed. Usually, when you need that information, just replace it by - and the user ID for current logged user will be used. The user ID never change for a user.
  • token : A token is a special 57 chars string that is used like a session identification, but that expire rather quickly. You usaully need a token for direct api calls that change informations. The token is valid for few minutes/hours. If API call fail (doesn't return OK), you just have to get antoher token.
  • client ID : A string that identify the client used. I suppose it's for logging/stat purpose, or perhaps to make some adjustement for some clients, but I doubt so. old GoogleReader interface use 'lens', new one use 'scroll'. The writer of this document use 'contact:name-at-host' for interactive test, and use string like 'pyrfeed/0.5.0' for the software pyrfeed in version 0.5.0 (like classical identification strings for unix softwares).
  • item/entry : Sometimes called item, sometimes called entry, the item is the base element of a feed. An item usally contain a text, a title and a link, but can contain other properties. An RSS/Atom aggregator aggregates items. (Note: item is the RSS term, while entry is the Atom term).

Identification

Note : According to Mihai Parparita in Google Reader Support Group ( http://groups.google.com/group/Google-Labs-Reader/browse_frm/thread/73a0aed708bcd005 ), "Authentication is one of the reason why the API hasn't been released yet". You should expect big changes before Google Reader release official API.

To login, you need to post with https on https://www.google.com/accounts/ClientLogin with the following POST parameters :

POST parameter name POST parameter value
service 'reader' (!)
Email your login
Passwd your password
source your client string identification (!)
continue 'http://www.google.com/' (!)

Of course, your login and your password are login and password you usually use to identify interactively to Google.

(!) : Those parameters are said to be optional ( http://code.google.com/p/pyrfeed/issues/detail?id=10 ). I didn't really tested. It's just how "browsers" identifies themselfs. Note that I consider source and service as a being informative parameters for google, so I feel like I need to provide them, event if they are not required. Note that I have no idea about what Google or the Google Reader team really think about that. Perhaps they prefer "nothing but a crafted information", or perhaps they don't care. Who knows...

There is no official rule your client string identification, see client ID in glossary for more informations.

The POST action will return you a text file, containing lines of the form :

key=value

You need to extract the value for the key named SID

You then have to add yourself a cookie (well, it look like Google doesn't add it itself) with the following properties :

name SID
domain .google.com
path /
expires 1600000000

If you don't have a http client API that support cookies, you can just add header lines that simulate this cookie in all other requests. This should be the only thing for which cookies are really needed.

The three layers for feed aggregators

When you're writting a feed aggregator, you need to write three different layers :

  • Layer 1 : The layer that parse feeds. It's not the easiest job. "But, it's just xml, it should be easy". It's not. It's just xml. It's just 10 differents and incompatible xml formats (9 RSS formats according to Mark Pilgrim and 1 Atom format). You also perhaps need to understand all non standard feeds that mix some features from differents standards.
  • Layer 2 : The database layer. Once you've parsed your feed, you need to store it in a database, and and interesting things like "items read", etc.
  • Layer 3 : The user interface.

Google Reader offer in fact acces to layer 1 only, or layer 1+2 or layer 1+2+3.

You can have acces to layer 1 only. Feeds are parsed by Google Reader, and Google Reader give you access to a new Atom feed that contains same data as the original feed, but always with the same output format : Atom.

You can have acces to layer 1+2. This documents purpose is about how to acces to layer 1+2 from Google Reader in order to create your own layer 3.

Of course, you have access to layer 1+2+3 because it's Google Reader's main product.

Url scheme

Except for identification process, all Google Reader url ressources start with http://www.google.com/reader/. We'll explain here direct subspaces of thoses urls.

URL prefix Will be refered as, in this document Description
http://www.google.com/reader/atom/ /atom/ All urls starting by this prefix return atom feeds. It's the (only?) way to acces to feed contents. This is the way to access layer 1 and layer 1+2.
http://www.google.com/reader/api/0/ /api/0/ This is the main API entry point. It's used for items/feeds modifications, like adding a Star, deleting a tag, etc. For those modification services, it return either "OK" or "". It's also used to consult some setting lists like list of feeds, list of tags, list of unread counts by feeds/tags, etc. For those read services, it returns an "object" that can be either json or xml that look like json. This is a layer 2 only zone.
http://www.google.com/reader/view/ /view/ All AJAX interface is done by /view/ urls. AJAX code use /atom/ and /api/0/ as sublayers to do the job. This is the way to access layer 3.
http://www.google.com/reader/shared/ /shared/ All shared pages use this prefix. You obviously don't need authentification to use those pages.
http://www.google.com/reader/settings/ /settings/ The AJAX application to configure all settings. Mainly manipulate informations from /api/0/. This part of layer 3.

Atom set of items

this section is about urls starting by http://www.google.com/reader/atom/

The Google Reader database contains a huge number of items. Some of them are in your reading list (understand, they are accessible in Google Reader for your account in "All items" section, and in your feeds/tags).

The only way to get information related to an item is to "query an atom set of items" that contain this item.

All items are or were included in feeds. One way to query items is to query the original feed.

Item are also associated to categories. tags/labels are categories, but also the "read" state is also a category.

Antoher way to query items is to query all items that are associated to a category.

Set of items suffix Description
feed/ url of a feed The url to query a specific feed. It's Google Reader way to access to layer 1 only. Note : This service is not related to an account and can be access without registration.
user/ user ID/ label/ label name This is the suffix to access to all items with a specific label
user/ user ID/ state/com.google/ state This is the suffix to access to all items with a specific state like read, starred, etc.

You can use - as your user ID, it will use the user ID for your currently identified account.

State name State meaning
read A read item will have the state read
kept-unread Once you've clicked on "keep unread", an item will have the state kept-unread
fresh When a new item of one of your feeds arrive, it's labeled as fresh. When (need to find what remove fresh label), the fresh label disappear.
starred When your mark an item with a star, you set it's starred state
broadcast When your mark an item as being public, you set it's broadcast state
reading-list All you items are flagged with the reading-list state. To see all your items, just ask for items in the state reading-list
tracking-body-link-used Set if you ever clicked on a link in the description of the item.
tracking-emailed Set if you ever emailed the item to someone.
tracking-item-link-used Set if you ever clicked on a link in the description of the item.
tracking-kept-unread Set if you ever mark your read item as unread.

If you need to query a set of items in an atom format, just query http://www.google.com/reader/atom/ followed by the set of items suffix.

For exemple, if you want to acces to Google Reader's rewritting of the feed http://xkcd.com/rss.xml , you can query http://www.google.com/reader/atom/feed/http://xkcd.com/rss.xml . This can be done whether you are identified or not. If you want to query all your last read items, you can query http://www.google.com/reader/atom/user/-/state/com.google/read .

Each atom set contains by default 20 items. You can change that, and other behaviour by adding parameters to the query.

GET parameter name python Google Reader API name parameter value
n count Number of items returns in a set of items (default 20)
client client The default client name (see client in glossary)
r order By default, items starts now, and go back time. You can change that by specifying this key to the value o (default value is d)
ot start_time The time (unix time, number of seconds from January 1st, 1970 00:00 UTC) from which to start to get items. Only works for order r=o mode. If the time is older than one month ago, one month ago will be used instead.
ck timestamp current time stamp, probably used as a quick hack to be sure that cache won't be triggered.
xt exclude_target another set of items suffix, to be excluded from the query. For exemple, you can query all items from a feed that are not flagged as read. This value start with feed/ or user/, not with !http:// or www
c continuation a string used for continuation process. Each feed return not all items, but only a certain number of items. You'll find in the atom feed (under the name gr:continuation) a string called continuation. Just add that string as argument for this parameter, and you'll retrieve next items.

Note : continuation has no meaning, it's just a string to help you find next items. You should not rely on its value to do anything else than that (even if this document will explain how that continuation is generated).

Exemple :

All the 17 first items items from xkcd.com main feed that are not read can be found on the url : http://www.google.com/reader/atom/feed/http://xkcd.com/rss.xml?n=17&ck=1169900000&xt=user/-/state/com.google/read

API

this section is about urls starting by http://www.google.com/reader/api/0/

There are two knids of API commands:

  • edit commands
  • list commands

The number 0 is probably the API version number. Using that number, it will allow Google Reader to change API while stile maintaining an old API for quite some time.

Edit API

To edit anything in the Google Reader database, you need a token (see glossary). To get a token, just go to http://www.google.com/reader/api/0/token . This url will return a string containing 57 chars. It's the token.

The token url takes optional GET arguments:

GET parameter name python Google Reader API name parameter value
ck timestamp current time stamp, probably used as a quick hack to be sure that cache won't be triggered.
client client The default client name (see client in glossary)

All edit commands use POST to retrieve information (note that GET won't work) but they also take a GET argument.

GET parameter name python Google Reader API name parameter value
client client The default client name (see client in glossary)

All edit commands will return either an empty string if failled, either the string "OK". If failed, your token has perhaps expires. You can just try to get a new token. If it still doesn't return OK, it's a failure.

Table of POST aguments for the subscription/edit edit call.

API call function POST parameter name python Google Reader API name parameter value
subscription/edit
s feed The subscription feed name, in the form feed/...
t title The subscription title, used when adding a new subscription or when changing a subscription name
a add A label to add (a label on a subscription is called a folder) in the form user/...
r remove A label to remove (a label on a subscription is called a folder) in the form user/...
ac action The actions to do. Know values are edit (to add/remove label/forlder to a feed), 'subscribe', 'unsubscribe'
token token The mandatory up to date token
tag/edit
s feed The tag/folder name seen as a feed
pub public A boolean string true or false. When true, the tag/folder will become public. When false, the tag/folder will stop being public.
token token The mandatory up to date token
edit-tag
i entry The item/entry to edit, in the form tag:google.com,2005:reader/item/... ( it's the xml id of the entry tag of the atom feed)
a add A label/state to add (a label on an item/entry is called a tag) in the form user/...
r remove A label/state to remove (a label on an item/entry is called a tag) in the form user/...
ac action The actions to do. Know value is edit (to add/remove label/forlder to a feed)
token token The mandatory up to date token
disable-tag
s feed The tag/folder name seen as a feed
ac action The actions to do. Know value is disable-tags (to remove a tag/folder)
token token The mandatory up to date token

Exemples :

To subscribe a new feed (for exemple http://xkcd.com/rss.xml), you can call:

http://www.google.com/reader/api/0/subscription/edit?client=contact:myname-at-gmail
with POST arguments : s=http://xkcd.com/rss.xml&ac=subscribe&token=here-put-a-valid-token
To add that feed in a folder (for exemple "comics"), you can call:
http://www.google.com/reader/api/0/subscription/edit?client=contact:myname-at-gmail
with POST arguments : s=http://xkcd.com/rss.xml&ac=edit&a=user/-/label/comics&token=here-put-a-valid-token

Open questions that needs to be fixed :

  • Are tag/edit and edit-tag just aliases ?
  • Why does removing a tag/folder doesn't take an action while every other calls take actions ?
  • Why is there several urls, it seems redundant with the action parameter ?

List API

All those calls can be used with GET requests.

API call function GET parameter name python Google Reader API name parameter value/API call description
tag/list Get the tag list and shared status for each tag.
output output The format of the returned output. may be 'json' or 'xml'
ck timestamp current time stamp, probably used as a quick hack to be sure that cache won't be triggered.
client client The default client name (see client in glossary)
subscription/list Get the subscription list and shared status for each tag.
output output The format of the returned output. may be 'json' or 'xml'
ck timestamp current time stamp, probably used as a quick hack to be sure that cache won't be triggered.
client client The default client name (see client in glossary)
preference/list Get the preference list (configuration of the account for GoogleReader).
output output The format of the returned output. may be 'json' or 'xml'
ck timestamp current time stamp, probably used as a quick hack to be sure that cache won't be triggered.
client client The default client name (see client in glossary)
unread-count Get all the information about where are located (in term of subscriptions and tags/folders) the unread items.
all all 'true' if whole subscriptions/tags are required. (TODO: Needs to check other values)
output output The format of the returned output. may be 'json' or 'xml'
ck timestamp current time stamp, probably used as a quick hack to be sure that cache won't be triggered.
client client The default client name (see client in glossary)

Viewer

this section is about urls starting by http://www.google.com/reader/view/

All url starting by http://www.google.com/reader/view/ are html pages that use AJAX code to show atom feeds found from http://www.google.com/reader/atom/.

You can append to the base url any set of items suffix to view only that set of items. Note however that GET parameters are not valid (in fact are ignored) for those urls.

You can browse directly all your items labeled "important" by going to http://www.google.com/reader/view/user/-/label/important

You can browse directly all items from xkcd main feed by going to http://www.google.com/reader/view/feed/http://xkcd.com/rss.xml even if you didn't subscribed to it (in which case there will be a button "Subscribe" on the top of the screen). Note however that if you're not identified, you'll browse the feed using the old interface (lens) and not the new on (scroll).

Misc

TODO: Text needs to be written TODO: mainly /share/

References

Comment by pricemon...@gmail.com, Jul 15, 2007

The api to mark the item as 'read' has slightly changed as on July 15, 2007. The name of the post parameter for token is 'T' and not 'token'.

Also to mark the item as 'read', you would need to pass parameter 'ac' with value 'edit-tags' and 's' with value of the feed url containing the item.

for e.g.

$req = POST $baseUrl, [
i => $guid, s => $url, a => 'user/-/state/com.google/read', ac => 'edit-tags', T => $token
];

Comment by pricemon...@gmail.com, Jul 15, 2007

The api to mark the item as 'read' has slightly changed as on July 15, 2007. The name of the post parameter for token is 'T' and not 'token'.

Also to mark the item as 'read', you would need to pass parameter 'ac' with value 'edit-tags' and 's' with value of the feed url containing the item.

for e.g.

$req = POST $baseUrl, [
i => $guid, s => $url, a => 'user/-/state/com.google/read', ac => 'edit-tags', T => $token
];

Comment by pricemon...@gmail.com, Jul 15, 2007

The api to mark the item as 'read' has slightly changed as on July 15, 2007. The name of the post parameter for token is 'T' and not 'token'.

Also to mark the item as 'read', you would need to pass parameter 'ac' with value 'edit-tags' and 's' with value of the feed url containing the item.

for e.g.

$req = POST $baseUrl, [
i => $guid, s => $url, a => 'user/-/state/com.google/read', ac => 'edit-tags', T => $token
];

Comment by pricemon...@gmail.com, Jul 15, 2007

The api to mark the item as 'read' has slightly changed as on July 15, 2007. The name of the post parameter for token is 'T' and not 'token'.

Also to mark the item as 'read', you would need to pass parameter 'ac' with value 'edit-tags' and 's' with value of the feed url containing the item.

for e.g.

$req = POST $baseUrl, [
i => $guid, s => $url, a => 'user/-/state/com.google/read', ac => 'edit-tags', T => $token
];

Comment by fitzgera...@gmail.com, Sep 5, 2007

Thanks for posting this! Seems like the API has changed a bit since Niall Kennedy's original article.

In playing with the API tonight, it seems like you have to be logged on in order to get any feeds from GReader...even the http://www.google.com/reader/atom/feed/http://xkcd.com/rss.xml link above seems to require that you are logged in. Has anyone else noticed the same thing?

Comment by 127.0.0.69, Sep 12, 2007

From the doc, I can't find a way to get the list of feeds subscribed... is that possible?

Comment by 127.0.0.69, Sep 12, 2007

From the doc, I can't find a way to get the list of feeds subscribed... is that possible?

Comment by 127.0.0.69, Sep 12, 2007

From the doc, I can't find a way to get the list of feeds subscribed... is that possible?

Comment by 127.0.0.69, Sep 12, 2007

From the doc, I can't find a way to get the list of feeds subscribed... is that possible?

Comment by 127.0.0.69, Sep 13, 2007

Sorry for duplicates comments. System bug.

I now know how to get the list of feeds subscribed... It was changed to: http://www.google.com/reader/api/0/subscription/list

The list of unread items count was also changed to: http://www.google.com/reader/api/0/unread-count?all=true

Unfortunately I still can't find a way to get the next 20 items after the first fetch... Maybe is through continuation POST var?

Comment by 127.0.0.69, Sep 13, 2007

Sorry for duplicates comments. System bug.

I now know how to get the list of feeds subscribed... It was changed to: http://www.google.com/reader/api/0/subscription/list

The list of unread items count was also changed to: http://www.google.com/reader/api/0/unread-count?all=true

Unfortunately I still can't find a way to get the next 20 items after the first fetch... Maybe is through continuation POST var?

Comment by 127.0.0.69, Sep 13, 2007

I seem to be misunderstanding some stuff... I checked, the continuation is used to get the next items (just like said in the doc). Thanks for the wiki.

Comment by gray...@gmail.com, Sep 14, 2007

note that ck (timestamp) is the standard unix timestamp, with the addition of milliseconds, so instead of 1189800875, it would be 1189800875112

Comment by gray...@gmail.com, Sep 14, 2007

for atom items, the get parameter r (sort order) can also have the value "n" which seems to be a synonym for "d". so "o" is oldest first, "n" is newest first, "d" is descending.

Comment by benamor....@gmail.com, Sep 20, 2007

Is there a way to filter a feed searching for a word? something like:

http://www.google.com/reader/view/user/-/label/important/#search/find_my_word

Comment by benamor....@gmail.com, Sep 20, 2007

Is there a way to filter a feed searching for a word? something like:

http://www.google.com/reader/view/user/-/label/important/#search/find_my_word

Comment by scruffy...@gmail.com, Dec 8, 2007

If I pass in the contents of <gr:continuation> as a parameter (c=...), it does jump me down the feed, but always to the same point (maybe post number 40).

Also, if i use n as a parameter it doesn't work for values over 9.

Are these bugs, or am I doing something wrong?

Comment by singpol...@gmail.com, Jan 10, 2008

token is actually T= not token= remember it is s=feed/FEEDURL not just s=FEEDURL

Comment by glennmar...@gmail.com, Mar 25, 2008

What about http://www.google.com/reader/public/atom/user/<uid>/label/<label>

This is the pure RSS atom feed of any tags you make public. It only returns the last 20 entries of the feed. Is there a way to make it return all the entries?

Comment by tubo...@gmail.com, Mar 26, 2008

How can I get a URI like "https://www.google.com/reader/public/atom/feed/<feed URI>"? Or "http://www.google.com/reader/public/atom/feed/<feed URI>"? Is this structure just like "/reader/atom/feed/<feed URI>" that is used to request any feed from google reader system? If so, is there any fresh time of google reader system about this <feed URI>? Or fetch the content from <feed URI> and send it to the client just when user request it?

Comment by arnstei...@gmail.com, May 10, 2008

There seems to be lots of other API changes too. For example, for adding a subscription, google reader uses http://www.google.com/reader/api/0/subscription/quickadd?client=myclient with postdata as quickadd=<URL>&ac=subscribe&T=<TOKEN>

I think they might have changed more, and this document might need reviewing.

Comment by lechtit...@gmail.com, Jun 3, 2008

I'm wondering if they're planning to release an official API someday :(. I'm working on a little Java program to manipulate my unread items, but it's quite painfull right now...

Comment by arnstei...@gmail.com, Jun 4, 2008

To get feeds beyong 20 feeds pass n=<numbertoretrieve> as GET request. Unfortunately I didn't figure out a way to start the feeds from a given number.

For example: http://www.google.com/reader/atom/feed/http://xkcd.com/atom.xml?n=20

Comment by lechtit...@gmail.com, Jun 4, 2008

I'm working on an unofficial Java API for Google Reader based on this page's information.

Comment by san...@gmail.com, Jun 6, 2008

Requierements is spelled requirements

Comment by thomas.a...@gmail.com, Jun 10, 2008

Is there any way to get the specific extensions in each feed? I'd like to be able to view the original itunes extensions through Google Reader because they keep history, but it seems like they strip them out; i.e. it's a bare-bones atom feed.

Comment by swetadri...@gmail.com, Jun 12, 2008

Is there any way to login in google-reader account by java program only?Means from code, not from google-reader homepage.Ia m sending "Email" and "Passwd" as post parameter to https://www.google.com/accounts/ClientLogin.Then I am getting SID and LSID.Then I am dumoing cookie.But,its not taking setDomain(".google.com") method. What to do? I want to be logged in via code.IS therer any mistake I am doing?Plz help!!!

Comment by lechtits...@gmail.com, Jun 14, 2008

@swetadri: I'm currently working on it, if you want more info and/or help me, you can contact me at lechtitseb at gmail . com

Comment by milob...@gmail.com, Jun 19, 2008

The "xt" parameter seems to work only for excluding read items. It seems to completely ignore other states, labels, or feed stream IDs beginning "feed/".

Does anyone have a workaround for this?

Comment by scarv...@gmail.com, Jul 3, 2008

I have made my own java based google reader api. Theres no documentation, and it is incomplete, but it may be useful for someone. http://www.caip.rutgers.edu/~scarvel/grapijava/

Comment by swetadri...@gmail.com, Jul 8, 2008

thanks to scarvel8...ur api is useful to me...

Comment by swetadri...@gmail.com, Jul 10, 2008

scarvel8, did you do the same thing for subscribtion via my yahoo or bloglines?if yes, please let me know

Comment by scarv...@gmail.com, Jul 10, 2008

No I haven't, although if I get some free time I will look into it. I am also working on other options not listed in this document, such as being able to load search results. I should have a more complete API up in the next week or two.

Comment by swetadri...@gmail.com, Jul 10, 2008

ok..if you do for yahoo rssfeeds, plz tell me...

Comment by ForeverZ...@gmail.com, Jul 17, 2008

I am trying to access this url with an XMLHttpRequest: http://www.google.com/reader/atom/user/-/state/com.google/broadcast

However, the responseText is a Google error page which says the following: "Further action needs to be taken by your user agent in order to fulfill the request. "

The script goes through a PHP proxy so it can go cross domain. Does anyone know what information Google Reader requires that would fix this error?

Comment by franssau...@gmail.com, Jul 17, 2008

Great article! I want to export my google reading list, and a step is to input it into a feedburner feed for further processing. I could not get Google to export the feed, with the correct userID: http://www.google.com/reader/atom/user/123456789123456789123456789/state/com.google/reading-list Is there authentication requirements?

Comment by franssau...@gmail.com, Jul 22, 2008

Ok.. answered my own question. I tried a GET with https://www.google.com/accounts/ClientLogin?service=reader&Email=myusername&Passwd=mypassword and got the authentication requirements parameters

Comment by lady...@gmail.com, Jul 29, 2008

Hi thanks for the post.Nice blog.Now this blog is in my favourite bookmark pages. http://www.squidoo.com/papershredderarticles

Comment by ForeverZ...@gmail.com, Jul 31, 2008

I out together a very small program that shows a basic way of grabbing GET data from Google Reader with Java. I commented it up so most questions should be answered. Note this is VERY basic, and just intended for people looking for information on how to get started.

http://www.foreverzero.org/Process.java

Comment by mdes...@gmail.com, Jul 31, 2008

Has anyone been able to successfully implement the continuation parameter for getting more feed items from a feed? I cant seem to get it to work. The url I create I can put in a browser address bar and it works fine but when I hit it from a server (CURL) it always shows the first n items.

Comment by mdes...@gmail.com, Jul 31, 2008

Also, I cant seem to get any of the xt (exclude) links to work. Has anyone pulled this off?

(http://www.google.com/reader/atom/?n=4&xt=user/-/state/com.google/read)

Comment by dfink...@gmail.com, Aug 17, 2008

i can read N items from a feed.. i am currently limited by heap size only, yay

Comment by dfink...@gmail.com, Aug 17, 2008

i can also query for number of unread items but have no implemented (in java) the ability to mark items as read.. any advice?

Comment by beg...@gmail.com, Aug 19, 2008

I can't make it retrieve more than 999 items from a given feed. Any ideas how I might get more than that?

(I have a few years' worth of friends' facebook status updates cached in Reader, and would love to be able to export them all! http://infoclarity.blogspot.com/2008/06/hidden-in-words.html)

Thanks for the great tips.

Comment by robertgr...@gmail.com, Sep 4, 2008

Ok, you can probably tell I'm a complete noob at this from my question but here it goes. I'm just trying to make a very simple bash shell script using curl to get my unread count. I can view the data I want just fine when I open this link in safari (http://www.google.com/reader/api/0/unread-count?all=true) and I can view the source and see exactly what I'd like to extract. However, when I use curl in my shell script it doesn't work. I'm assuming I have to login as described at the beginning of the article to access this data using curl. My stupid question is this: is it safe/secure to include my user name and password in this url ( https://www.google.com/accounts/ClientLogin?service=reader&Email=myusername&Passwd=mypassword) in a shell script? Any suggestions would be a big help. Thanks!

Comment by pinow...@gmail.com, Oct 4, 2008

For doing any operation which requires authentication, you would need to provide two tokens:

SID Authentication token or T token (do not mix up this token with the Auth token you get by authenticating against Google by ClientLogin?)

SID (session ID) is a session token. There are also two ways of fetching this token:

If you have a browser (i.e Firefox) opened and already logged in any Google site, a valid SID token would be stored inside your browser. Firefox stores session tokens inside session_store.js file. In conclusion, search for the SID inside session_store.js if there is any google session opened inside your Firefox.

Authentication against Google reader service using ClientLogin? mechanism. Google reader service codename is 'reader'. ClienLogin? mechanism is fully documented by Google (just google it). ClientLogin? mechanism returns three tokens, one of them is SID (session token).

Once you got a valid SID token, then you need to retrieve

Once you get a valid SID token, do a GET request to the following URL to get a valid T token.

http://www.google.com/reader/api/0/token

This request should be composed by adding SID as a Cookie.

Once you get both tokens, SID and T, you can successfully perform any Google Reader operations which require authentication (pass these two values as cookies)

So answering the question above, how to compose a valid curl command to fetch a list of unread elements:

First, get a valid SID token:

curl https://www.google.com/accounts/ClientLogin -d Email=just_your_username_here_without_at_gmail_dot_com -d Passwd=your_password_here -d source=Google-cURL-Example -d service=reader

Response: Auth=XXX SID=DQAAAH0AAAC0YHom0L5LDq10xGnbQK_O7OLiX3Qrou4XeA6P469shoM1goEFQT_zVn8YxDV38Y5v3mGJlhSzJuz5xLPqpKEM0Wedks-ak7LLpNjO7dZw779ljOQrC-2UCYFjiktJcfXmof7WeZs7O0SCNCQgPSKaENJ6FBTeDBeQLahUUrajrg LSID=XXX

Once you get a valid SID, request a T token:

curl -s -X GET http://www.google.com/reader/api/0/token --header "Cookie: SID=DQAAAH0AAAC0YHom0L5LDq10xGnbQK_O7OLiX3Qrou4XeA6P469shoM1goEFQT_zVn8YxDV38Y5v3mGJlhSzJuz5xLPqpKEM0Wedks-ak7LLpNjO7dZw779ljOQrC-2UCYFjiktJcfXmof7WeZs7O0SCNCQgPSKaENJ6FBTeDBeQLahUUrajrg"

Response:

kArWxxwBAAA.vegUbtUjv2Vvf_HKWlwjIA.QfhP1LoSb5ghYPz_AbOG_Q

Once you get a valid T token, perform any operation you want against Google Reader, for instance, retrieve your list of feeds

curl -s -X GET http://www.google.com/reader/api/0/unread-count?all=true --header "Cookie: SID=DQAAAH0AAAC0YHom0L5LDq10xGnbQK_O7OLiX3Qrou4XeA6P469shoM1goEFQT_zVn8YxDV38Y5v3mGJlhSzJuz5xLPqpKEM0Wedks-ak7LLpNjO7dZw779ljOQrC-2UCYFjiktJcfXmof7WeZs7O0SCNCQgPSKaENJ6FBTeDBeQLahUUrajrg; T=kArWxxwBAAA.vegUbtUjv2Vvf_HKWlwjIA.QfhP1LoSb5ghYPz_AbOG_Q" | tidy -xml -indent -quiet

Comment by uche.ogb...@gmail.com, Oct 31, 2008

Following the curl breadcrumbs of pinowsky (thanks!) I worked up the following Python code to use Google Reader to convert feeds to Atom:

http://wiki.xml3k.org/Amara/Recipes/Google_Web_feed_atomizer

Comment by AlexeiSe...@gmail.com, Nov 12, 2008

From now it seems like I need to be logged in to access atom/feed/somefeedurl?

Comment by rlstrac...@gmail.com, Nov 12, 2008

I can't use command-line URL-fetchers (like 'wget' or 'GET') successfully when trying to access the following URL: http://www.google.com/reader/atom/feed/http://xkcd.com/rss.xml

They don't return XML data, but rather an HTML page telling me to log in. Is Google restricting access to particular user-agents (browsers)?

Comment by taka.ats...@gmail.com, Nov 12, 2008

Google Reader has feed translation, introduced 2008-11-11.

That's accessible by the parameter/key pair of "trans=true"

ex. http://www.google.com/reader/atom/feed/SOME_FEED_URL?trans=true

the above translates to the language of your setting with Google Reader.

I don't know if you can make it translate to languages of your choice just by varying a parameter.

Comment by katap...@gmail.com, Nov 25, 2008

Is "edit-tag" still working?

I got a "400 client error" when I try to add a label to a specific post of my favorite list. I got a valid SID and Token, but for exemple this URL is not working: http://www.google.com/reader/api/0/edit-tag?ac=edit&i=tag:google.com,2005:reader/item/041fa449c5de72c9&a=user/-/label/test&token=97xa1B0BAAA.RDpLb8-l3NMfqpaw0vYq-g.JcgYUQXFh9E6MmkLNIpwEw

Am I missing something?

Comment by mariano.kamp, Dec 13, 2008

Hi,

I am wondering how to sync with GoogleReader?? for offline reading? I want the latest 10 entries that I haven't seen before, e.g. r=d (date descending), n=100, ot=<timestamp of last sync>. But you say above that specifying ot only works with r=o. ;-(

Cheers, Mariano

Comment by Thrashin...@gmail.com, Dec 18, 2008

Hi Mariano -- What you're going to want to do is use the "xt" (exclude target) parameter to exclude read items in your query. Look for "xt" above.

Comment by mariano.kamp, Dec 21, 2008

Hi TrashingStick?, I appreciate very much that you took the time to post an answer. I thought nobody would ;-(

But this would not help me really. It is not the same to have donwloaded an item and have read it. So I download a couple of items to a mobile device, read some of them, but then don't want to download the unread items all over again every time I sync. It is also not an option to mark them as read anyway and keep a separate read state on the client. This would make the items marked read for the online reader also.

Any more ideas?

Comment by jesusche...@gmail.com, Dec 28, 2008

the start_time parameter no longer (or never) works.

no matter what start_time i set, whether r=o or r=n, the oldest feed item returned is within this month.

oh well. if anyone tries to grap all the items. the way is to set n very very big so that it covers all the items.

Comment by shabda.s...@gmail.com, Dec 29, 2008

Will somebody pl tell me - 1. how to mark an item as read (using these api) 2. how to mark many items as read (using theser api)

I tried whatever has been said above.......however not getting it right. Pl explain with an example.

Thanks a ton in advance -shabda

Comment by jackphe...@gmail.com, Feb 5, 2009

Does anyone know how to solve this...?

I'm trying to roll my own aggregator by running feeds through the API to normalize the contents. Works great for most feeds ("http://www.google.com/reader/atom/feed/#{feed.url}"). However, some feeds use url parameters to deliver their contents... example: "http://img.perezhilton.com/?feed=rss2". The API sees this and thinks the feed address is just "http://img.perezhilton.com/", and that the "?feed=rss2" is a parameter for IT, rather than the feed's server. Escaping the ? does not work... anyone have any clues?

Thanks to all for the awesome work figuring this out.

Comment by Sesarr...@gmail.com, Feb 28, 2009

jackphelps, try urlencoding the whole url:

http://www.google.com/reader/atom/feed/http%3A%2F%2Fimg.perezhilton.com%2F%3Ffeed%3Drss2

this seems to work :). Good luck with your project

Comment by koo...@gmail.com, Mar 2, 2009

I'm getting 401 (Unauthorized) HTTP error, when trying to call "edit" API methods. I've tried to attach "T" token both in post request and as cookie to no avail. Does anyone else get the same error?

Comment by michael....@gmail.com, Mar 2, 2009

I'm have the same problem (401 (Unauthorized))

Comment by AlexeiSe...@gmail.com, Mar 11, 2009

Google don't allow to remove "user/-/state/com.google/read", and I failed to add "user/-/state/com.google/kept-read". Any tips on how to mark article "unread" now?

Comment by MekkM...@gmail.com, Mar 20, 2009

Thank you very much for this analysis, it was very helpful.

Here is my small tool written using Reader API (and some python code): managing subscriptions as a text file

Comment by wayne.cu...@gmail.com, Mar 23, 2009

katapulp - did you have any luck? I'm having the same issue. I've presented the i, s, & a arguments in every way I can imagine (in the url, as data in the post, URL encoded, not URL encoded) and the same with SID and token, and I always get a 400 or 401 error. Any one here have any luck editing tags? I can read data no problem, I just can't modify.

Comment by karthik...@gmail.com, Apr 2, 2009

Hi, For all shared items, how can I get the list of tags for each shared item? I have been trying with the above api and so far unsuccessful. Any suggestions are appreciated. Thanks.

Comment by bolda...@gmail.com, Apr 15, 2009

To catapulp and wayne.culbreth:

I have a working 'edit-tag' feature of marking entries as read in the following way:

Post to url: http://www.google.com/reader/api/0/edit-tag?client=- Post body: "i="+entryId+"&a=user/-/state/com.google/read&ac=edit&T="+token

Other combinations of T->token, ac=edit->ac=edit-tags, adding s=feedURL and so on come to 400 error from Google.

Comment by ionutz.p...@gmail.com, Apr 16, 2009

Hello guys ,

I am planning to write an application that simulates a Feed Reader and manager and I decided to write it in SIlverlight (it sounded interesting and I hope I will learn a lot).

My first problem was somehow to "generalize" the feeds brought into the application. After some research I found out Google Reader offers the posibility to access their first layer ( parsing layer) and in this way I could get the feed in atom format for any feed.

(using http://www.google.com/reader/atom/feed/[URL] command)

Ok ,things were clear until here .I already knew that for an SIlverligt appication to exist the posibility to extract some data from another location than it's domani ,that data site should have a crossdomain.xml file in the root of the site.

My thought was first that Google has something like this ,I also was enthusiastic when found reply to crossdomain.xml. But disappointment come soon because on a closer look the xml file looks like :

<?xml version="1.0"?> <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/ dtds/cross-domain-policy.dtd"> <cross-domain-policy>

<site-control permitted-cross-domain-policies="by-content-type" />
</cross-domain-policy>

So my first idea was to use a proxy to access this link ,I am new in this technology and tried some solutions:

SIlverlight can extract for example any data through a proxy ,for example this works: http://al.cloudapp.net/proxy.ashx?http://rss.cnn.com/rss/edition.rss ,it extracts the direct feed from cnn site even if they don't have a crossdomain.xml file.

My next step was to generalize the feed through Google Reader :

http://al.cloudapp.net/proxy.ashx?http://www.google.com/reader/atom/feed/http://rss.cnn.com/rss/edition.rss ,but this solution failed ,I also tried with different proxies and no success.

My questions would be:

1.Why Google has this crossdomain.xml file and not a more permissive one? Could it be possible to modify this crossdomain.xml so that Silverlight application can access this API?

2.If 1 is not possible does anyone have a better solution ,I feel I am very close and maybe it may work through a proxy and I am doing something wrong?

3.Anyone else have any other ideas?

Thanks a lot, Ionut

Comment by garyhu...@gmail.com, May 3, 2009

Hello. Just found this and have only begun digging in, but my first simple test is failing and it seems to be a "mad-made" issue. Google Reader shows that I have 84 unread items, yet the following code only returns 20 entries:

xmlfeed = gr.get_all()
print xmlfeed.get_title()
for entry in xmlfeed.get_entries():
    print entry

I see a 'count' parameter in ATOM_ARGS which may be used to limit the number of items (?) and "20" is a suspiciously convenient and round number, but I dont see any reference to 20 in the code... Is the response limited to 20 items?

Comment by curtis.h...@gmail.com, May 6, 2009

Has anyone looked into emulating the ability of the bookmarklet they release (http://googlereader.blogspot.com/2008/05/share-anything-anytime-anywhere.html). It allows you to share an item even if it isn't in one of your feeds. Would be nice to be able to duplicate this in the code too.

Comment by chadot...@gmail.com, May 13, 2009

Mine works for a little while, but then I get a 302 redirection and the message "Further action needs to be taken by your user agent in order to fulfill the request." After some period of time (I'm not sure how long yet) it will start working again.

If anyone aware of a limit to how often you can access the API during a period of time. I always get to a similar point (>100 I think) before getting the redirection.

Comment by mistermi...@gmail.com, May 21, 2009

I've already queried atom feeds from it several thousand times in testing my app. Seems to be no problem there.

Comment by bolda...@gmail.com, Jun 2, 2009

Does anybody know how to eliminate duplicates of entries which google returns sometime with the http://www.google.com/reader/atom/ API? This often happens when the RSS creators update entry, but the URL or id of the entry is changed. The same feed explored with Google Reader web interface doesn't contain duplicates, which appear with Reader API. While Google Reader is based on the GoogleReader? API it should be possible to avoid duplicates with API too.

Comment by monk...@gmail.com, Jun 3, 2009

How can I get a list of unread news (with the title)?

Comment by boje...@gmail.com, Jun 10, 2009

Trying to make edit tag work. I've got the data to be sent by using Firebug in Firefox and using online Google Reader. The result is return of "Invalid stream name." Anybody knows what that means?

Comment by abdulrah...@gmail.com, Jun 23, 2009

Hey i am getting a 400 error when i try to add a subscription list to google reader. Here is what I am doing

url = "http://www.google.com/reader/api/0/subscription/edit?client=-"

I set my http request url to this

and pass the following post parameters

postRequestPayload=feed/http://xkcd.com/rss.xml&ac=subscribe&T="+token.

I have also tried token instead of T and also tried client=scroll in my url but I still get the 400 error. Please help.

Comment by cubegames, Jun 27, 2009

The official Google Reader desktop gadget uses the API, so accurate API information can be gathered from it: http://code.google.com/p/google-reader-gadget/

Comment by gia...@gmail.com, Jul 14, 2009

I was using the following url http://www.google.com/reader/atom/feed/http://.. to be able to download all the feeds that i would eventually miss when my RSS Client is off. Why is not working any more?? I get this error in safari: “The feed could not be loaded because the content is not in a known feed format.” (PubSub?:2)

Comment by gia...@gmail.com, Jul 14, 2009

Fixed. The problem was something regarding cookies. I just needed to logout, delete the cookies in safari and login again. I recommend to use those url if the feed you're watching has more than 20 updates per day as the Client/feed might not pick more than that. -GianPaJ

Comment by markst3v...@gmail.com, Jul 26, 2009

I am using this URL to get unread headlines: https://www.google.com/reader/atom/user/-/state/com.google/reading-list?xt=user/-/state/com.google/read

Is there a query string parameter to exclude elements like <summary>? That would mean I would download a lot less data.

Comment by ross.bur...@gmail.com, Aug 11, 2009

I discovered that the "broadcast-friends" state is for items that your friends have shared (i.e. are in the People You Follow section).

Comment by bolda...@gmail.com, Aug 17, 2009

My HTTP requests to Google Reader API return HTTP 403 response. Everything worked fine until i've started experiment to check for new entries in cycle for about 4000 feeds. It looks like some kind of ban but i can't find any published restrictions on service usage. Does any body know about restrictions or about the way to pass the problem without changing the IP?

Comment by markst3v...@gmail.com, Aug 24, 2009

I have found the JSON version of /reader/atom/user/-/state/com.google/reading-list if anyone is interested:

http://www.google.com/reader/api/0/stream/contents/?xt=user/-/state/com.google/read

Comment by dmatara...@gmail.com, Sep 6, 2009

Everything was working fine, and then I started getting the message "Your client does not have permission to get URL /reader/api/0/token from this server," when requesting a token despite not having changed any code. Has anyone else experienced this?

Comment by ruim...@gmail.com, Sep 6, 2009

@dmatarazzo I'm having the same problem. =\

Comment by dmatara...@gmail.com, Sep 6, 2009

@ruimams I figured out that the problem was with how I was setting up the cookie that contained the SID. Could that be the source of your problem? As long as you're using POST, sending a cookie (I sent mine through the header) that reads SID=SID here? and using the /reader/api/0/token URL, it should work...

Comment by dmatara...@gmail.com, Sep 9, 2009

Since there isn't an "unread" state, to get a list of all unread items just query your reading list with a very large number and exclude read items like so: http://www.google.com/reader/atom/user/-/state/com.google/reading-list?n=9999&xt=user/-/state/com.google/read

Comment by jot.k...@gmail.com, Oct 8, 2009

How do you "mark as read " ?

I've tried sending : URL : http://www.google.com/reader/api/0/edit-tag Post values : i = tag:google.com,2005:reader/item/03052da1635b7fdb a = /user/-/state/com.google/read T = token value I include the sessions cookies as well.

Thanks.

Comment by jot.k...@gmail.com, Oct 8, 2009

Answering my post above. I had a slash in front of 'user' in the 'a' tag. 'ac' tag is set to 'edit-tags'. URL encode the token, 'i', and 's'. It works now.

Comment by cyberpra...@gmail.com, Oct 30, 2009

This is great!!! Can we use this API for a commercial product? Can someone at google respond to me cyberprashant at gmail dot com. Thanks!

Comment by ng2tuan@gmail.com, Oct 30, 2009

Hello,

I'm working with .NET, and I looking .NET component tall with Google Reader API

Now, I use component at: http://mattberseth.com/blog/2009/02/net_googlereader_api.html

In my code, I get rss from google news but have error - bad request

http://www.google.com/reader/atom/feed/http://news.google.com/news?cf=all&ned=us&hl=en&q=obama&cf=all&output=rss

How to fix this error?

Pls help me!

Comment by lyf...@gmail.com, Nov 16, 2009

Nice article. Just tried it to get all my feeds on Google reader.

Thanks.

Comment by chadot...@gmail.com, Dec 1, 2009

@ng2tuan:

Try urlencoding the feed URL. The ? is your problem.

Comment by chadot...@gmail.com, Dec 1, 2009

I've had my server checking feeds using the Google Reader API for a long time now and all of a sudden I'm getting 302 redirections because it's coming from an automated script. Is anyone else seeing this?

I've been fetching feeds directly from Google so I can have the Google ID's for each item to promote syncing. If anyone knows of another method for this I would love to hear it.

Comment by gonzalo....@gmail.com, Dec 4, 2009

I have installed everything just as indicated, but obtain the following error when trying to run pyrfeed.py: AttributeError??: 'module' object has no attribute 'EVT_BeforeNavigate2?? Any ideas? Thanks,

Gonzalo

Comment by luke.t.s...@gmail.com, Dec 10, 2009

spelling fix (diff):

-You should not rely on anything on this document is you need an exact information. +You should not rely on anything on this document if you need an exact information.

Comment by ham...@gmail.com, Jan 9, 2010

How to get like count for an item?

Comment by adawangx...@gmail.com, Jan 19, 2010

Does Google change the api? My RSS reader for Android is work normally before. But It can't link and always return fail these days. Who can tell me why?

Comment by tobu...@gmail.com, Jan 20, 2010

(formatting sucks, sorry. see the original.)

Comment by adawangx...@gmail.com, Jan 21, 2010

Please help!

post url: http://www.google.com/reader/api/0/subscription/edit

post parameter: Cookie:SID=mysid client=- s=feed/http://rss.sina.com.cn/news/marquee/ddt.xml ac=subscribe T=mytoken

response:http 401 error

Missing any parameter?url changed?

When can we have a offical document for google reader api?

Comment by markst3v...@gmail.com, Jan 26, 2010

If anyone is interested there is also output=proto for outputting in Google's own Protocol Buffers binary format. For example, http://www.google.com/reader/api/0/unread-count?output=proto

Comment by takashi316, Jan 28, 2010

This is what I have been looking for long time.

Comment by matteja...@gmail.com, Jan 30, 2010

Anyone know how to get all articles changed since a given date/time? Ie, I want not only new articles since a given date, but also any articles that had a state change such as read, unread, favorite, etc.

Comment by markst3v...@gmail.com, Jan 31, 2010

Just need the .proto files now to be able to decode the protocol buffer API responses. I have tried searching for them with no success yet.

Comment by knut.ahl...@gmail.com, Mar 23, 2010

Just created a tiny ruby test script for accessing the API to add / remove subscriptions and labels in my reader. (Will use this functions later on in an other script). I also used the Authorization-Header-Authentication instead of Cookie-Authentication.

If someone is interested in this script you can see it at http://gist.github.com/341399

Comment by karthik...@gmail.com, Mar 26, 2010

Is authentication still a problem for reading an user's data in Google Reader?

Can't AuthSub? or OAuth be used around this to get access to data without providing username and password?

Comment by mom...@gmail.com, Apr 2, 2010

'n' is limited to 1000. If you need to get more items than 1000 you have to use 'continuation'. So annoying.

Comment by farinsp...@gmail.com, Apr 8, 2010

Sample PHP code for adding/removing a feed (see above for getting session ID and token):

// adding a feed
$ch = curl_init();
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt ($ch, CURLOPT_URL, "http://www.google.com/reader/api/0/subscription/quickadd?client=scroll");
curl_setopt ($ch, CURLOPT_COOKIE, 'SID='.$this->session_id);
curl_setopt ($ch, CURLOPT_POST, 1);
//curl_setopt ($ch, CURLOPT_POSTFIELDS, array('quickadd'=>urlencode($feed_url),'T'=>$token)); // will not work
curl_setopt ($ch, CURLOPT_POSTFIELDS, 'quickadd='.urlencode($feed_url).'&T='.$token);
curl_setopt ($ch, CURLOPT_USERAGENT, $this->user_agent);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($ch);
curl_close($ch);
// removing a feed
$ch = curl_init();
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt ($ch, CURLOPT_URL, "http://www.google.com/reader/api/0/subscription/edit?client=scroll");
curl_setopt ($ch, CURLOPT_COOKIE, 'SID='.$this->session_id);
curl_setopt ($ch, CURLOPT_POST, 1);
curl_setopt ($ch, CURLOPT_POSTFIELDS, 'ac=unsubscribe&s=feed/'. urlencode($feed_url) .'&T='. $token);
curl_setopt ($ch, CURLOPT_USERAGENT, $this->user_agent);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($ch);
curl_close($ch);
Comment by justin...@gmail.com, Apr 11, 2010
google add a statue 
State name: created State meaning: A read item will have the state create. url:http://www.google.com/reader/atom/user/-/state/com.google/created

this is user comment items.
Comment by justin...@gmail.com, Apr 11, 2010

google modified the access param "token" to "T" for "www.google.com/reader/api/0"

"/api/0/token" will return a string containing 22 chars

Comment by gurpree...@gmail.com, Apr 18, 2010

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

Lets say I wish to filter the results above based on a keyword, "Roethlisberger".

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

Comment by dinochri...@gmail.com, Apr 19, 2010

Hi, I am trying to use the reader api to get feeds that I have been tracking since early 2009. However, I noticed that my feeds seem to only read 1000 items before a limit is reached. Is there some setting that allows one to access feeds with a much higher maximum number count?

Comment by thomas.h...@gmail.com, May 14, 2010

Hi, Any idea how to search for a particular entry guid, or original-id?

I know the original-id and I want to make updates to the google version, how do I map between? Thanks, T

Comment by bandie9...@gmail.com, May 19, 2010

Is cookie SID a secure thing? I get it via /accounts/ClientLogin?, then i unvalidate it via /accounts/Logout, but stil can feach private data with curl -H "Cookie: SID=$SID" ... What about, if anyone found one of my SID strings?

Comment by fmst...@gmail.com, May 27, 2010

Hey everyone,

I'm getting 400 errors when trying to star an item, and I can't figure out why. Here is the URL:

http://www.google.com/reader/api/0/edit-tag?i=tag%3Agoogle.com%2C2005%3Areader%2Fitem%2F97e73baae1c833d6&s=feed%2Fhttp%3A%2F%2Fwww.slickdeals.net%2Frss.php&a=user%2F-%2Fstate%2Fcom.google%2Fstarred&T=_2g76ZvXODPljRi-gCP42A

I've also tried passing ac=edit, ac=edit-tags, and URL Encoding and not URL Encoding variables. I am passing the SID as a cookie, and all my queries work fine, such as getting unread lists and items. But as soon as I try to use the edit-tag api it fails.

Ideas?

Comment by liviu.da...@gmail.com, May 29, 2010

Any new opinions on how to subscrie to a feed ? I'm using C#:

I create a http web request with POST here: http://www.google.com/reader/api/0/subscription/quickadd with GET params : client = scroll and ck = ... and POST params : quickadd = feedURL, T = token

I attached the cookie and pust an user agent to the request, but I still get 401. Is there someone who has succeeded in making this request ? I've double checked with these params using Firebug, but still no succes

Comment by cosina1...@gmail.com, May 31, 2010

hey can anyone tell me about how to get 'ot' value?

Comment by sot...@gmail.com, Jun 23, 2010

Hi!

This wiki page greatly helped me in writing my own application for reading rss news. (I might publish it soon).

My application was working fine for couple of months now. However, google reader responses started to return information about authentication requirement. Logging in is still successful and SID cookie is created the same way.

Does anyone know what might have changed?

Comment by ripne...@gmail.com, Jun 23, 2010

This seems to be broken as of June 2010 . My app which has worked for months is now getting a unauthorised from googles servers... Hopefully we will get an official API soon...

Comment by sot...@gmail.com, Jun 23, 2010

Using:

 Authorization:GoogleLogin auth=[value obtained from ClientLogin] 

works :)

Comment by murderer1234@gmail.com, Jun 23, 2010

header

name : Authorization value : GoogleLogin? auth=obtained from ClientLogin?

Comment by kon...@gmail.com, Jun 23, 2010

Authorization:GoogleLogin? auth=obtained from ClientLogin?

How to use that?

Comment by rundber...@gmail.com, Jun 23, 2010

Add the following header to your HTTP request. Name: "Authorization", Value: "GoogleLogin? auth=<ADD AUTH TOKEN HERE>"

Comment by yorkchri...@gmail.com, Jun 23, 2010

Does anyone have a complete header request? My requests were working with SID, but I've tried adding the headers as above with/without my old SID header and my new auth. I'm getting 400 error.

Comment by haxmeadr...@gmail.com, Jun 24, 2010

I've had the same problem as of a few days ago and can't resolve it. Tried the GoogleLogin? in the header and still get a 401 when requesting a google reader URL that worked fine for weeks before. Anyone else get this resolved? Did you completely drop the SID? Is a space ok in the header between Authorization and GoogleLogin??

Comment by spreads...@gmail.com, Jun 24, 2010

when you get the SID at https://www.google.com/accounts/ClientLogin, there is now a new additional parameter 'Auth'. you need to extract it and use it in the HTTP request header of every request to the google reader in the following way: add a new header variable 'Authorization', where its value is 'GoogleLogin? auth={here add the Auth variable you got from where the SID is}'. all the rest stays the same!

Comment by iw2...@gmail.com, Jun 25, 2010

i cant get my app to work with new auth method: is still required the GET call to http://www.google.com/reader/api/0/token or the auth= value received from GoogleLogin? can be used as token my try was 1) save the valued of ath, add header, call api/0/token = error 403 2) save the valued of ath, add header call directly reader/api/0/subscription/list?client=pushNews&output=json = error 401

since few days ago all was working with SID+token

Comment by ja.sav...@gmail.com, Jun 25, 2010

For those using the cookie method, this is working for me:

"Cookie: SID={sid string}\r\nAuthorization:GoogleLogin? auth={auth string}"

Be sure to remove the '?' after 'G00gleLog1n?'

Comment by iw2...@gmail.com, Jun 25, 2010

im quite sure to do all correctly, but still got error :(

is there someone that is able to retreive api/0/token with iphone sdk ??
Comment by iw2...@gmail.com, Jun 26, 2010

this's the routine: SID (no more useful) and Auth correctly read with /accounts/ClientLogin?

try to retrieve the token: request = [alloc? init];

url = stringWithFormat:@"http://www.google.com/reader/api/0/token"?; //url = stringWithFormat:@"http://www.ericgiguere.com/tools/http-header-viewer.html"?; setURL:[NSURL URLWithString:url?]; setHTTPMethod:@"GET"?; setValue:[NSString stringWithFormat:@"GoogleLogin auth=%@", AUTH? forHTTPHeaderField:@"Authorization"]; NSLog(AUTH); //is correct setHTTPShouldHandleCookies:NO?; setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"?; risposta = sendSynchronousRequest:request returningResponse:&response error:&error?;

i still got error 403

thanks for any tips

Comment by iw2...@gmail.com, Jun 26, 2010

my God, 2 days lost for a stupid error: i was not stripping the last linefeed in the response of ClientLogin? now with posted routine all is ok

Comment by unicen...@gmail.com, Jun 28, 2010

I can not change read/unread by edit-tag. But I can get token correctly. Can anyone tell me why? Thx a lot !

Comment by xiaofenf...@gmail.com, Jun 28, 2010

Authorization problem fix The following amendments to two documents \GoogleReader?\reader.py \GoogleReader?\web\web.py

reader.py


import time import urllib import cookielib # TODO : Get rise of web package. from web import web

# TODO : Use those line when python 2.6 will be out, for now, there is no # reasons to not be compatible with python 2.4 just to please PEP 238 ! # (lines will be mandatory only with python 2.7) # from .feed import GoogleFeed? # from .object import GoogleObject? # from .const import CONST from feed import GoogleFeed? from object import GoogleObject? from const import CONST

def utf8(s): return s.encode('utf-8','ignore') if isinstance(s, unicode) else str(s)

class GoogleReader?(object) :

'''This class provide python binding for GoogleReader? http://google.com/reader/''' def init(self,agent=None,http_proxy=None) :
self.login = None self.passwd = None

self.agent = agent or CONST.AGENT self.web = web(agent=self.agent,http_proxy=http_proxy) self.sid = None self.Auth = None
self.token = None

  1. Login process

def identify(self,login,passwd) :
''' Provide login and passwd to the GoogleReader? object. You must call this before login.''' self.login = login self.passwd = passwd
def login(self) :
''' Login into GoogleReader?. You must call identify before calling this.
You must call this before anything else that acces to GoogleReader? data.'''
if self.login==None or self.passwd == None :
return
data = {
'service':'reader', 'Email':self.login, 'Passwd':self.passwd, 'source':CONST.AGENT, 'continue':'http://www.google.com/', 'accountType':'HOSTED_OR_GOOGLE', }
sidinfo = self.web.get( CONST.URI_LOGIN, data )
  1. print sidinfo
self.sid = None SID_ID = 'SID=' if SID_ID in sidinfo :
pos_beg = sidinfo.find(SID_ID) pos_end = sidinfo.find('\n',pos_beg) self.sid = sidinfo[pos_beg+len(SID_ID):pos_end]
if self.sid != None :
cookie = cookielib.Cookie(version=0, name='SID', value=self.sid, port=None, port_specified=False, domain='.google.com', domain_specified=True, domain_initial_dot=True, path='/', path_specified=True, secure=False, expires='1600000000', discard=False, comment=None, comment_url=None, rest={}) self.web.cookies().set_cookie(cookie)
self.Auth = None Auth_TXT = 'Auth=' if Auth_TXT in sidinfo :
pos_beg = sidinfo.find(Auth_TXT) pos_end = sidinfo.find('\n',pos_beg) self.Auth = sidinfo[pos_beg+len(Auth_TXT):pos_end] self.web.Auth = self.Auth return True

  1. Very low

def get_token(self,force=False) :
'''Return a tokey. A token is a special string that is used like a session identification, but that expire rather quickly.''' if ( force or (self.token == None) ) :
feedurl = CONST.URI_PREFIXE_API + CONST.API_TOKEN + '?client=' + CONST.AGENT
  1. print feedurl
self.token = self.web.get(feedurl)

## self.token = self.Auth

return self.token

def get_timestamp(self) :
return str(int(1000*time.time()))
def translate_args(self, dictionary, googleargs, kwargs) :
""" translate_args takes a 'dictionary' to translate argument names
in 'kwargs' from this API to google names. It also serve as a filter. Nothing is returned 'googleargs' is just updated. """
for arg in dictionary :
if arg in kwargs :
googleargs[dictionaryarg?] = kwargsarg?
if dictionaryarg? in kwargs :
googleargs[dictionaryarg?] = kwargs[dictionaryarg?]

  1. Low

def get_feed(self,url=None,feed=None,kwargs) :
""" 'get_feed' returns a GoogleFeed?, giving either an 'url' or a 'feed' internal name.
other arguments may be any keys of CONST.ATOM_ARGS keys """
if url != None :
feedurl = CONST.ATOM_GET_FEED + urllib.quote_plus(url)
if feed == None :
feedurl = CONST.ATOM_STATE_READING_LIST
else:
feedurl = urllib.quote(utf8(feed))
feedurl = CONST.URI_PREFIXE_ATOM + feedurl
urlargs = {} kwargs['client'] = CONST.AGENT kwargs['timestamp'] = self.get_timestamp() self.translate_args( CONST.ATOM_ARGS, urlargs, kwargs )
atomfeed = self.web.get(feedurl + '?' + urllib.urlencode(urlargs))
if atomfeed != '' :
return GoogleFeed?(atomfeed)
return None
def get_api_list(self,apiurl,kwargs) :
""" 'get_api_list' returns a structure than can be send either
by json or xml, I used xml because... I felt like it. """
urlargs = {} kwargs['output'] = CONST.OUTPUT_XML kwargs['client'] = CONST.AGENT kwargs['timestamp'] = self.get_timestamp() self.translate_args( CONST.LIST_ARGS, urlargs, kwargs ) xmlobject = self.web.get(apiurl + '?' + urllib.urlencode(urlargs)) if xmlobject != '' :
return GoogleObject?(xmlobject).parse()
return None
def edit_api( self, target_edit, dict_args, kwargs ) :
""" 'edit_api' wrap Google Reader API for editting database.
"""
urlargs = {} urlargs['client'] = CONST.AGENT
postargs = {} kwargs['token'] = self.get_token() self.translate_args( dict_args, postargs, kwargs ) feedurl = CONST.URI_PREFIXE_API + target_edit + '?' + urllib.urlencode(urlargs) result_edit = self.web.post(feedurl,postargs)
  1. print "result_edit:[%s]"%result_edit
if result_edit != 'OK' :
  1. just change the token and try one more time !
kwargs['token'] = self.get_token(force=True) self.translate_args( dict_args, postargs, kwargs ) result_edit = self.web.post(feedurl,postargs)
  1. print "result_edit_bis:[%s]"%result_edit
return result_edit

  1. Middle

def edit_tag( self, kwargs ) :
if 'feed' not in kwargs :
kwargs['feed'] = CONST.ATOM_STATE_READING_LIST
kwargs['action'] = 'edit-tags' return self.edit_api( CONST.API_EDIT_TAG, CONST.EDIT_TAG_ARGS, kwargs )
def edit_subscription( self, kwargs ) :
if 'action' not in kwargs :
kwargs['action'] = 'edit'
if 'item' not in kwargs :
kwargs['item'] = 'null'
return self.edit_api( CONST.API_EDIT_SUBSCRIPTION, CONST.EDIT_SUBSCRIPTION_ARGS, kwargs )
def get_preference(self) :
""" 'get_preference' returns a structure containing preferences.
"""
return self.get_api_list(CONST.URI_PREFIXE_API + CONST.API_LIST_PREFERENCE)
def get_subscription_list(self) :
""" 'get_subscription_list' returns a structure containing subscriptions.
"""
return self.get_api_list(CONST.URI_PREFIXE_API + CONST.API_LIST_SUBSCRIPTION)
def get_tag_list(self) :
""" 'get_tag_list' returns a structure containing tags.
"""
return self.get_api_list(CONST.URI_PREFIXE_API + CONST.API_LIST_TAG)
def get_unread_count_list(self) :
""" 'get_unread_count_list' returns a structure containing the number
of unread items in each subscriptions/tags. """
return self.get_api_list(CONST.URI_PREFIXE_API + CONST.API_LIST_UNREAD_COUNT, all='true')

  1. High

def get_all(self) :
return self.get_feed()
def get_unread(self) :
return self.get_feed( exclude_target=CONST.ATOM_STATE_READ )
def set_read(self,entry) :
return self.edit_tag( entry=entry, add=CONST.ATOM_STATE_READ, remove=CONST.ATOM_STATE_UNREAD )
def set_unread(self,entry) :
return self.edit_tag( entry=entry, add=CONST.ATOM_STATE_UNREAD, remove=CONST.ATOM_STATE_READ )
def add_star(self,entry) :
return self.edit_tag( entry=entry, add=CONST.ATOM_STATE_STARRED )
def del_star(self,entry) :
return self.edit_tag( entry=entry, remove=CONST.ATOM_STATE_STARRED )
def add_public(self,entry) :
return self.edit_tag( entry=entry, add=CONST.ATOM_STATE_BROADCAST )
def del_public(self,entry) :
return self.edit_tag( entry=entry, remove=CONST.ATOM_STATE_BROADCAST )
def add_label(self,entry,labelname) :
return self.edit_tag( entry=entry, add=CONST.ATOM_PREFIXE_LABEL+labelname )
def del_label(self,entry,labelname) :
return self.edit_tag( entry=entry, remove=CONST.ATOM_PREFIXE_LABEL+labelname )
def add_subscription(self,url=None,feed=None,labels=,kwargs) :
postargs = {} result_edit = None if (feed is not None) or (url is not None) :
if feed is None :
kwargs['url'] = url kwargs['token'] = self.get_token(force=True) self.translate_args( CONST.QUICKADD_ARGS, postargs, kwargs ) result_edit = self.web.post(CONST.URI_QUICKADD,postargs)
  1. print "result_edit:[%s]"%result_edit
if "QuickAdd?_success('" in result_edit :
start_pos = result_edit.find("QuickAdd?_success('") stop_pos = result_edit.rfind("')") uri_orig, feed = result_edit[start_pos+len("QuickAdd?_success('"):stop_pos].split("','")
else :
result_edit = self.edit_subscription(feed=feed,action='subscribe')
for label in labels :
  1. print feed,CONST.ATOM_PREFIXE_LABEL+label
self.edit_subscription(feed=feed,add=CONST.ATOM_PREFIXE_LABEL+label.lower())
return result_edit
def del_subscription(self,feed,kwargs) :
postargs = {} result_edit = None if feed is not None :
result_edit = self.edit_subscription(feed=feed,action='unsubscribe')
return result_edit

def test() :

from private import login_info

gr = GoogleReader?() gr.identify(login_info) if gr.login():
print "Login OK"
else :
print "Login KO" return
print "[%s]" % gr.get_token()
print "[%s]" % gr.get_tag_list()
  1. print gr.set_read("tag:google.com,2005:reader/item/c3abf620979a5d06")
  2. print gr.set_unread("tag:google.com,2005:reader/item/8b1030db93c70e9e")
  3. print gr.del_label(entry="tag:google.com,2005:reader/item/8b1030db93c70e9e",labelname="vorkana")
  4. xmlfeed = gr.get_feed(feed=CONST.ATOM_PREFIXE_LABEL+'url',order=CONST.ORDER_REVERSE,start_time=1165482202,count=15)
  5. print xmlfeed
  6. print xmlfeed.get_title()
  7. for entry in xmlfeed.get_entries() :
  8. print " %s\n"%entry['title']
  9. print " %s\n"%entry['published']
  10. continuation = xmlfeed.get_continuation()
  11. print "(%s)\n"%continuation
  12. while continuation != None :
  13. xmlfeed = gr.get_feed(feed=CONST.ATOM_PREFIXE_LABEL+'url',order=CONST.ORDER_REVERSE,start_time=1165482202,count=2,continuation=continuation)
  14. print xmlfeed
  15. print xmlfeed.get_title()
  16. for entry in xmlfeed.get_entries() :
  17. print " %s\n"%entry['title']
  18. print " %s\n"%entry['published']
  19. continuation = xmlfeed.get_continuation()
  20. print "(%s)\n"%continuation
  1. print gr.get_preference()
  2. print gr.get_subscription_list()
  3. print gr.get_tag_list()
  1. print gr.get_feed("http://action.giss.ath.cx/RSSRewriter.py/freenews",order=CONST.ORDER_REVERSE,start_time=1165482202,count=2)
  1. f = GoogleFeed?(xmlfeed)
  2. rint gf.get_title()

## xmlfeed = gr.get_feed(order=CONST.ORDER_REVERSE,count=3,ot=1166607627) ## print xmlfeed.get_title() ## for entry in xmlfeed.get_entries() : ## print " %s %s %s\n" % (entry['google_id'],entry['published'],entry['title']) ## print xmlfeed.get_continuation()

xmlfeed = gr.get_feed(order=CONST.ORDER_REVERSE,count=3) print xmlfeed.get_title() for entry in xmlfeed.get_entries() :
print " %s %s %s\n" % (entry['google_id'],entry['published'],entry['title'])
print xmlfeed.get_continuation()
print gr.set_read("tag:google.com,2005:reader/item/90454f0d28177378") pass

if name=='main' :

test()

web.py


#!/usr/bin/perl

# --------------------------------------------------------------

import socket import urllib import urllib2 import cookielib

from resolvUrl.resolvUrl import resolvUrl # from SSLproxy import ConnectHTTPHandler from SSLproxy import ConnectHTTPSHandler

# --------------------------------------------------------------

DEFAULT_AGENT = "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90)"

# --------------------------------------------------------------

class AppURLopener(urllib.FancyURLopener):

def init(self, version, args):
self.version = version urllib.FancyURLopener.init(self, args)

# --------------------------------------------------------------

class webUrllib :

def init( self, agent = DEFAULT_AGENT, http_proxy=None ) :
  1. http_proxy is not used now.

self.agent = agent urllib.urlopener = AppURLopener(agent)
def get ( self, url, file=None, encoding='utf-8' ) :
result = "" url = url.encode(encoding) try :
if file == None :
f = urllib.urlopen( url ) for line in f.readlines() :
result += line
else :
result = urllib.urlretrieve( url, file ) result = result0?
except IOError :
pass
except socket.error :
pass
return result
def post(self, args, kwargs) :
raise Exception("Not Implemented")
def cookies(self) :
return None

# --------------------------------------------------------------

class webUrllib2 :

def init( self, agent = DEFAULT_AGENT, http_proxy=None ) :
self.agent = agent self.Auth = None

openers =
proxy_support = None if http_proxy is not None :
  1. Look like urllib2 default proxy works better than ConnectHTTPHandler
  2. peners.append(ConnectHTTPHandler(proxy="%s:%s" % (http_proxy0?,http_proxy1?),debuglevel=1))
openers.append(urllib2.ProxyHandler?({"http" : "http://%s:%s" % (http_proxy0?,http_proxy1?)}))
openers.append(ConnectHTTPSHandler(proxy="%s:%s" % (http_proxy0?,http_proxy1?)))
self.cookiejar = cookielib.LWPCookieJar() openers.append(urllib2.HTTPCookieProcessor(self.cookiejar))
opener = urllib2.build_opener(openers) urllib2.install_opener(opener)
def get ( self, url, postargs=None, file=None, encoding='utf-8', cookie=None) :
result = ""
url = url.encode(encoding)
postdata = None
if postargs != None :
postdata = urllib.urlencode(postargs)
if self.Auth != None :
header = {'User-agent' : self.agent, 'Authorization': 'GoogleLogin? auth=' + self.Auth }
else :
header = {'User-agent' : self.agent}
if cookie :
header['Cookie']=cookie
  1. rint self.cookiejar
  2. rint url
request = urllib2.Request(url, postdata, header)
  1. rint "%s " % self.cookiejar.cookies_for_request(request)
self.cookiejar.add_cookie_header(request)
f = urllib2.urlopen( request ) result = f.read() if file != None :
handle = open(file,'wb') handle.write(result) handle.close() result = file
return result
def post( self, args, kwargs ) :
return self.get(args,kwargs)
def cookies(self) :
return self.cookiejar

# --------------------------------------------------------------

web = webUrllib2

# --------------------------------------------------------------

if name == "main" :

w = web() print "%s\n-------------------" % w.get("http://giss.mine.nu/")

#



Comment by peri...@gmail.com, Jul 17, 2010

I am trying to convert a feed to atom using Google Reader and then saving it locally to my server.I am using a php script with curl.No matter what i have tried the saved xml says that further action needs to be taken by my agent.I have already logged in to Google with curl and have retieved SID, Auth and token (event though i don't need them all for accessing layer 1) and i have used both the header method and the cookie method but still Google does not allow me to save the result to a file.I have googled around but i haven't found anyone attempting this.The closest is this python feed converter http://wiki.xml3k.org/Amara2/Recipes/Google_Web_feed_atomizer Can anyone help?Thank you

Comment by zhumingv...@gmail.com, Aug 19, 2010

Are we need is auth token in header now, we don't need to set cookie anymore. The follow is a example using java with apache httpclient:

DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
httpget.setHeader("Authorization", "GoogleLogin auth=" + authToken);
HttpResponse response = httpClient.execute(httpget);
Comment by kaival...@gmail.com, Aug 29, 2010

I have the same issue, I had a working python script and now it not longer works returning a 401 auth error, with either old cookie based auth or the method mentioned above :(

Comment by kaival...@gmail.com, Aug 29, 2010
I had a working python script and now it not longer works returning a 401 auth error, with either old cookie based auth or the method mentioned above :(

Here's the main code:

        url = "https://www.google.com/reader/api/0/unread-count?all=true"
        request = urllib2.Request(url, None, auth_header)
        response = urllib2.urlopen(request)
        unreadxml = response.read()

And here is the function that provides the Auth_header dict object:

    def getAuthorizationHeader(self):
        
        # Authenticate to obtain SID
        auth_url = 'https://www.google.com/accounts/ClientLogin'
        auth_req_data = urllib.urlencode({'Email': self.options.username,
                                          'Passwd': self.options.password})
        auth_req = urllib2.Request(auth_url, data=auth_req_data)
        auth_resp = urllib2.urlopen(auth_req)
        auth_resp_content = auth_resp.read()
        auth_resp_dict = dict(x.split('=') for x in auth_resp_content.split('\n') if x)
        SID = auth_resp_dict["SID"]
        
        # Create a auth key in the header using the SID 
        header = {}

        header["Authorization"] = "GoogleLogin auth=" + SID
        
        return header
Comment by kaival...@gmail.com, Aug 29, 2010

Fixed the auth header function, had to use the auth key and not the previously used SID, also had to add the service key into the request:

    def getAuthorizationHeader(self):
        
        # Authenticate to obtain SID
        auth_url = 'https://www.google.com/accounts/ClientLogin'
        auth_req_data = urllib.urlencode({'Email': self.options.username,
                                          'Passwd': self.options.password,
                                          'service': 'reader'})
        auth_req = urllib2.Request(auth_url, data=auth_req_data)
        auth_resp = urllib2.urlopen(auth_req)
        auth_resp_content = auth_resp.read()
        auth_resp_dict = dict(x.split('=') for x in auth_resp_content.split('\n') if x)
        AUTH = auth_resp_dict["Auth"]
        
        # Create a header using the AUTH key 
        header = {"Authorization" : "GoogleLogin auth=%s"%AUTH}
        
        return header
Comment by peri...@gmail.com, Sep 3, 2010

Cant figure out why i couldn't make this PHP code work before, but it does now.Here's a php example on how to download and store locally the converted feeds.

<?php

$path = "GoogleFeed.xml";
$url = "http://your_feed_url";
$feed_url = "http://www.google.com/reader/atom/feed/$url?n=100";


//Parameters required to login to Google
$params = array('accountType' => 'GOOGLE', 'Email' => 'example@gmail.com',
'Passwd' => 'your_passwd', 'source'=>'PHP-cUrl-GooleLogin', 'service'=>'reader');

//Login to Google
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.google.com/accounts/ClientLogin");
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
$googleResponse = curl_exec($ch);
curl_close ($ch);

//Retrieve the SID and Auth parameters for further Google transactions
$sid = substr($googleResponse,4,203);
$pos = strpos($googleResponse,"Auth=");
$pos = $pos+5;
$auth = substr($googleResponse,$pos,224);

//Connect to Google Reader and retrieve the user's feed in Atom form spanning at least 100 entry elements
$headers = array(
    "Authorization: GoogleLogin auth=" . $auth,
    "GData-Version: 3.0",
);
$agent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.7) Gecko/20100713 Firefox/3.6.7";
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $feed_url);
curl_setopt($curl, CURLOPT_USERAGENT, $agent);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_POST, false);
//Save Google Reader's response directly to a file
$fp = fopen($path, 'w');
curl_setopt($curl, CURLOPT_FILE, $fp);
curl_exec($curl);
curl_close ($curl);
fclose($fp);

?>
Comment by rishi.ha...@gmail.com, Sep 7, 2010

Is there a way to paginate the feed?

suppose, I setup my feed 20 per page using Atom set method, and now i want to jump to 5th page directly (that means, post 81 to 100).. is there a way to do that?

something like http://www.google.com/reader/atom/user/-/state/com.google/broadcast?n=20&page=5

is there a way to do this?

Comment by liska.jakub, Oct 9, 2010

Hey,

can I get the feed with content that is not html formatted ? Or I can only get html formatted content from google reader, thanks

Comment by F...@gmx.net, Nov 21, 2010

A few corrections (it seems the API has changed somewhat):

  • the token parameter is now just T
  • when adding a subscription with the s parameter, its URI has to be prefixed with feed/ (this is mentioned in the overview, but missing from the example)

To be continued...

Comment by emmanuel...@gmail.com, Dec 6, 2010

Hello,

I have some problems to mark an item as read I have an error 400 or 401. I'm developping on Android and using JSoup to send the request

Thanks

Comment by justchar...@gmail.com, Dec 22, 2010

Has anyone found a way to get sort by Magic working? Do any apps have this feature at all? Can't find it anywhere but on the GR site.

Comment by u01j...@gmail.com, Dec 23, 2010

Hello,

Can anyone post a complete URL that works with the current API for marking all items as read? I have tried:

http://www.google.com/reader/api/0/edit-tag?i=tag:google.com,2005:reader/item/03052da1635b7fdb&a=user/-/state/com.google/read&ac=edit-tags&T=[token]

but I get a 401 error.

Many thanks.

Comment by sidramuj...@gmail.com, Jan 5, 2011

I am very much pleased with the contents you have mentioned.I wanted to thank you for this great article. http://www.Craigslistz.org

Comment by yuzhe801...@gmail.com, Jan 16, 2011
string args="?i=tag:google.com,2005:reader/item/2ee53214436e17a5&a=user/-/state/com.google/read&ac=edit&T=//4Dk64M97g7q9Afbad301sA"

HttpWebResponse? response = httpPost("https://www.google.com/reader/api/0/token/edit-tag/client", args);

private HttpWebResponse? httpPost(string requestUrl, string postArgs) {
byte buffer = Encoding.GetEncoding?(1252).GetBytes?(postArgs); //byte buffer = Encoding.GetEncoding?(65001).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; request.Headers.Add("Authorization", "GoogleLogin? auth=" + auth);
Stream PostData? = request.GetRequestStream?();
PostData?.Write(buffer, 0, buffer.Length); PostData?.Close();
try {
return (HttpWebResponse?)request.GetResponse?();
} catch(Exception ee) {
MessageBox?.Show(ee.Message); return null;
}
}

it got "404 error"! who can help me!thx

Comment by rain.bipper@gmail.com, Jan 21, 2011

It seemed that one can clear "state/com.google/read" state only if entry have "state/com.google/fresh". Otherwise read state is not cleared though request returns "OK"

Comment by mrc...@gmail.com, Jan 28, 2011

for edit-tag reqiest you should send following post fields:

i - for id of item (eg. tag:google.com,2005:reader/item/b1b915a7dfa70337)

a or r - for add or remove tag name (eg. user/-/label/tagname)

s - for feed url of item starting with feed/ (eg. feed/http://habrahabr.ru/rss/)

T - for token

Comment by hoveyda...@gmail.com, Feb 7, 2011

when using ios make sure you add

NSString authHeader = stringWithFormat:@"GoogleLogin %@", authString?;

addValue:authHeader forHTTPHeaderField:@"Authorization"?;

to every GET

Comment by rain.bipper@gmail.com, Feb 11, 2011

Some specific behaviour: items in "starred" folder always have "fresh" label, so always can be marked as "unread"; if this very entry in original folder doesn't have "fresh" label, then unread states may differs in original and "starred" folders. If entry in original folder have "fresh" label, then unread state reflects such state in "starred" folder. weird. if you get entryes filtered by "starred" label, you cant'be sure if entry is in "read" state in original folder. seemes as some bug in GoogleReader? logic.

Comment by nemesis...@gmail.com, Mar 23, 2011

I'm trying to add a feed to my Google reader account with a call to http://www.google.com/reader/api/0/subscription/edit but I'm getting an error saying "POST requests require a Content-length header." This is using curl in PHP. I can log in and get a token, the next step is where I get the error. Here is my code:

$ch = curl_init();

$data = array('accountType' => 'GOOGLE', 'Email' => 'user@domain.com', 'Passwd' => 'password', 'source'=>'nameyourapp', 'service'=>'reader');

curl_setopt($ch, CURLOPT_URL, "https://www.google.com/accounts/ClientLogin"); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

$loginResult = curl_exec($ch);

$authRaw = strstr($loginResult, "Auth"); $authToken = substr($authRaw, 5); $header = 'Authorization: GoogleLogin?? auth='.$authToken;

curl_setopt($ch, CURLOPT_URL, "http://www.google.com/reader/api/0/token"); curl_setopt($ch, CURLOPT_POST, false); curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$token = curl_exec($ch);

//everything works fine up to here

$data = array('s' => 'http://feeds.feedburner.com/TechCrunch', 'ac' => 'subscribe', 'a' => 'user/-/label/techcrunch', 'token'=> $token); $data = http_build_query($data); $header = 'Content-length: ' . strlen($data);

curl_setopt($ch, CURLOPT_URL, "http://www.google.com/reader/api/0/subscription/edit?client=contact:user@domain.com"); curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

$result = curl_exec($ch); curl_close($ch);

print ($result);

As you can see, I am sending the content-length header. But the error makes it sound like it's not even there. I've searched Google and found other people having this error message with different Google services, but none of them seem to be able to resolve the issue. Some of them make it sound like it's a problem on Google's end. Please help!

Comment by jatinjai...@gmail.com, Apr 26, 2011

Hi Whenever i try to subscribe a url on google reader, getting below error

//nCt3Vgbs0Xgj7Jx_jNpWvQ<html><head><title>400 Client Error</title>

first I try to get token, I am getting token from this url http://www.google.com/reader/api/0/token response //nCt3Vgbs0Xgj7Jx_jNpWvQ saving token string in pStrToken? = nCt3Vgbs0Xgj7Jx_jNpWvQ then i try to send subscribe url to google reader http://www.google.com/reader/api/0/subscription/quickadd?ck=<timestamp>&client=FeedViewer?&quickadd=<feed://timesofindia.feedsportal.com/c/33039/f/533915/index.rss>&ac=subscribe&token=<nCt3Vgbs0Xgj7Jx_jNpWvQ>

and always getting error.

Please see my iphone code #define SUBSCRIBE_URL @"http://www.google.com/reader/api/0/subscription/quickadd?ck=%@&client=FeedViewer&quickadd=%@&ac=subscribe&token=%@" #define SUBSCRIBE_URL_VALUE @"feed%2Fhttp://feeds.feedburner.com/TechCrunch?" pStrToken?= nCt3Vgbs0Xgj7Jx_jNpWvQ ;

NSTimeInterval timeInterval = [date? timeIntervalSince1970];

NSString unixTime = stringWithFormat:@"%f", (float)timeInterval?;

NSString codedString = stringWithFormat:SUBSCRIBE_URL,unixTime,SUBSCRIBE_URL_VALUE,[self pStrToken?] ; NSString lencodedString=stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding?; NSURL lurl = URLWithString:lencodedString?; if(!lurl)
return;
[sharedURLCache? setMemoryCapacity:0]; [sharedURLCache? setDiskCapacity:0]; NSMutableURLRequest
lrequestURL = requestWithURL:lurl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:25?; setHTTPMethod:@"POST"?;
NSURLConnection iConnection = [alloc? initWithRequest:lrequestURL delegate:self];
if(!iConnection)
NSLog(@"failed to create connection");

Please suggest if I am doing any thing wrong.

Comment by mauroasp...@gmail.com, May 4, 2011

Following this http://code.google.com/apis/accounts/docs/OAuth2.html I managed to get an OAuth2 access_token, but I can't make use of it... Keep returning Status=Unauthorized - 401

To use the OAuth flow u can try to set the scope? param:

Example:

https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=<your_client_id>&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=https%3A%2F%2Fwww.google.com%2Freader%2Fapi%2F0%2F

If anybody figure this out, please share it :D

I have forked a fork of this class here ;) https://github.com/brutuscat/googlereader. It currently works so try it :D

Comment by gia...@gmail.com, May 15, 2011

Is there a way to get a feed of your starred news items, BUT only for a certain folder or tag (or even feed).

My idea is to put this rss feed into Boxee so I see only my starred YouTube? Subscription video, and not all of them like at the moment. http://gdata.youtube.com/feeds/base/users/USERNAME/newsubscriptionvideos

http://googlesystem.blogspot.com/2009/05/feed-for-youtube-subscriptions.html

Comment by joe...@gmail.com, May 23, 2011

Does kept-unread mean the box was specifically only checked marked and tracking-kept-unread will be a superset of kept-unread?

Comment by christop...@gmail.com, Jun 6, 2011

Here is a class I have developed, in order to use this Google Reader API in JAVA : http://lewebenbien.wordpress.com/2011/06/06/google-reader-api/ Hope that could be useful for someone else :)

Comment by TheBootroo@gmail.com, Jul 6, 2011

hello i want to add smart feed adding to my program, so i need the api url to retreive a feed list maching a keyword (in browser the page is http://www.google.fr/reader/view/?#directory-search/<MY_KEYWORD>//0 ) thanks a lot PS :the page can retreive multiple times the same url in results but i want only one time each (maybe an additional parameter). i want results as a list of subscriptions : - string:title - string:url - int:nbsuscribers - float:nbnewsbyweek - bool:suscribed (no mandatory, since i can compute it myself)

Comment by TheBootroo@gmail.com, Jul 6, 2011

hello i want to add smart feed adding to my program, so i need the api url to retreive a feed list maching a keyword (in browser the page is http://www.google.fr/reader/view/?#directory-search/<MY_KEYWORD>//0 ) thanks a lot PS :the page can retreive multiple times the same url in results but i want only one time each (maybe an additional parameter). i want results as a list of subscriptions : - string:title - string:url - int:nbsuscribers - float:nbnewsbyweek - bool:suscribed (no mandatory, since i can compute it myself)

Comment by ahmedja...@gmail.com, Aug 21, 2011

Hello, i am using unofficial Google Reader Api in my iPhone application. I am facing problem in syncing my app with google reader. if any item become read from unRead state by clicking on in browser then how i can permit this change in my app?. How i can get all items that are clicked as read in the browser, and retrieve in iphone app?? Thanks in Advance..

Comment by Arow...@gmail.com, Nov 21, 2011

This document should be update now, to see http://undoc.in/googlereader.html

Comment by walter.s...@medunigraz.at, Nov 29, 2011

HI , please one question. I want to get 999 atoms for one particular user. It works like http://www.google.com/reader/atom/user%2F14750707885618507930%2Fstate%2Fcom.google%2Freading-list but here I onle get 20 items. How can I get 999 Items? Thanks

Comment by Alexande...@gmail.com, Dec 1, 2011

You should use parameter n (count).

Comment by Alexande...@gmail.com, Dec 1, 2011

Hello everyone. Need help. I try to set a star for feed.

I use these params as post args: key = i, value =tag:google.com,2005:reader/item/88a3ce8e14832f39

key = T, value =eMMPqk1Ls1gA6EIi5ml0nw

key = async, value =true

key = a, value =user/-/state/com.google/starred

key = ac, value =edit-tags

These params I use for header args:

key = client, value =googlereader-ios-client

key = ck, value =1322744198

In reply I get html with an error "There was an error in your request.". The same error occurs when I try to mark a feed as read, favourite and others.

Comment by IAmSe...@gmail.com, Jan 4, 2012

Does Google Alert (via ATOM Feed) include social mentions (in FB, TW, G+) ?

Comment by valeh.ha...@gmail.com, Jan 13, 2012

What does "published" and "updated" fields mean? Is it a date ? If it is date then explain what does "1325880983" mean as date ?

Comment by richardfearn, Jan 14, 2012

@Valeh: They are UNIX timestamps. See http://en.wikipedia.org/wiki/Unix_time. 1325880983 corresponds to Fri, 06 Jan 2012 20:16:23 GMT.


Sign in to add a comment
Powered by Google Project Hosting