├── .gitignore ├── LICENSE ├── README.md ├── graphics ├── README.md ├── icon.pdf ├── icon.png ├── icon.svg └── jsonfeed.sketch ├── pages ├── code.markdown ├── mappingrssandatom.markdown └── version │ ├── 1.1.markdown │ └── 1.markdown ├── posts └── 2017 │ └── 05 │ └── 17 │ └── announcing_json_feed.markdown ├── snippets ├── footer.html └── header.html ├── styles └── styleSheet.css └── templates ├── archive_index.html ├── archive_month.html ├── archive_single_post.html ├── blog_home.html ├── page.html ├── post.html ├── post_including_link.html ├── post_including_link_no_title.html ├── post_no_title.html └── rss /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | wildcat_settings 4 | 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSONFeed 2 | This is the repository for the [JSONFeed.org](https://jsonfeed.org/) website. It contains the Markdown files and supporting resources, not the actual rendered website. 3 | 4 | The current spec, and any older specs (if we ever do more than one), are in the [pages/version/](https://github.com/brentsimmons/JSONFeed/blob/master/pages/version/) folder. 5 | -------------------------------------------------------------------------------- /graphics/README.md: -------------------------------------------------------------------------------- 1 | # Graphics 2 | 3 | You can use the graphics (by [Craig Hockenberry](http://furbo.org/)) on your own site when linking to your JSON Feed. As with the familiar RSS icon, you can modify the image to suit your needs, but keep in mind that the symbol and color scheme will help people understand what you're doing. 4 | 5 | The images are available as a PNG bitmap or as vectors in both SVG and PDF. These files were created using `jsonfeed.sketch` which can be opened with [Sketch](https://sketchapp.com/). -------------------------------------------------------------------------------- /graphics/icon.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manton/JSONFeed/7fed7625c6646942d4a6c9f3cabde75e2092a58c/graphics/icon.pdf -------------------------------------------------------------------------------- /graphics/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manton/JSONFeed/7fed7625c6646942d4a6c9f3cabde75e2092a58c/graphics/icon.png -------------------------------------------------------------------------------- /graphics/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /graphics/jsonfeed.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manton/JSONFeed/7fed7625c6646942d4a6c9f3cabde75e2092a58c/graphics/jsonfeed.sketch -------------------------------------------------------------------------------- /pages/code.markdown: -------------------------------------------------------------------------------- 1 | @title Code 2 | # Code 3 | 4 | * [WordPress plugin](https://github.com/manton/jsonfeed-wp) by Manton Reece 5 | * [Drupal module](https://www.drupal.org/project/json_feed) by Karl Shea 6 | * [Swift parsing library](https://github.com/totocaster/JSONFeed) by Toto Tvalavadze 7 | * [Swift parsing library](https://github.com/wesbillman/JSONFeed) by Wes Billman 8 | * [Go package](https://github.com/st3fan/jsonfeed) by Stefan Arentz 9 | * [Go package](https://github.com/kr/jsonfeed) by Keith Rarick 10 | * [Jekyll feed template](https://github.com/vallieres/jekyll-json-feed) by Alexandre Vallières-Lagacé 11 | * [Jekyll feed with attachments](https://github.com/tedchoward/tidbits/blob/master/feed.json) by Ted Howard 12 | * [Movable Type template](https://gist.github.com/walt/8da71fead3b8ba321f91efd954f0cb32) by Walt Grayson 13 | * [Movable Type template and EscapeForJSON](https://daringfireball.net/projects/mt-escapeforjson/) by John Gruber 14 | * [Craft CMS with Element API](https://github.com/craftcms/element-api/tree/v1#json-feed) by Pixel & Tonic 15 | * [Rust crate](https://crates.io/crates/jsonfeed) by Paul Woolcock 16 | * [Hugo feed template](https://gist.github.com/voidfiles/302e8d690a5ef4990e371ce70bca3240) by Alex Kessinger 17 | * [Hugo feed template](https://github.com/frjo/hugo-theme-zen/blob/master/layouts/_default/list.json.json) by Fredrik Jonsson 18 | * [Python feed validator](https://github.com/voidfiles/jsonfeedvalidator) by Alex Kessinger 19 | * [Ruby feedparser gem](http://www.rubyflow.com/p/a57is4-added-new-json-feed-jsonfeed-format-to-the-universal-feedparser-gem) support added by Gerald Bauer 20 | * [RSS/Atom to JSON Feed converter](https://github.com/appsattic/feed2json.org) and [web service](https://feed2json.org) by Andrew Chilton 21 | * [PHP JSON Feed Generator](https://github.com/mateusjatenee/php-json-feed) by Mateus Guimarães 22 | * [PHP JSONFeed library](https://github.com/jdecool/jsonfeed) by Jérémy DECOOL 23 | * [PHP feed-io library](https://feed-io.net) by Alexandre Debril 24 | * [Metalsmith plugin](https://github.com/bensmithett/metalsmith-json-feed) by Ben Smithett 25 | * [Pelican plugin](https://github.com/andrewheiss/pelican_json_feed) by Andrew Heiss 26 | * [Pelican feed template](https://github.com/andrewheiss/athpelican/blob/master/theme/templates/feed.json) by Andrew Heiss 27 | * [C# parsing library](https://github.com/gramgibson/jsonfeed) by Gram Gibson 28 | * [C# parsing & generator library](https://github.com/DanRigby/JsonFeed.NET) by Dan Rigby 29 | * [Crystal parser & generator library](https://github.com/DougEverly/jsonfeed.cr) by Doug Everly 30 | * [Ruby Feedjira gem](https://github.com/feedjira/feedjira) support added by Jonathan Pike 31 | * [FeedKit](https://github.com/nmdias/FeedKit) by Nuno Dias 32 | * [Scala parser & generator library](https://github.com/chobeat/scala-json-feed) by Simone Robutti 33 | * [Java parsing library](https://github.com/devilgate/pertwee) by Martin McCallion 34 | * [JS JSON Feed to Atom converter](https://github.com/bcomnes/jsonfeed-to-atom) by Bret Comnes 35 | * [JS JSON Feed to RSS converter](https://github.com/bcomnes/jsonfeed-to-rss) (with full Apple Podcast support) by Bret Comnes 36 | * [Perl5 JSON::Feed parser and generator](https://metacpan.org/pod/JSON::Feed) by Kang-min Liu 37 | * [Eleventy plugin](https://www.npmjs.com/package/eleventy-plugin-json-feed) by John SJ Anderson 38 | 39 | As more code is published, by us and others, we’ll add to this page. 40 | -------------------------------------------------------------------------------- /pages/mappingrssandatom.markdown: -------------------------------------------------------------------------------- 1 | @title Mapping RSS and Atom to JSON Feed 2 | # Mapping RSS and Atom to JSON Feed 3 | 4 | Though [RSS](http://cyber.harvard.edu/rss/rss.html) and [Atom](https://tools.ietf.org/html/rfc4287) are XML and [JSON Feed](https://jsonfeed.org/version/1.1) isn’t, there are a number of similarities. Here’s how to map them. 5 | 6 | ## RSS 7 | 8 | ### Channel 9 | 10 | While RSS has a `channel` top-level element, JSON Feed puts the corresponding information at the top level. 11 | 12 | * RSS `title` and `description` map directly to JSON. An RSS `link` maps to `home_page_url`. 13 | 14 | * `cloud` element is similar in purpose to the JSON Feed `hubs` item. 15 | 16 | * RSS has `webmaster` and `managingEditor` items, while JSON Feed has an `author` item. 17 | 18 | * `image` is superficially like a JSON Feed `icon` — except that the JSON Feed version should be square, and the RSS image should be wider than it is tall. These map only in the case that your RSS image is already square. 19 | 20 | ### Item 21 | 22 | RSS has an array of `item` objects, and so does JSON Feed. 23 | 24 | * `title` maps directly, with the caveat that it must be plain text in JSON Feed. (Note: `title` is optional in both RSS and JSON Feed.) 25 | 26 | * `link` maps to `url` and to `external_url`. The `url` must be a permalink, a link to the content of the item. When an item links to another page — as in a linkblog — then `external_url` must be the URL of that other page. (See the [Daring Fireball JSON feed](https://daringfireball.net/feeds/json) for an example.) 27 | 28 | * `description` maps to `content_html` and to `content_text`. Choose the one that fits. A Twitter-like service might use `context_text`, while a blog might use `content_html`. 29 | 30 | * `guid` maps to `id`. In RSS, `guid` can have an `isPermaLink` attribute; in JSON Feed the `url` must be the permalink, and `id` *may* be the same as `url`, though it doesn’t have to be. 31 | 32 | * The `author` element is a single value, while in JSON Feed it’s an object with `name`, `url`, and `avatar` values. 33 | 34 | * `pubDate` maps to `date_published`, but this date and others in JSON Feed use a different format, the RFC 3339 format. (Example: `2010-02-07T14:04:00-05:00`.) 35 | 36 | * `enclosure` maps to `attachments` — but JSON Feed allows for multiple attachments. An RSS `enclosure` has attributes `url`, `length`, and `type`, and the JSON Feed attachment object has corresponding elements `url`, `size_in_bytes`, and `mime_type`. JSON Feed adds `title` and `duration_in_seconds`. 37 | 38 | * `category` maps to `tags`. In RSS a `category` can have a `domain` attribute, and there’s no equivalent in JSON Feed. 39 | 40 | ## Atom 41 | 42 | ### Feed 43 | 44 | Unlike RSS's `channel` element, Atom puts many of the elements to describe a feed at the top level of the document, just like JSON Feed. 45 | 46 | * Atom's `title` maps directly to JSON Feed. 47 | 48 | * Atom uses `link` elements to show the relationship between the feed and other URLs. Without a `rel` attribute, or with `rel="alternate"`, Atom's `link` is equivalent to JSON Feed's `home_page_url`. With `rel="self"`, it maps to JSON Feed's `feed_url`. 49 | 50 | * Atom has `subtitle` and `id` elements. There is no mapping for these in JSON Feed, although `description` in JSON could be used instead of `subtitle`. 51 | 52 | * For WebSub, Atom uses `link` elements with `rel="hub"`. JSON Feed has a dedicated `hubs` array. 53 | 54 | ### Entry 55 | 56 | Atom has an array of `entry` objects. In JSON Feed these are `item` objects. 57 | 58 | * Atom's `title`, `id`, and `summary` map directly to JSON. In JSON, however, `title` and `summary` are always plain text. 59 | 60 | * Atom uses a content's `type` attribute to declare whether the text is plain text or HTML. `type="html"` or `type="xhtml"` in an Atom feed maps to `content_html` in JSON. `type="text"` maps to `content_text` in JSON. 61 | 62 | * `link` with `rel="alternate"` maps to `url` in JSON. If `rel="related"` is used for links to an external site, in JSON Feed those map to `external_url`. 63 | 64 | * The `author` element contains `name`, `uri`, and `email`, while in JSON Feed it's an object with `name`, `url`, and `avatar` values. 65 | 66 | * Atom's `published` and `updated` dates map to `date_published` and `date_modified` in JSON. Both Atom and JSON Feed use the same date format. 67 | 68 | * Atom's `link` with `rel="enclosure"` maps to `attachments` in JSON Feed. An Atom enclosure has attributes `href`, `length`, and `type`, and the JSON Feed attachment object has corresponding elements `url`, `size_in_bytes`, and `mime_type`. JSON Feed adds `title` and `duration_in_seconds`. -------------------------------------------------------------------------------- /pages/version/1.1.markdown: -------------------------------------------------------------------------------- 1 | @title Version 1.1 2 | # JSON Feed Version 1.1 3 | 4 | by Brent Simmons and Manton Reece 5 | 6 | The JSON Feed format is a pragmatic syndication format, like [RSS](http://cyber.harvard.edu/rss/rss.html) and [Atom](https://tools.ietf.org/html/rfc4287), but with one big difference: it’s JSON instead of XML. 7 | 8 | For most developers, JSON is *far* easier to read and write than XML. Developers may groan at picking up an XML parser, but decoding JSON is often just a single line of code. 9 | 10 | Our hope is that, because of the lightness of JSON and simplicity of the JSON Feed format, developers will be more attracted to developing for the open web. 11 | 12 | Here’s a simple example: 13 | 14 | { 15 | "version": "https://jsonfeed.org/version/1.1", 16 | "title": "My Example Feed", 17 | "home_page_url": "https://example.org/", 18 | "feed_url": "https://example.org/feed.json", 19 | "items": [ 20 | { 21 | "id": "2", 22 | "content_text": "This is a second item.", 23 | "url": "https://example.org/second-item" 24 | }, 25 | { 26 | "id": "1", 27 | "content_html": "
Hello, world!
", 28 | "url": "https://example.org/initial-post" 29 | } 30 | ] 31 | } 32 | 33 | It supports more than just the above, of course. 34 | 35 | ## Goals 36 | 37 | After making feeds easier to read and write, our second goal is to provide a format that’s self-documenting and difficult to do wrong. 38 | 39 | We also want to support: 40 | 41 | * Microblogs, which are often plain text and without titles. So much web writing today is Twitter-like, which is actually plain text. 42 | * Multiple attachments. 43 | * Modern needs such as avatar images, feed icons and favicons, and banner and featured images. Feed readers should not have to search and scrape to guess at these things. 44 | * A simple way to add extensions. 45 | 46 | (Note about plain text: on this page it means “not HTML” — emojis, for instance, are considered plain text.) 47 | 48 | ## The Structure of a Feed 49 | 50 | A JSON Feed is a list that may change over time, and the individual items in the list may change. 51 | 52 | Think of a blog or microblog, Twitter or Facebook timeline, set of commits to a repository, or even a server log. These are all lists, and each could be described by a feed. 53 | 54 | A JSON Feed starts with some info at the top: it says where the feed comes from, and may say who created it and so on. 55 | 56 | After that there’s an array of objects — `items` — that describe each object in the list. 57 | 58 | ### Top-level 59 | 60 | * `version` (required, string) is the URL of the version of the format the feed uses. This should appear at the very top, though we recognize that not all JSON generators allow for ordering. 61 | 62 | * `title` (required, string) is the name of the feed, which will often correspond to the name of the website (blog, for instance), though not necessarily. 63 | 64 | * `home_page_url` (optional but strongly recommended, string) is the URL of the resource that the feed describes. This resource may or may not actually be a “home” page, but it should be an HTML page. If a feed is published on the public web, this should be considered as required. But it may not make sense in the case of a file created on a desktop computer, when that file is not shared or is shared only privately. 65 | 66 | * `feed_url` (optional but strongly recommended, string) is the URL of the feed, and serves as the unique identifier for the feed. As with `home_page_url`, this should be considered required for feeds on the public web. 67 | 68 | * `description` (optional, string) provides more detail, beyond the `title`, on what the feed is about. A feed reader may display this text. 69 | 70 | * `user_comment` (optional, string) is a description of the purpose of the feed. This is for the use of people looking at the raw JSON, and should be ignored by feed readers. 71 | 72 | * `next_url` (optional, string) is the URL of a feed that provides the next n items, where n is determined by the publisher. This allows for pagination, but with the expectation that reader software is not required to use it and probably won’t use it very often. `next_url` must not be the same as `feed_url`, and it must not be the same as a previous `next_url` (to avoid infinite loops). 73 | 74 | * `icon` (optional, string) is the URL of an image for the feed suitable to be used in a timeline, much the way an avatar might be used. It should be square and relatively large — such as 512 x 512 pixels — so that it can be scaled-down and so that it can look good on retina displays. It should use transparency where appropriate, since it may be rendered on a non-white background. 75 | 76 | * `favicon` (optional, string) is the URL of an image for the feed suitable to be used in a source list. It should be square and relatively small, but not smaller than 64 x 64 pixels (so that it can look good on retina displays). As with `icon`, this image should use transparency where appropriate, since it may be rendered on a non-white background. 77 | 78 | * `authors` (optional, array of objects) specifies one or more feed authors. The author object has several members. These are all optional — but if you provide an author object, then at least one is required: 79 | 80 | * `name` (optional, string) is the author’s name. 81 | 82 | * `url` (optional, string) is the URL of a site owned by the author. It could be a blog, micro-blog, Twitter account, and so on. Ideally the linked-to page provides a way to contact the author, but that’s not required. The URL could be a mailto: link, though we suspect that will be rare. 83 | 84 | * `avatar` (optional, string) is the URL for an image for the author. As with `icon`, it should be square and relatively large — such as 512 x 512 pixels — and should use transparency where appropriate, since it may be rendered on a non-white background. 85 | 86 | * `language` (optional, string) is the primary language for the feed in the format specified in [RFC 5646](https://tools.ietf.org/html/rfc5646). The value is usually a 2-letter language tag from [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes), optionally followed by a region tag. (Examples: `en` or `en-US`.) 87 | 88 | * `expired` (optional, boolean) says whether or not the feed is finished — that is, whether or not it will ever update again. A feed for a temporary event, such as an instance of the Olympics, could expire. If the value is `true`, then it’s expired. Any other value, or the absence of `expired`, means the feed may continue to update. 89 | 90 | * `hubs` (very optional, array of objects) describes endpoints that can be used to subscribe to real-time notifications from the publisher of this feed. Each object has a `type` and `url`, both of which are required. See the section “Subscribing to Real-time Notifications” below for details. 91 | 92 | ### Items 93 | 94 | `items` is an array, and is required. An item includes: 95 | 96 | * `id` (required, string) is unique for that item for that feed over time. If an item is ever updated, the `id` should be unchanged. New items should never use a previously-used `id`. Ideally, the `id` is the full URL of the resource described by the item, since URLs make great unique identifiers. 97 | 98 | * `url` (optional, string) is the URL of the resource described by the item. It’s the permalink. This may be the same as the `id` — but should be present regardless. 99 | 100 | * `external_url` (very optional, string) is the URL of a page elsewhere. This is especially useful for linkblogs. If `url` links to where you’re talking about a thing, then `external_url` links to the thing you’re talking about. 101 | 102 | * `title` (optional, string) is plain text. Microblog items in particular may omit titles. 103 | 104 | * `content_html` and `content_text` are each optional strings — but one or both must be present. This is the HTML or plain text of the item. Important: the only place HTML is allowed in this format is in `content_html`. A Twitter-like service might use `content_text`, while a blog might use `content_html`. Use whichever makes sense for your resource. (It doesn’t even have to be the same for each item in a feed.) 105 | 106 | * `summary` (optional, string) is a plain text sentence or two describing the item. This might be presented in a timeline, for instance, where a detail view would display all of `content_html` or `content_text`. 107 | 108 | * `image` (optional, string) is the URL of the main image for the item. This image may also appear in the `content_html` — if so, it’s a hint to the feed reader that this is the main, featured image. Feed readers may use the image as a preview (probably resized as a thumbnail and placed in a timeline). 109 | 110 | * `banner_image` (optional, string) is the URL of an image to use as a banner. Some blogging systems (such as [Medium](https://medium.com/)) display a different banner image chosen to go with each post, but that image wouldn’t otherwise appear in the `content_html`. A feed reader with a detail view may choose to show this banner image at the top of the detail view, possibly with the title overlaid. 111 | 112 | * `date_published` (optional, string) specifies the date in [RFC 3339](https://tools.ietf.org/html/rfc3339) format. (Example: `2010-02-07T14:04:00-05:00`.) 113 | 114 | * `date_modified` (optional, string) specifies the modification date in RFC 3339 format. 115 | 116 | * `authors` (optional, array of objects) has the same structure as the top-level `authors`. If not specified in an item, then the top-level `authors`, if present, are the authors of the item. 117 | 118 | * `tags` (optional, array of strings) can have any plain text values you want. Tags tend to be just one word, but they may be anything. Note: they are not the equivalent of Twitter hashtags. Some blogging systems and other feed formats call these categories. 119 | 120 | * `language` (optional, string) is the language for this item, using the same format as the top-level `language` field. The value can be different than the primary language for the feed when a specific item is written in a different language than other items in the feed. 121 | 122 | #### Attachments 123 | 124 | An individual item may have one or more attachments. 125 | 126 | * `attachments` (optional, array) lists related resources. Podcasts, for instance, would include an attachment that’s an audio or video file. Each attachment has several members: 127 | 128 | * `url` (required, string) specifies the location of the attachment. 129 | 130 | * `mime_type` (required, string) specifies the type of the attachment, such as “audio/mpeg.” 131 | 132 | * `title` (optional, string) is a name for the attachment. Important: if there are multiple attachments, and two or more have the exact same `title` (when `title` is present), then they are considered as alternate representations of the same thing. In this way a podcaster, for instance, might provide an audio recording in different formats. 133 | 134 | * `size_in_bytes` (optional, number) specifies how large the file is. 135 | 136 | * `duration_in_seconds` (optional, number) specifies how long it takes to listen to or watch, when played at normal speed. 137 | 138 | ### Deprecations 139 | 140 | JSON Feed version 1 specified a singular `author` field instead of the `authors` array used in version 1.1. New feeds should use `authors`, even if only 1 author is needed. Existing feeds can include both `author` and `authors` for compatibility with existing feed readers. Feed readers should always prefer `authors` if present. 141 | 142 | Deprecated items remain valid forever, but you should move to the new fields when you can. A feed using fields from JSON Feed 1.0 is still a valid feed for version 1.1 and future versions of JSON Feed. 143 | 144 | ## Extensions 145 | 146 | Publishers can use custom objects in JSON Feeds. Names must start with an `_` character followed by a letter. Custom objects can appear anywhere in a feed. 147 | 148 | For instance, imagine a podcast directory service — call it Blue Shed Podcasts — that asks a podcaster to specify some additional information about a feed or item. A publisher would do something like this: 149 | 150 | "_blue_shed": { 151 | "about": "https://blueshed-podcasts.com/json-feed-extension-docs", 152 | "explicit": false, 153 | "copyright": "1948 by George Orwell", 154 | "owner": "Big Brother and the Holding Company", 155 | "subtitle": "All shouting, all the time. Double. Plus. Good." 156 | } 157 | 158 | Feed readers that do not understand a given custom object must ignore it. 159 | 160 | The `about` string is there for a human looking at the feed, so they can understand what goes in the custom extension. It’s optional, but it should appear at least once in a feed that may contain multiple uses of `_blue_shed` (preferably in the first use, but that’s not required). 161 | 162 | Also, it’s good practice to name an extension with a company or service name, to provide a clue right away as to what it’s for and who made it. 163 | 164 | Further naming rules: the extension name and its member keys must not contain any `.` characters. The extension name, and only the extension name, must begin with an `_` character. (No standard keys will ever begin with an `_` — this is reserved for extensions.) 165 | 166 | Member keys should be alphanumeric. That said, emojis are not illegal — we’re not heartless — and somebody’s going to use them. 167 | 168 | ## Subscribing to Real-time Notifications 169 | 170 | Traditional feed readers usually poll a web site for changes at a regular interval. This is fine for many applications, but there’s a more efficient approach for applications that need to know the moment a feed changes. The top-level `hubs` array points to one or more services that can be used by feed aggregators to subscribe to changes to this feed. Those hubs can then send a notification to the application as soon as the feed is updated. 171 | 172 | The `type` field describes the protocol used to talk with the hub, such as “rssCloud” or “WebSub.” When using WebSub, the value for the JSON Feed’s `feed_url` is passed for the `hub.topic` parameter. For more information about WebSub, see [the specification at the W3C](https://www.w3.org/TR/websub/). 173 | 174 | ## Future Compatibility 175 | 176 | A version 1 feed will be a valid version 2 feed, and so on. Future versions may add things, but won’t make older feeds invalid. 177 | 178 | ### Key Naming Rules 179 | 180 | In future versions, defined keys will always adhere to these rules: 181 | 182 | * Leading `_` characters are reserved for extensions. 183 | * Keys will be made of alphanumeric characters from the ASCII character set. 184 | * Keys will never contain a `.` character. 185 | 186 | ## Suggestions for Publishers 187 | 188 | JSON Feed files should be served using the MIME type `application/feed+json`. Many feeds will still use the more general MIME type `application/json`, which is common wherever JSON is served. When discovering a feed, apps must prefer `application/feed+json`, but should fall back to accepting `application/json` if no feeds using `application/feed+json` are available. 189 | 190 | The number of items in a feed is unlimited, but practical limits should be observed. A 1MB feed places a burden on feed readers, especially if there are many such feeds. Under 100K is ideal, and 250K is fine. Use your judgment. If you need to provide older items, consider using pagination and `next_url`. 191 | 192 | Publishers should support [Conditional GET](https://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers/), to limit impact on their system when feed readers poll for changes. 193 | 194 | Also, to further reduce bandwidth use, publishers should provide the top-level `icon` and `favicon` URLs. When not present, feed readers will often attempt to find these things by 1) downloading the home page and scraping the HTML, and 2) making one or more requests to likely locations for these images. To reduce traffic on your server, put this info in the feed. 195 | 196 | JSON Feeds should be encoded using UTF-8 — but any encoding that’s [legal JSON](https://tools.ietf.org/html/rfc7159) is legal for JSON Feeds. 197 | 198 | Any publisher already publishing RSS and/or Atom should continue to do so. In fact, if you’re trying to decide which format (of RSS, Atom, and JSON Feed) to use, and you can do only one, pick RSS — it’s time-tested, popular, and good. 199 | 200 | ## Suggestions for Feed Readers 201 | 202 | If a feed is invalid JSON, then we strongly recommend not attempting to parse it or use partial data. You can’t rely on it. 203 | 204 | There are cases, though, where a required element might not be present. In the case of an `attachment` missing a `mime_type`, you can probably deal with it fine. After all, when you download the attached file, the web browser will provide a MIME type. (And you might have been able to guess it from the file suffix.) 205 | 206 | Another case might be a malformed `date_published` that you can’t parse. You might substitute the date the reader parsed it. (Feed readers have been doing that kind of thing for many years, for bad or missing dates.) 207 | 208 | As much as we’d like to encourage good feeds, we also emphasize that this is a pragmatic format, and the final test is user experience: if an error can be recovered from without significantly harming that experience, then it’s better than just refusing to use the feed (or part of the feed) at all. 209 | 210 | That said, there is one thing we insist on: any `item` without an `id` must be discarded. We come to this from years of experience dealing with feeds in other formats where unique identifiers are optional. Without unique identifiers, it’s impossible to reliably refer to a given `item` and its changes over time, and this is terrible for user experience and becomes a source of bug reports to you. (Your users will complain of “reruns.”) In that case, you may wish to alert the user that there’s a problem with the feed, and you may also wish to contact the publisher. 211 | 212 | If an `id` is presented as a number, a JSON Feed reader should coerce it to a string. If an `id` is blank or can't be coerced to a valid string, the `item` must be discarded. 213 | 214 | For web-based feed readers, it would be helpful to publishers if you reported your subscription numbers. To do this, add a substring of the form `(n subscribers)`, where n is the actual number, to the user-agent header in your http and https requests. 215 | 216 | Feed readers are strongly advised to use [Conditional GET](https://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers/), in order to minimize bandwidth and CPU cycles on clients and servers. 217 | 218 | On the issue of which URL to use — `url` or `external_url` — when opening a web page: because an item’s `url` is always a permalink, the `url` should be the default. For linkblogs that include an `external_url`, feed readers may give users a choice which URL to open: perhaps by displaying the `external_url` prominently in the UI, perhaps by a preference to use these URLs when present, or by some other mechanism. 219 | 220 | ### Discovery 221 | 222 | A web page should include a `link` tag that specifies the location of the JSON Feed. Like this: 223 | 224 | 225 | 226 | This is the same as the feed discovery mechanism used for RSS and Atom. 227 | 228 | The `title` attribute is optional, but can be useful to differentiate multiple feeds — for instance, there might be a feed for all blog posts and a feed for comments on a specific post. These should have different titles. 229 | 230 | In an ideal world, manual discovery — by a human using a web browser — is also possible, by adding `feed.json` to the resource the feed describes. If there’s a blog at `https://example.org/`, then a human could tryhttps://example.org/feed.json
to find the feed.
231 |
232 | However, we realize that there are reasons — both technical and matters of preference — that prevent this from being universal, which is fine. But still, if you can do this, it would be nice.
233 |
234 | ### Linking to a Feed on a Web Page
235 |
236 | Publishers are encouraged to provide a link to their JSON Feed — as they do with RSS and Atom feeds — on their websites. It’s okay to make the link text “JSON Feed,” but a more specific title is also okay.
237 |
238 | You can also use the JSON Feed icon as a link on your site, like this:
239 |
240 |
241 |
242 | (The authors thank [Craig Hockenberry](http://furbo.org/) for the icon.)
243 |
244 | This spec does not address the problem of how to go from clicking a link in a browser to getting a feed added to a feed reader — which, to be fair, may not always be the user intention. And of course a feed reader may be a local app or a web app.
245 |
246 | However, the `user_comment` is your chance to tell someone eyeing a bunch of raw JSON in their web browser just what they’re looking at. Here’s an example:
247 |
248 | "user_comment": "This feed allows you to read the posts from this site in any feed reader that supports the JSON Feed format. To add this feed to your reader, copy the following URL — https://example.org/feed.json — and add it your reader."
249 |
250 | ## More Examples
251 |
252 | The below examples have just one item, for the sake of brevity in illustration. Normally a feed would have more than one item.
253 |
254 | ### Podcast
255 |
256 | {
257 | "version": "https://jsonfeed.org/version/1.1",
258 | "user_comment": "This is a podcast feed. You can add this feed to your podcast client using the following URL: http://therecord.co/feed.json",
259 | "title": "The Record",
260 | "home_page_url": "http://therecord.co/",
261 | "feed_url": "http://therecord.co/feed.json",
262 | "items": [
263 | {
264 | "id": "http://therecord.co/chris-parrish",
265 | "title": "Special #1 - Chris Parrish",
266 | "url": "http://therecord.co/chris-parrish",
267 | "content_text": "Chris has worked at Adobe and as a founder of Rogue Sheep, which won an Apple Design Award for Postage. Chris’s new company is Aged & Distilled with Guy English — which shipped Napkin, a Mac app for visual collaboration. Chris is also the co-host of The Record. He lives on Bainbridge Island, a quick ferry ride from Seattle.",
268 | "content_html": "Chris has worked at Adobe and as a founder of Rogue Sheep, which won an Apple Design Award for Postage. Chris’s new company is Aged & Distilled with Guy English — which shipped Napkin, a Mac app for visual collaboration. Chris is also the co-host of The Record. He lives on Bainbridge Island, a quick ferry ride from Seattle.",
269 | "summary": "Brent interviews Chris Parrish, co-host of The Record and one-half of Aged & Distilled.",
270 | "date_published": "2014-05-09T14:04:00-07:00",
271 | "attachments": [
272 | {
273 | "url": "http://therecord.co/downloads/The-Record-sp1e1-ChrisParrish.m4a",
274 | "mime_type": "audio/x-m4a",
275 | "size_in_bytes": 89970236,
276 | "duration_in_seconds": 6629
277 | }
278 | ]
279 | }
280 | ]
281 | }
282 |
283 | Note that it uses both `content_text` and `content_html`, which is completely valid. An app such as iTunes, for instance, might prefer to use `content_text`, while a feed reader might prefer `content_html`.
284 |
285 | Also note while there is just one attachment in this example, there could be several.
286 |
287 | ### Microblog
288 |
289 | {
290 | "version": "https://jsonfeed.org/version/1.1",
291 | "user_comment": "This is a microblog feed. You can add this to your feed reader using the following URL: https://example.org/feed.json",
292 | "title": "Brent Simmons’s Microblog",
293 | "home_page_url": "https://example.org/",
294 | "feed_url": "https://example.org/feed.json",
295 | "authors": [
296 | {
297 | "name": "Brent Simmons",
298 | "url": "http://example.org/",
299 | "avatar": "https://example.org/avatar.png"
300 | }
301 | ],
302 | "items": [
303 | {
304 | "id": "2347259",
305 | "url": "https://example.org/2347259",
306 | "content_text": "Cats are neat. \n\nhttps://example.org/cats",
307 | "date_published": "2016-02-09T14:22:00-07:00"
308 | }
309 | ]
310 | }
311 |
312 | Note that `content_text` contains a URL. It’s still plain text. A reader may choose to turn URLs in plain text into clickable links. Note also that there’s no `title`.
313 |
314 | There are some JSON Feeds on the web:
315 |
316 | * [Shape Of](http://shapeof.com/feed.json)
317 | * [Flying Meat](http://flyingmeat.com/blog/feed.json)
318 | * [Maybe Pizza?](http://maybepizza.com/feed.json)
319 | * [Daring Fireball](https://daringfireball.net/feeds/json)
320 | * [Hypercritical](http://hypercritical.co/feeds/main.json)
321 | * [inessential](http://inessential.com/feed.json)
322 | * [Manton Reece](https://manton.org/feed/json)
323 | * [Micro.blog timeline](https://micro.blog/feeds/manton.json)
324 | * [Timetable](http://timetable.manton.org/feed.json) (podcast)
325 | * [The Record](http://therecord.co/feed.json) (podcast)
326 | * [Allen Pike](http://www.allenpike.com/feed.json)
327 |
328 | In addition, this website has its own [JSON Feed](https://jsonfeed.org/feed.json).
329 |
330 | ## Reviewers
331 |
332 | The authors thank the following people for their extensive contributions and review, in alphabetical order: [Allen Pike](http://www.steamclock.com/blog/), [Craig Hockenberry](http://furbo.org/), [Daniel Jalkut](http://bitsplitting.org/), [Gus Mueller](http://shapeof.com/), [Guy English](https://twitter.com/gte), [Jim Correia](https://twitter.com/jimcorreia), [Joe Heck](https://rhonabwy.com/), [John Gruber](http://daringfireball.net/), [John Siracusa](https://twitter.com/siracusa), [Laura Savino](https://twitter.com/savinola), [Marco Arment](https://marco.org/), and [Paul Kafasis](https://onefoottsunami.com/).
333 |
334 | ## See Also
335 |
336 | [Mapping RSS and Atom to JSON Feed](https://jsonfeed.org/mappingrssandatom)
337 |
338 | ## Changes
339 |
340 | Version 1.1 — 8/7/2020:
341 |
342 | * Updated to use more specific `application/feed+json` MIME type.
343 | * Added `authors` field to allow more than 1 author per feed or item. Deprecated `author`.
344 | * Added `language` field.
345 | * Clarified that `id` should be a string.
346 | * Updated links to JSON and other specs.
347 |
348 | Version 1 — 5/17/2017:
349 |
350 | * Initial version.
351 |
--------------------------------------------------------------------------------
/pages/version/1.markdown:
--------------------------------------------------------------------------------
1 | @title Version 1
2 | # JSON Feed Version 1
3 |
4 | by Brent Simmons and Manton Reece
5 |
6 | The JSON Feed format is a pragmatic syndication format, like [RSS](http://cyber.harvard.edu/rss/rss.html) and [Atom](https://tools.ietf.org/html/rfc4287), but with one big difference: it’s JSON instead of XML.
7 |
8 | For most developers, JSON is *far* easier to read and write than XML. Developers may groan at picking up an XML parser, but decoding JSON is often just a single line of code.
9 |
10 | Our hope is that, because of the lightness of JSON and simplicity of the JSON Feed format, developers will be more attracted to developing for the open web.
11 |
12 | Here’s a simple example:
13 |
14 | {
15 | "version": "https://jsonfeed.org/version/1",
16 | "title": "My Example Feed",
17 | "home_page_url": "https://example.org/",
18 | "feed_url": "https://example.org/feed.json",
19 | "items": [
20 | {
21 | "id": "2",
22 | "content_text": "This is a second item.",
23 | "url": "https://example.org/second-item"
24 | },
25 | {
26 | "id": "1",
27 | "content_html": "Hello, world!
", 28 | "url": "https://example.org/initial-post" 29 | } 30 | ] 31 | } 32 | 33 | It supports more than just the above, of course. 34 | 35 | ## Goals 36 | 37 | After making feeds easier to read and write, our second goal is to provide a format that’s self-documenting and difficult to do wrong. 38 | 39 | We also want to support: 40 | 41 | * Microblogs, which are often plain text and without titles. So much web writing today is Twitter-like, which is actually plain text. 42 | * Multiple attachments. 43 | * Modern needs such as avatar images, feed icons and favicons, and banner and featured images. Feed readers should not have to search and scrape to guess at these things. 44 | * A simple way to add extensions. 45 | 46 | (Note about plain text: on this page it means “not HTML” — emojis, for instance, are considered plain text.) 47 | 48 | ## The Structure of a Feed 49 | 50 | A JSON Feed is a list that may change over time, and the individual items in the list may change. 51 | 52 | Think of a blog or microblog, Twitter or Facebook timeline, set of commits to a repository, or even a server log. These are all lists, and each could be described by a feed. 53 | 54 | A JSON Feed starts with some info at the top: it says where the feed comes from, and may say who created it and so on. 55 | 56 | After that there’s an array of objects — `items` — that describe each object in the list. 57 | 58 | ### Top-level 59 | 60 | * `version` (required, string) is the URL of the version of the format the feed uses. This should appear at the very top, though we recognize that not all JSON generators allow for ordering. 61 | 62 | * `title` (required, string) is the name of the feed, which will often correspond to the name of the website (blog, for instance), though not necessarily. 63 | 64 | * `home_page_url` (optional but strongly recommended, string) is the URL of the resource that the feed describes. This resource may or may not actually be a “home” page, but it should be an HTML page. If a feed is published on the public web, this should be considered as required. But it may not make sense in the case of a file created on a desktop computer, when that file is not shared or is shared only privately. 65 | 66 | * `feed_url` (optional but strongly recommended, string) is the URL of the feed, and serves as the unique identifier for the feed. As with `home_page_url`, this should be considered required for feeds on the public web. 67 | 68 | * `description` (optional, string) provides more detail, beyond the `title`, on what the feed is about. A feed reader may display this text. 69 | 70 | * `user_comment` (optional, string) is a description of the purpose of the feed. This is for the use of people looking at the raw JSON, and should be ignored by feed readers. 71 | 72 | * `next_url` (optional, string) is the URL of a feed that provides the next n items, where n is determined by the publisher. This allows for pagination, but with the expectation that reader software is not required to use it and probably won’t use it very often. `next_url` must not be the same as `feed_url`, and it must not be the same as a previous `next_url` (to avoid infinite loops). 73 | 74 | * `icon` (optional, string) is the URL of an image for the feed suitable to be used in a timeline, much the way an avatar might be used. It should be square and relatively large — such as 512 x 512 — so that it can be scaled-down and so that it can look good on retina displays. It should use transparency where appropriate, since it may be rendered on a non-white background. 75 | 76 | * `favicon` (optional, string) is the URL of an image for the feed suitable to be used in a source list. It should be square and relatively small, but not smaller than 64 x 64 (so that it can look good on retina displays). As with `icon`, this image should use transparency where appropriate, since it may be rendered on a non-white background. 77 | 78 | * `author` (optional, object) specifies the feed author. The author object has several members. These are all optional — but if you provide an author object, then at least one is required: 79 | 80 | * `name` (optional, string) is the author’s name. 81 | 82 | * `url` (optional, string) is the URL of a site owned by the author. It could be a blog, micro-blog, Twitter account, and so on. Ideally the linked-to page provides a way to contact the author, but that’s not required. The URL could be a mailto: link, though we suspect that will be rare. 83 | 84 | * `avatar` (optional, string) is the URL for an image for the author. As with `icon`, it should be square and relatively large — such as 512 x 512 — and should use transparency where appropriate, since it may be rendered on a non-white background. 85 | 86 | * `expired` (optional, boolean) says whether or not the feed is finished — that is, whether or not it will ever update again. A feed for a temporary event, such as an instance of the Olympics, could expire. If the value is `true`, then it’s expired. Any other value, or the absence of `expired`, means the feed may continue to update. 87 | 88 | * `hubs` (very optional, array of objects) describes endpoints that can be used to subscribe to real-time notifications from the publisher of this feed. Each object has a `type` and `url`, both of which are required. See the section “Subscribing to Real-time Notifications” below for details. 89 | 90 | ### Items 91 | 92 | `items` is an array, and is required. An item includes: 93 | 94 | * `id` (required, string) is unique for that item for that feed over time. If an item is ever updated, the `id` should be unchanged. New items should never use a previously-used `id`. If an `id` is presented as a number or other type, a JSON Feed reader must coerce it to a string. Ideally, the `id` is the full URL of the resource described by the item, since URLs make great unique identifiers. 95 | 96 | * `url` (optional, string) is the URL of the resource described by the item. It’s the permalink. This may be the same as the `id` — but should be present regardless. 97 | 98 | * `external_url` (very optional, string) is the URL of a page elsewhere. This is especially useful for linkblogs. If `url` links to where you’re talking about a thing, then `external_url` links to the thing you’re talking about. 99 | 100 | * `title` (optional, string) is plain text. Microblog items in particular may omit titles. 101 | 102 | * `content_html` and `content_text` are each optional strings — but one or both must be present. This is the HTML or plain text of the item. Important: the only place HTML is allowed in this format is in `content_html`. A Twitter-like service might use `content_text`, while a blog might use `content_html`. Use whichever makes sense for your resource. (It doesn’t even have to be the same for each item in a feed.) 103 | 104 | * `summary` (optional, string) is a plain text sentence or two describing the item. This might be presented in a timeline, for instance, where a detail view would display all of `content_html` or `content_text`. 105 | 106 | * `image` (optional, string) is the URL of the main image for the item. This image may also appear in the `content_html` — if so, it’s a hint to the feed reader that this is the main, featured image. Feed readers may use the image as a preview (probably resized as a thumbnail and placed in a timeline). 107 | 108 | * `banner_image` (optional, string) is the URL of an image to use as a banner. Some blogging systems (such as [Medium](https://medium.com/)) display a different banner image chosen to go with each post, but that image wouldn’t otherwise appear in the `content_html`. A feed reader with a detail view may choose to show this banner image at the top of the detail view, possibly with the title overlaid. 109 | 110 | * `date_published` (optional, string) specifies the date in [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. (Example: `2010-02-07T14:04:00-05:00`.) 111 | 112 | * `date_modified` (optional, string) specifies the modification date in RFC 3339 format. 113 | 114 | * `author` (optional, object) has the same structure as the top-level `author`. If not specified in an item, then the top-level `author`, if present, is the author of the item. 115 | 116 | * `tags` (optional, array of strings) can have any plain text values you want. Tags tend to be just one word, but they may be anything. Note: they are not the equivalent of Twitter hashtags. Some blogging systems and other feed formats call these categories. 117 | 118 | #### Attachments 119 | 120 | An individual item may have one or more attachments. 121 | 122 | * `attachments` (optional, array) lists related resources. Podcasts, for instance, would include an attachment that’s an audio or video file. Each attachment has several members: 123 | 124 | * `url` (required, string) specifies the location of the attachment. 125 | 126 | * `mime_type` (required, string) specifies the type of the attachment, such as “audio/mpeg.” 127 | 128 | * `title` (optional, string) is a name for the attachment. Important: if there are multiple attachments, and two or more have the exact same `title` (when `title` is present), then they are considered as alternate representations of the same thing. In this way a podcaster, for instance, might provide an audio recording in different formats. 129 | 130 | * `size_in_bytes` (optional, number) specifies how large the file is. 131 | 132 | * `duration_in_seconds` (optional, number) specifies how long it takes to listen to or watch, when played at normal speed. 133 | 134 | ## Extensions 135 | 136 | Publishers can use custom objects in JSON Feeds. Names must start with an `_` character followed by a letter. Custom objects can appear anywhere in a feed. 137 | 138 | For instance, imagine a podcast directory service — call it Blue Shed Podcasts — that asks a podcaster to specify some additional information about a feed or item. A publisher would do something like this: 139 | 140 | "_blue_shed": { 141 | "about": "https://blueshed-podcasts.com/json-feed-extension-docs", 142 | "explicit": false, 143 | "copyright": "1948 by George Orwell", 144 | "owner": "Big Brother and the Holding Company", 145 | "subtitle": "All shouting, all the time. Double. Plus. Good." 146 | } 147 | 148 | Feed readers that do not understand a given custom object must ignore it. 149 | 150 | The `about` string is there for a human looking at the feed, so they can understand what goes in the custom extension. It’s optional, but it should appear at least once in a feed that may contain multiple uses of `_blue_shed` (preferably in the first use, but that’s not required). 151 | 152 | Also, it’s good practice to name an extension with a company or service name, to provide a clue right away as to what it’s for and who made it. 153 | 154 | Further naming rules: the extension name and its member keys must not contain any `.` characters. The extension name, and only the extension name, must begin with an `_` character. (No standard keys will ever begin with an `_` — this is reserved for extensions.) 155 | 156 | Member keys should be alphanumeric. That said, emojis are not illegal — we’re not heartless — and somebody’s going to use them. 157 | 158 | ## Subscribing to Real-time Notifications 159 | 160 | Traditional feed readers usually poll a web site for changes at a regular interval. This is fine for many applications, but there’s a more efficient approach for applications that need to know the moment a feed changes. The top-level `hubs` array points to one or more services that can be used by feed aggregators to subscribe to changes to this feed. Those hubs can then send a notification to the application as soon as the feed is updated. 161 | 162 | The `type` field describes the protocol used to talk with the hub, such as “rssCloud” or “WebSub.” When using WebSub, the value for the JSON Feed’s `feed_url` is passed for the `hub.topic` parameter. For more information about WebSub, see [the specification at the W3C](https://www.w3.org/TR/websub/). 163 | 164 | ## Future Compatibility 165 | 166 | A version 1 feed will be a valid version 2 feed, and so on. Future versions may add things, but won’t make older feeds invalid. 167 | 168 | ### Key Naming Rules 169 | 170 | In future versions, defined keys will always adhere to these rules: 171 | 172 | * Leading `_` characters are reserved for extensions. 173 | * Keys will be made of alphanumeric characters from the ASCII character set. 174 | * Keys will never contain a `.` character. 175 | 176 | ## Suggestions for Publishers 177 | 178 | JSON Feed files must be served using the same MIME type — `application/json` — that’s used whenever JSON is served. 179 | 180 | The number of items in a feed is unlimited, but practical limits should be observed. A 1MB feed places a burden on feed readers, especially if there are many such feeds. Under 100K is ideal, and 250K is fine. Use your judgment. If you need to provide older items, consider using pagination and `next_url`. 181 | 182 | Publishers should support [Conditional GET](https://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers/), to limit impact on their system when feed readers poll for changes. 183 | 184 | Also, to further reduce bandwidth use, publishers should provide the top-level `icon` and `favicon` URLs. When not present, feed readers will often attempt to find these things by 1) downloading the home page and scraping the HTML, and 2) making one or more requests to likely locations for these images. To reduce traffic on your server, put this info in the feed. 185 | 186 | JSON Feeds should be encoded using UTF-8 — but any encoding that’s [legal JSON](https://www.ietf.org/rfc/rfc4627.txt) is legal for JSON Feeds. 187 | 188 | Any publisher already publishing RSS and/or Atom should continue to do so. In fact, if you’re trying to decide which format (of RSS, Atom, and JSON Feed) to use, and you can do only one, pick RSS — it’s time-tested, popular, and good. 189 | 190 | ## Suggestions for Feed Readers 191 | 192 | If a feed is invalid JSON, then we strongly recommend not attempting to parse it or use partial data. You can’t rely on it. 193 | 194 | There are cases, though, where a required element might not be present. In the case of an `attachment` missing a `mime_type`, you can probably deal with it fine. After all, when you download the attached file, the web browser will provide a MIME type. (And you might have been able to guess it from the file suffix.) 195 | 196 | Another case might be a malformed `date_published` that you can’t parse. You might substitute the date the reader parsed it. (Feed readers have been doing that kind of thing for many years, for bad or missing dates.) 197 | 198 | As much as we’d like to encourage good feeds, we also emphasize that this is a pragmatic format, and the final test is user experience: if an error can be recovered from without significantly harming that experience, then it’s better than just refusing to use the feed (or part of the feed) at all. 199 | 200 | That said, there is one thing we insist on: any `item` without an `id` must be discarded. We come to this from years of experience dealing with feeds in other formats where unique identifiers are optional. Without unique identifiers, it’s impossible to reliably refer to a given `item` and its changes over time, and this is terrible for user experience and becomes a source of bug reports to you. (Your users will complain of “reruns.”) In that case, you may wish to alert the user that there’s a problem with the feed, and you may also wish to contact the publisher. 201 | 202 | For web-based feed readers, it would be helpful to publishers if you reported your subscription numbers. To do this, add a substring of the form `(n subscribers)`, where n is the actual number, to the user-agent header in your http and https requests. 203 | 204 | Feed readers are strongly advised to use [Conditional GET](https://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers/), in order to minimize bandwidth and CPU cycles on clients and servers. 205 | 206 | On the issue of which URL to use — `url` or `external_url` — when opening a web page: because an item’s `url` is always a permalink, the `url` should be the default. For linkblogs that include an `external_url`, feed readers may give users a choice which URL to open: perhaps by displaying the `external_url` prominently in the UI, perhaps by a preference to use these URLs when present, or by some other mechanism. 207 | 208 | ### Discovery 209 | 210 | A web page should include a `link` tag that specifies the location of the JSON Feed. Like this: 211 | 212 | 213 | 214 | This is the same as the feed discovery mechanism used for RSS and Atom. 215 | 216 | The `title` attribute is optional, but can be useful to differentiate multiple feeds — for instance, there might be a feed for all blog posts and a feed for comments on a specific post. These should have different titles. 217 | 218 | In an ideal world, manual discovery — by a human using a web browser — is also possible, by adding `feed.json` to the resource the feed describes. If there’s a blog at `https://example.org/`, then a human could tryhttps://example.org/feed.json
to find the feed.
219 |
220 | However, we realize that there are reasons — both technical and matters of preference — that prevent this from being universal, which is fine. But still, if you can do this, it would be nice.
221 |
222 | ### Linking to a Feed on a Web Page
223 |
224 | Publishers are encouraged to provide a link to their JSON Feed — as they do with RSS and Atom feeds — on their websites. It’s okay to make the link text “JSON Feed,” but a more specific title is also okay.
225 |
226 | You can also use the JSON Feed icon as a link on your site, like this:
227 |
228 |
229 |
230 | (The authors thank [Craig Hockenberry](http://furbo.org/) for the icon.)
231 |
232 | This spec does not address the problem of how to go from clicking a link in a browser to getting a feed added to a feed reader — which, to be fair, may not always be the user intention. And of course a feed reader may be a local app or a web app.
233 |
234 | However, the `user_comment` is your chance to tell someone eyeing a bunch of raw JSON in their web browser just what they’re looking at. Here’s an example:
235 |
236 | "user_comment": "This feed allows you to read the posts from this site in any feed reader that supports the JSON Feed format. To add this feed to your reader, copy the following URL — https://example.org/feed.json — and add it your reader."
237 |
238 | ## More Examples
239 |
240 | The below examples have just one item, for the sake of brevity in illustration. Normally a feed would have more than one item.
241 |
242 | ### Podcast
243 |
244 | {
245 | "version": "https://jsonfeed.org/version/1",
246 | "user_comment": "This is a podcast feed. You can add this feed to your podcast client using the following URL: http://therecord.co/feed.json",
247 | "title": "The Record",
248 | "home_page_url": "http://therecord.co/",
249 | "feed_url": "http://therecord.co/feed.json",
250 | "items": [
251 | {
252 | "id": "http://therecord.co/chris-parrish",
253 | "title": "Special #1 - Chris Parrish",
254 | "url": "http://therecord.co/chris-parrish",
255 | "content_text": "Chris has worked at Adobe and as a founder of Rogue Sheep, which won an Apple Design Award for Postage. Chris’s new company is Aged & Distilled with Guy English — which shipped Napkin, a Mac app for visual collaboration. Chris is also the co-host of The Record. He lives on Bainbridge Island, a quick ferry ride from Seattle.",
256 | "content_html": "Chris has worked at Adobe and as a founder of Rogue Sheep, which won an Apple Design Award for Postage. Chris’s new company is Aged & Distilled with Guy English — which shipped Napkin, a Mac app for visual collaboration. Chris is also the co-host of The Record. He lives on Bainbridge Island, a quick ferry ride from Seattle.",
257 | "summary": "Brent interviews Chris Parrish, co-host of The Record and one-half of Aged & Distilled.",
258 | "date_published": "2014-05-09T14:04:00-07:00",
259 | "attachments": [
260 | {
261 | "url": "http://therecord.co/downloads/The-Record-sp1e1-ChrisParrish.m4a",
262 | "mime_type": "audio/x-m4a",
263 | "size_in_bytes": 89970236,
264 | "duration_in_seconds": 6629
265 | }
266 | ]
267 | }
268 | ]
269 | }
270 |
271 | Note that it uses both `content_text` and `content_html`, which is completely valid. An app such as iTunes, for instance, might prefer to use `content_text`, while a feed reader might prefer `content_html`.
272 |
273 | Also note while there is just one attachment in this example, there could be several.
274 |
275 | ### Microblog
276 |
277 | {
278 | "version": "https://jsonfeed.org/version/1",
279 | "user_comment": "This is a microblog feed. You can add this to your feed reader using the following URL: https://example.org/feed.json",
280 | "title": "Brent Simmons’s Microblog",
281 | "home_page_url": "https://example.org/",
282 | "feed_url": "https://example.org/feed.json",
283 | "author": {
284 | "name": "Brent Simmons",
285 | "url": "http://example.org/",
286 | "avatar": "https://example.org/avatar.png"
287 | },
288 | "items": [
289 | {
290 | "id": "2347259",
291 | "url": "https://example.org/2347259",
292 | "content_text": "Cats are neat. \n\nhttps://example.org/cats",
293 | "date_published": "2016-02-09T14:22:00-07:00"
294 | }
295 | ]
296 | }
297 |
298 | Note that `content_text` contains a URL. It’s still plain text. A reader may choose to turn URLs in plain text into clickable links. Note also that there’s no `title`.
299 |
300 | There are some JSON Feeds on the web:
301 |
302 | * [Shape Of](http://shapeof.com/feed.json)
303 | * [Flying Meat](http://flyingmeat.com/blog/feed.json)
304 | * [Maybe Pizza?](http://maybepizza.com/feed.json)
305 | * [Daring Fireball](https://daringfireball.net/feeds/json)
306 | * [Hypercritical](http://hypercritical.co/feeds/main.json)
307 | * [inessential](http://inessential.com/feed.json)
308 | * [Manton Reece](https://manton.org/feed/json)
309 | * [Micro.blog timeline](https://micro.blog/feeds/manton.json)
310 | * [Timetable](http://timetable.manton.org/feed.json) (podcast)
311 | * [The Record](http://therecord.co/feed.json) (podcast)
312 | * [Allen Pike](http://www.allenpike.com/feed.json)
313 |
314 | In addition, this website has its own [JSON Feed](https://jsonfeed.org/feed.json).
315 |
316 | ## Reviewers
317 |
318 | The authors thank the following people for their extensive contributions and review, in alphabetical order: [Allen Pike](http://www.steamclock.com/blog/), [Craig Hockenberry](http://furbo.org/), [Daniel Jalkut](http://bitsplitting.org/), [Gus Mueller](http://shapeof.com/), [Guy English](https://twitter.com/gte), [Jim Correia](https://twitter.com/jimcorreia), [Joe Heck](https://rhonabwy.com/), [John Gruber](http://daringfireball.net/), [John Siracusa](https://twitter.com/siracusa), [Laura Savino](https://twitter.com/savinola), [Marco Arment](https://marco.org/), and [Paul Kafasis](https://onefoottsunami.com/).
319 |
320 | ## See Also
321 |
322 | [Mapping RSS and Atom to JSON Feed](https://jsonfeed.org/mappingrssandatom)
323 |
--------------------------------------------------------------------------------
/posts/2017/05/17/announcing_json_feed.markdown:
--------------------------------------------------------------------------------
1 | @title Announcing JSON Feed
2 | @pubDate 2017-05-17 08:02:12 -0700
3 | @modDate 2017-05-17 08:02:12 -0700
4 | We — Manton Reece and Brent Simmons — have noticed that JSON has become the developers’ choice for APIs, and that developers will often go out of their way to avoid XML. JSON is simpler to read and write, and it’s less prone to bugs.
5 |
6 | So we developed JSON Feed, a format similar to [RSS](http://cyber.harvard.edu/rss/rss.html) and [Atom](https://tools.ietf.org/html/rfc4287) but in JSON. It reflects the lessons learned from our years of work reading and publishing feeds.
7 |
8 | [See the spec](https://jsonfeed.org/version/1). It’s at version 1, which may be the only version ever needed. If future versions are needed, version 1 feeds will still be valid feeds.
9 |
10 | #### Notes
11 |
12 | We have a [WordPress plugin](https://github.com/manton/jsonfeed-wp) and, coming soon, a JSON Feed Parser for Swift. As more code is written, by us and others, we’ll update the [code](https://jsonfeed.org/code) page.
13 |
14 | See [Mapping RSS and Atom to JSON Feed](https://jsonfeed.org/mappingrssandatom) for more on the similarities between the formats.
15 |
16 | This website — the Markdown files and supporting resources — [is up on GitHub](https://github.com/brentsimmons/JSONFeed), and you’re welcome to comment there.
17 |
18 | This website is also a blog, and you can subscribe to the [RSS feed](https://jsonfeed.org/xml/rss.xml) or the [JSON feed](https://jsonfeed.org/feed.json) (if your reader supports it).
19 |
20 | We worked with a number of people on this over the course of several months. We list them, and thank them, at the bottom of the [spec](https://jsonfeed.org/version/1). But — most importantly — [Craig Hockenberry](http://furbo.org/) spent a little time making it look pretty. :)
21 |
--------------------------------------------------------------------------------
/snippets/footer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
24 |
25 |