With the AJAX Feed API, you can download any public Atom or RSS feed using only JavaScript, so you can easily mash up feeds with your content and other APIs like the Google Maps API. For Flash, and other Non-Javascript environments, the API exposes a raw RESTful interfaceNew! that returns JSON encoded results that are easily processed by most languages and runtimes.
This documentation is designed for people familiar with JavaScript programming and object-oriented programming concepts. There are many JavaScript tutorials available on the Web.
With the AJAX Feed API, you can download any public Atom or RSS feed using only JavaScript, so you can easily mash up feeds with your content and other APIs like the Google Maps API. See the program below for a simple example.
JavaScript and XMLHttpRequest
use the Same-Origin Policy (SOP). With this policy, scripts can access data from the same host from which the containing page of HTML was served, but not other hosts. This protects users from certain classes of scripting attacks, but prevents many developers from writing AJAX-based mashups. The Google AJAX Feed API offers a simple workaround to these restrictions for a specific type of content available on the web: syndication feeds. See the security notes below for more details about how the AJAX Feed API preserves user security.
The easiest way to start learning about this API is to see a simple example. The following example downloads the Digg RSS feed and displays the feed entry titles to the user:
<html> <head> <script type="text/javascript" src="http://www.google.com/jsapi?key=YOUR_KEY_HERE"></script> <script type="text/javascript"> google.load("feeds", "1"); function initialize() { var feed = new google.feeds.Feed("http://www.digg.com/rss/index.xml"); feed.load(function(result) { if (!result.error) { var container = document.getElementById("feed"); for (var i = 0; i < result.feed.entries.length; i++) { var entry = result.feed.entries[i]; var div = document.createElement("div"); div.appendChild(document.createTextNode(entry.title)); container.appendChild(div); } } }); } google.setOnLoadCallback(initialize); </script> </head> <body> <div id="feed"></div> </body> </html>
You can download this example to edit and play around with it, but you'll have to replace the key in that file with your own Google API key.
To include the AJAX Feed API in your page, you need to both include the Google AJAX APIs script tag and call google.load("feeds", "1")
:
<script type="text/javascript" src="http://www.google.com/jsapi?key=YOUR_KEY_HERE"></script> <script type="text/javascript"> google.load("feeds", "1"); </script>
The first script tag loads the google.load
function, which lets you load individual Google APIs. google.load("feeds", "1")
loads Version 1 of the feeds API. Currently the AJAX Feed API is in Version 1, but new versions may be available in the future. See the versioning discussion below for more information.
Loading the API requires two steps because Google is moving to a new model of loading AJAX APIs to make it easier to include multiple Google APIs on your pages. Subscribe to the Google AJAX APIs Blog for announcements as we start rolling out this new AJAX API loading mechanism.
The AJAX Feed API can return feeds in two formats: JSON and XML. By default, the API returns the feed in the JSON format.
The AJAX Feed API JSON format is an abbreviated, canonicalized version of the original feed. It maps Atom and RSS attributes like title
, description
, and summary
to a set of common JSON properties so that you can access Atom and RSS feeds uniformly. For example, the JSON result format returns RSS attribute description
as the JSON property content
, just like Atom. Likewise, the RSS element pubDate
is returned as the JSON property publishedDate
to make the results uniform with Atom feeds. The JSON result format is useful if you only want to access standard RSS and Atom elements, and you don't want to worry about the differences between feed formats. See the JSON example below or JSON result format specification for information.
If you specify the XML result format with setResultFormat
, the AJAX Feed API will return the complete feed XML instead of JSON results. You can access the XML document with the standard XML DOM functions built into the browser. The XML result format is useful if you prefer using DOM functions to JSON or you need to access extension elements in the feed, like digg:diggCount
. See the XML example below or XML result format specification for information.
You can also use both the JSON properties and the XML document to get the benefits of canonicalized attributes and access to XML extension elements. See the combined XML/JSON example below that uses the JSON attributes to access all of the entries in the feed, but uses the XML DOM to get the custom Digg digg:diggVotes
element in the feed.
The second argument to google.load
is the version of the AJAX Feed API you are using. Currently the AJAX Feed API is in version 1, but new versions may be available in the future.
If we do a significant update to the API in the future, we will change the version number and post a notice on Google Code and the AJAX APIs discussion group. When that happens, we expect to support both versions for at least a month in order to allow you to migrate your code.
The AJAX Feed API team periodically updates the API with the most recent bug fixes and performance enhancements. These bug fixes should only improve performance and fix bugs, but we may inadvertently break some API clients. Please use the AJAX APIs discussion group to report such issues.
This example downloads a single feed and displays the title of each entry to the user.
var feed = new google.feeds.Feed("http://www.digg.com/rss/index.xml"); feed.load(function(result) { if (!result.error) { var container = document.getElementById("feed"); for (var i = 0; i < result.feed.entries.length; i++) { var entry = result.feed.entries[i]; var div = document.createElement("div"); div.appendChild(document.createTextNode(entry.title)); container.appendChild(div); } } });
View example (helloworld.html)
This example is similar to the simple example above, but it displays most of the canonical JSON properties exposed by the AJAX Feed API. See the JSON result format specification for information.
var feed = new google.feeds.Feed("http://www.digg.com/rss/index.xml"); feed.load(function(result) { if (!result.error) { var container = document.getElementById("feed"); for (var i = 0; i < result.feed.entries.length; i++) { var entry = result.feed.entries[i]; var attributes = ["title", "link", "publishedDate", "contentSnippet"]; for (var j = 0; j < attributes.length; j++) { var div = document.createElement("div"); div.appendChild(document.createTextNode(entry[attributes[j]])); container.appendChild(div); } } } });
The following examples show how to access an RSS and Atom feed through the XML DOM rather than using the JSON results returned by the
AJAX Feed API. The difference between accessing the two feeds is that the RSS example uses the RSS elements such as item
and the Atom example uses Atom elements such as entry
.
The first example directly accesses an RSS feed through the XML DOM. In the example, we take advantage of the getElementsByTagNameNS
included in the AJAX Feed API to access the diggCount
extension element in the Digg feed, which lets us display the number of votes next to the title in the output.
var feed = new google.feeds.Feed("http://www.digg.com/rss/index.xml"); feed.setResultFormat(google.feeds.Feed.XML_FORMAT); feed.load(function(result) { var container = document.getElementById("feed"); if (!result.error) { var items = result.xmlDocument.getElementsByTagName("item"); for (var i = 0; i < items.length; i++) { var titleElement = items[i].getElementsByTagName("title")[0]; var title = titleElement.firstChild.nodeValue; var votesElement = google.feeds.getElementsByTagNameNS(items[i], "http://digg.com/docs/diggrss/", "diggCount")[0]; var votes = votesElement.firstChild.nodeValue; var div = document.createElement("div"); div.appendChild(document.createTextNode(title + " (" + votes + " votes)")); container.appendChild(div); } } });
The second example directly accesses an Atom feed through the XML DOM. In this example, we again take advantage of the getElementsByTagNameNS
included in the AJAX Feed API to access the elements in the Google Base feed.
var feed = new google.feeds.Feed("http://www.google.com/base/feeds/snippets"); feed.setResultFormat(google.feeds.Feed.XML_FORMAT); feed.load(function(result) { var container = document.getElementById("feed"); if (!result.error) { var entries = google.feeds.getElementsByTagNameNS(result.xmlDocument, "http://www.w3.org/2005/Atom", "entry"); for (var i = 0; i < entries.length; i++) { var titleElement = google.feeds.getElementsByTagNameNS(entries[i], "http://www.w3.org/2005/Atom", "title")[0]; var title = titleElement.firstChild.nodeValue; var priceElement = google.feeds.getElementsByTagNameNS(entries[i], "http://base.google.com/ns/1.0", "price")[0]; var price = priceElement.firstChild.nodeValue; var div = document.createElement("div"); div.appendChild(document.createTextNode(title + " (" + price + ")")); container.appendChild(div); } } });
This example reproduces the output of the XML example above, but combines usage of the JSON result format and access to the XML DOM. We iterate over all of the elements in the feed using the JSON data structure returned by the AJAX Feed API, and we use the special xmlNode
pointer in each JSON result to access the element in the XML DOM corresponding to that entry. We use that XML element and getElementsByTagNameNS
to access the diggCount
extension element, which gives us access to the number of votes for that Digg story.
var feed = new google.feeds.Feed("http://www.digg.com/rss/index.xml"); feed.setResultFormat(google.feeds.Feed.MIXED_FORMAT); feed.load(function(result) { if (!result.error) { var container = document.getElementById("feed"); for (var i = 0; i < result.feed.entries.length; i++) { var entry = result.feed.entries[i]; var votesElement = google.feeds.getElementsByTagNameNS(entry.xmlNode, "http://digg.com/docs/diggrss/", "diggCount")[0]; var votes = votesElement.firstChild.nodeValue; var div = document.createElement("div"); div.appendChild(document.createTextNode(entry.title + " (" + votes + "votes)")); container.appendChild(div); } } });
This example uses the higher level google.feeds.FeedControl
class to
display a collection of feeds. This class is similar to the AJAX Search API's Search Control layer
GSearchControl.
This example creates a FeedControl class, adds two feeds into the class, and then tells the feed control to draw.
<html> <head> <script type="text/javascript" src="http://www.google.com/jsapi?key="YOUR-KEY"></script> <script type="text/javascript"> google.load("feeds", "1"); function initialize() { var feedControl = new google.feeds.FeedControl(); feedControl.addFeed("http://www.digg.com/rss/index.xml", "Digg"); feedControl.addFeed("http://feeds.feedburner.com/Techcrunch", "TechCrunch"); feedControl.draw(document.getElementById("feedControl")); } google.setOnLoadCallback(initialize); </script> </head> <body> <div id="feedControl">Loading</div> </body> </html>
View example (feedcontrol.html)
These two examples use the global methods, google.feeds.findFeeds
and google.feeds.lookupFeed
, to discover feeds based on search terms and to lookup feeds associated with standard web pages.
The first sample uses the google.feeds.findFeeds
to dynamically populate a FeedControl based on search terms.
<html> <head> <script type="text/javascript" src="http://www.google.com/jsapi?key="YOUR-KEY"></script> <script type="text/javascript"> google.load("feeds", "1"); var defaultQuery = 'Official Google Blogs'; function findFeeds(query) { google.feeds.findFeeds(query, feedSearchDone); } function feedSearchDone(result) { var el = document.getElementById('feedControl'); if (result.error || result.entries.length <= 0) { el.innerHTML = 'No Results Found'; return; } // Create a feed control var feedControl = new google.feeds.FeedControl(); // Grab top 4.. for (var i = 0; i < 4; i++) { feedControl.addFeed(result.entries[i].url, result.entries[i].title); } feedControl.setLinkTarget(google.feeds.LINK_TARGET_BLANK); feedControl.setNumEntries(2); feedControl.draw(el); } google.setOnLoadCallback(function() {findFeeds(defaultQuery)}); </script> </head> <body> <div id="feedControl">Loading</div> </body> </html>
The second sample uses the google.feeds.lookupFeed
to get the feed associated with a public Flickr web page for a given user and then dynamically populate a slideshow.
<html> <head> <script type="text/javascript" src="http://www.google.com/jsapi?key="YOUR-KEY"></script> <script type="text/javascript"> google.load("feeds", "1"); var defaultUser = 'dlc0421'; function newSlideShow(user) { showStatus('Resolving feed for ' + user); var url = 'http://www.flickr.com/photos/' + user; google.feeds.lookupFeed(url, lookupDone); } function lookupDone(result) { if (result.error || result.url == null) { showStatus('Could not locate feed for user'); return; } showStatus('Found Photo Feed'); // We need to switch over from Atom to RSS to get Yahoo Media for slideshow.. var url = result.url.replace('format=atom', 'format=rss_200'); showSlideShow(url); } function showSlideShow(url) { var options = { displayTime: 2500, transistionTime: 800, scaleImages: true, thumbnailTag: 'content', linkTarget : google.feeds.LINK_TARGET_BLANK }; new GFslideShow(url, "slideshow", options); } google.setOnLoadCallback(function() {newSlideShow(defaultUser)}); </script> </head> <body> <div id="feedControl">Loading</div> </body> </html>
The Google AJAX Feed API supports the following feed formats:
The Google AJAX Feed API now supports additional global methods, google.feeds.findFeeds
and google.feeds.lookupFeed
which can be used to search for relevant feeds and lookup the associated feed for an HTML based URL.
The Google AJAX Feed API crawls feeds with Feedfetcher, which is also used for Google Reader and the Google personalized homepage. See the Google Webmaster Help Center for details on Feedfetcher.
As the Google AJAX Feed API uses Feedfetcher, feed data from the AJAX Feed API may not always be up to date. The Google feed crawler ("Feedfetcher") retrieves feeds from most sites less than once every hour. Some frequently updated sites may be refreshed more often.
Microsoft Internet Explorer does not support DOM Level 2, which means that it does not support namespace-aware DOM functions like getElementsByTagNameNS
. The Google AJAX Feed API includes a cross-browser implementation of getElementsByTagNameNS
since it is a common requirement for sites consuming feeds. The API does not include implementations of any other DOM Level 2 methods at this time.
For Flash developers, and those developers that have a need to access the AJAX Feed API from other Non-Javascript environments,
the API exposes a simple RESTful interface. In all cases, the method supported is GET
and the response format is a
JSON encoded result with embedded status codes. Applications that use this interface must abide by
all existing terms of use. An area to pay special attention to relates to correctly identifying
yourself in your requests. Applications MUST always include a valid and accurate http referer header
in their requests. In addition, we ask, but do not require, that each request contains a valid API Key. By providing a key, your application
provides us with a secondary identification mechanism that is useful should we need to contact you in order to correct any problems.
The easiest way to start learning about this interface is to try it out... Using the command line tool curl
or wget
execute the
following command:
curl -e http://www.my-ajax-site.com \ 'http://ajax.googleapis.com/ajax/services/feed/load?q=http%3A%2F%2Fwww.digg.com%2Frss%2Findex.xml&v=1.0'
This command performs a Feed Load
(/ajax/services/feed/load
), for the
Digg.com feed
(q=http%3A%2F%2Fwww.digg.com%2Frss%2Findex.xml
). The
response has a Content-Type
of
text/javascript; charset=utf-8
. You can see from the
response below that the responseData
is identical to
the properties described in the JSON
Result Format documentation. See this table mapping methods to base
URLS for details on how the various
access methods described in the previous sections are made
available through the REST API.
{"responseData": { "feed": { "title": "Digg", "link": "http://digg.com/", "author": "", "description": "Digg", "type": "rss20", "entries": [ { "title": "The Pirate Bay Moves Servers to Egypt Due to Copyright Laws", "link": "http://digg.com/tech_news/The_Pirate_Bay_Moves_Servers_to_Egypt_Due_to_Copyright_Laws", "author": "", "publishedDate": "Mon, 31 Mar 2008 23:13:33 -0700", "contentSnippet": "Due to the new copyright legislation that are going ...", "content": "Due to the new copyright legislation that are going to take...", "categories": [ ] }, { "title": "Millions Dead/Dying in Recent Mass-Rick-Rolling by YouTube.", "link": "http://digg.com/comedy/Millions_Dead_Dying_in_Recent_Mass_Rick_Rolling_by_YouTube", "author": "", "publishedDate": "Mon, 31 Mar 2008 22:53:30 -0700", "contentSnippet": "Click on any \u0022Featured Videos\u0022. When will the insanity stop?", "content": "Click on any \u0022Featured Videos\u0022. When will the insanity stop?", "categories": [ ] }, ... ] } } , "responseDetails": null, "responseStatus": 200}
In addition to this response format, the protocol also supports a classic JSON-P style callback which is triggered by
specifying a callback
argument. When this argument is present
the json object is delivered as an argument to the specified callback.
curl -e http://www.my-ajax-site.com \ 'http://ajax.googleapis.com/ajax/services/feed/load?q=http%3A%2F%2Fwww.digg.com%2Frss%2Findex.xml&v=1.0&callback=foo'
This command performs a Feed Load that is identical to the previous load, BUT has been altered to pass callback
. With this
argument in place, instead of a JSON object being returned, a Javascript call is returned in the response and the JSON object is passed via the results
parameter.
foo({"responseData": { "feed": { "title": "Digg", "link": "http://digg.com/", "author": "", "description": "Digg", "type": "rss20", "entries": [ { "title": "The Pirate Bay Moves Servers to Egypt Due to Copyright Laws", "link": "http://digg.com/tech_news/The_Pirate_Bay_Moves_Servers_to_Egypt_Due_to_Copyright_Laws", "author": "", "publishedDate": "Mon, 31 Mar 2008 23:13:33 -0700", "contentSnippet": "Due to the new copyright legislation that are going ...", "content": "Due to the new copyright legislation that are going to take...", "categories": [ ] }, { "title": "Millions Dead/Dying in Recent Mass-Rick-Rolling by YouTube.", "link": "http://digg.com/comedy/Millions_Dead_Dying_in_Recent_Mass_Rick_Rolling_by_YouTube", "author": "", "publishedDate": "Mon, 31 Mar 2008 22:53:30 -0700", "contentSnippet": "Click on any \u0022Featured Videos\u0022. When will the insanity stop?", "content": "Click on any \u0022Featured Videos\u0022. When will the insanity stop?", "categories": [ ] }, ... ] } } , "responseDetails": null, "responseStatus": 200})
And finally, the protocol supports a callback
and context
argument. When these url arguments
are specified, the response is encoded as a direct Javascript call with a signature of: callback(context, feed, status, details, unused)
.
Note the slight difference in the following command and response.
curl -e http://www.my-ajax-site.com \ 'http://ajax.googleapis.com/ajax/services/feed/load?q=http%3A%2F%2Fwww.digg.com%2Frss%2Findex.xml&v=1.0&callback=foo&context=bar'
This command performs a Feed load and is identical to the previous load, BUT has been altered to pass both callback
and context
. With these
arguments in place, instead of a JSON object being returned, a Javascript call is returned in the response and the JSON object is passed via the feed
parameter.
foo('bar', { "feed": { "title": "Digg", "link": "http://digg.com/", "author": "", "description": "Digg", "type": "rss20", "entries": [ { "title": "The Pirate Bay Moves Servers to Egypt Due to Copyright Laws", "link": "http://digg.com/tech_news/The_Pirate_Bay_Moves_Servers_to_Egypt_Due_to_Copyright_Laws", "author": "", "publishedDate": "Mon, 31 Mar 2008 23:13:33 -0700", "contentSnippet": "Due to the new copyright legislation that are going ...", "content": "Due to the new copyright legislation that are going to take...", "categories": [ ] }, { "title": "Millions Dead/Dying in Recent Mass-Rick-Rolling by YouTube.", "link": "http://digg.com/comedy/Millions_Dead_Dying_in_Recent_Mass_Rick_Rolling_by_YouTube", "author": "", "publishedDate": "Mon, 31 Mar 2008 22:53:30 -0700", "contentSnippet": "Click on any \u0022Featured Videos\u0022. When will the insanity stop?", "content": "Click on any \u0022Featured Videos\u0022. When will the insanity stop?", "categories": [ ] }, ... ] } } , 200, null)
For complete documentation on this interface, please visit the class reference manual.
JavaScript uses the Same-Origin Policy (SOP) to prevent malicious scripts from accessing private user data. See the Security for GWT Applications article for an in-depth discussion on the implications of this policy and other JavaScript security issues.
The AJAX Feed API does not send any private information to the host of the requested feeds (e.g., digg.com
). Google's crawler Feedfetcher downloads the feeds anonymously, and Google's servers act as a cache for that feed for all requests made with the AJAX Feed API. The AJAX Feed API only provides access to publicly accessible feeds.
If you encounter problems with your code: