A FreshRSS / Google Reader API Plugin for Tiny-Tiny RSS
Tiny-Tiny RSS is one of the best and most customizable self-hostable RSS readers available, but historically has had only limited compatibility with third party RSS readers through two APIs:
Many mobile applications support one of these protocols, many do not. FreshAPI implements the FreshRSS / Google Reader API to allow Tiny-Tiny RSS to be used with more third party apps, and with more features.
| Feature | Fever API | Official API | FreshAPI |
|---|---|---|---|
| Mark Article as Read/Unread | ✅ | ✅ | ✅ |
| Add/Remove Star from Article | ✅ | ✅ | ✅ |
| Mark Entire Feed/Category as Read | ✅ | ✅ | ✅ |
| Secure Implementation | ❌ | ✅ | ✅ |
| Subscribe to a Feed | ❌ | ✅ | ✅ |
| Unsubscribe from a Feed | ❌ | ✅ | ✅ |
| Rename a Feed | ❌ | ❌ | ✅ |
| Add a Category to a Feed | ❌ | ❌ | ✅ |
| Remove a Category from a Feed | ❌ | ❌ | ✅ |
| Create a new Category | ❌ | ❌ | ✅ |
| Rename a Label | ❌ | ❌ | ✅ |
| Delete a Label | ❌ | ❌ | ✅ |
| Add a Custom Label / Tag | ❌ | ❌ | ✅ |
| Delete a Custom Label / Tag | ❌ | ❌ | ✅ |
| OPML Export | ❌ | ❌ | ✅ |
| OPML Import | ❌ | ❌ | ✅ |
FreshAPI assumes that you're using the official docker based integration and running the latest version of TT-RSS with PostgreSQL as the backend database. A change required for the API to work (enabling PATH_INFO for the plugins.local directory) was pushed on 9/11/2024, so any docker images from before that change will need to be updated.
If you are using another installation method you may need to make this PATH_INFO update yourself, more details here.
This plugin also uses backend components of the official auth_internal plugin, which is enabled by default with TT-RSS installs. If you've disabled this plugin you'll need to re-enable it to use freshapi.
-
Clone this repository into your Tiny Tiny RSS
plugins.localdirectory.Official docker images: the TT-RSS code lives on the
appvolume, which theapp,updaterandweb-nginxcontainers share. From the directory with yourdocker-compose.yml, clone into it:docker compose exec -u app app git clone https://github.com/eric-pierce/freshapi.git /var/www/html/tt-rss/plugins.local/freshapiIf you'd rather bind-mount the plugin from the host, mount it into the
web-nginxcontainer as well asappandupdater. nginx runs in its own container and servesgreader.phpfrom its own copy of the files: with the plugin mounted intoapponly, freshapi still appears in Preferences but the API returns 404 (#14). Keep theappmount writable, since the container's startup script changes ownership of the files and stops if it can't:services: app: volumes: - app:/var/www/html - ./freshapi:/var/www/html/tt-rss/plugins.local/freshapi updater: volumes: - app:/var/www/html - ./freshapi:/var/www/html/tt-rss/plugins.local/freshapi web-nginx: volumes: - app:/var/www/html:ro - ./freshapi:/var/www/html/tt-rss/plugins.local/freshapi:ro
Other installs:
cd tt-rss/plugins.local git clone https://github.com/eric-pierce/freshapi.git -
Navigate to the Preferences menu in Tiny Tiny RSS, and check the box under "General" titled "Enable API"

-
To confirm that everything is configured correctly, visit
https://yourdomain.com/tt-rss/plugins.local/freshapi/api/greader.phpin a browser, and you should see the text "OK" displayed. Then check that API requests reach the plugin, using deliberately wrong credentials:curl -i -X POST --data 'Email=test&Passwd=test' https://yourdomain.com/tt-rss/plugins.local/freshapi/api/greader.php/accounts/ClientLoginA
401 Unauthorizedresponse means everything is wired up correctly. If not:- 404 in the browser: the web server can't see the plugin files. With the official docker images, make sure nginx can see them too (see step 1).
- "OK" in the browser, but 404 from the curl command: the web server isn't passing
PATH_INFOto PHP. See Non-Official Docker based Installs.
-
When configuring your mobile app, select either "FreshRSS" or "Google Reader API". You'll need to point your client to your TT-RSS installation, depending on your setup. If you're using a subdomain to host TT-RSS then use
https://yoursubdomain.yourdomain.cominstead ofhttps://yourdomain.comin the requests below.If you're using the standard docker installation use
https://yourdomain.com/tt-rss/plugins.local/freshapi/api/greader.phpas the server URL.If you're running the TT-RSS app at the website root (not including /tt-rss/ in the URL) by using the APP_WEB_ROOT and APP_BASE environment variables as described here you'll also need to remove tt-rss from the domain you use with clients:
https://yourdomain.com/plugins.local/freshapi/api/greader.phpUse your standard TT-RSS username and password. If you've enabled 2 Factor Authentication (2FA) generate and use an App Password.
If you're using an install method other than the official docker images or Awesome-TTRSS then you may need to modify your nginx.conf files to support PATH_INFO, which is how the FreshRSS and Google Reader APIs pass requests to the backend server. This is as simple as adding a new "location" ruleset in the .conf file to enable PATH_INFO for the freshapi URL. You can use the nginx.conf files from the official and Awesome-TTRSS installs as a guide, and there's a discussion about enabling this here.
If you're using NixOS with Postgres, use the following as a template:
configuration.nix
services.tt-rss = {
enable = true;
database = {
type = "pgsql";
};
selfUrlPath = "http://<Host>";
virtualHost = "<Host>";
pluginPackages = [ (pkgs.callPackage ./freshapi.nix {}) ];
};
PATH_INFO nginx config in configuration.nix
virtualHosts."<HOST from above>" = {
locations."~ /plugins\\.local/.*/api/.*\\.php(/|$)" = {
extraConfig = ''
fastcgi_split_path_info ^(.+\.php)(/.+)$;
try_files $fastcgi_script_name =404;
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/phpfpm/tt-rss.sock;
include ${config.services.nginx.package}/conf/fastcgi_params;
fastcgi_index index.php;
'';
};
freshapi.nix should contain:
{ lib, stdenv, fetchFromGitHub, tt-rss }:
stdenv.mkDerivation {
pname = "tt-rss-plugin-freshapi";
version = "0.01";
src = fetchFromGitHub {
owner = "eric-pierce";
repo = "freshapi";
rev = "942b1c37ef2035444c3a22a21e225f3ece73c705"; # this and the line below needs to be updated based on the git sha of freshapi you want to install
sha256 = "sha256-XWzEya+1A/UtwTL+HseoX8trEypNjHurK/VF3k2seMQ";
};
installPhase = ''
mkdir -p $out/freshapi
cp -r api init.php $out/freshapi
'';
meta = with lib; {
description = "Tiny Tiny RSS FreshAPI Plugin";
longDescription = ''
A FreshRSS / Google Reader API Plugin for Tiny-Tiny RSS
'';
license = with licenses; [ agpl3Only ];
homepage = "https://github.com/eric-pierce/freshapi";
maintainers = with maintainers; [ bigloser ];
inherit (tt-rss.meta) platforms;
};
}
While OIDC based logins aren't supported by Clients as they would need to redirect to a browser page to complete the OIDC login flow, it is possible to use both OIDC and freshapi. OIDC plugins such as auth_oidc only handle browser logins, so to use FreshAPI with an OIDC account:
- Keep auth_internal enabled alongside the OIDC plugin. With the official docker images that means adding auth_oidc to the default list:
TTRSS_PLUGINS=auth_internal, auth_oidc, note, nginx_xaccel. With auth_internal disabled, App Passwords aren't offered and every client login fails. - Sign in to the web UI with OIDC. In Preferences, check "Enable API" and enable the freshapi plugin.
- Under Preferences → Personal data / Authentication → App passwords, generate a password for your client.
- In your client, use your TT-RSS username and the App Password. For auth_oidc users the username is the lowercased
preferred_usernameclaim by default (set byTTRSS_AUTH_OIDC_CLIENT_USERNAME_CLAIM), not your email address. Your OIDC provider's password won't work here.
Client sessions are checked on every request. Changing your password, disabling your account, unchecking "Enable API", or disabling the freshapi plugin signs clients out, and they'll need to log in again.
Please provide details about your setup in any issues you open.
The following clients have been tested, but FreshAPI should be compatible with any FreshRSS or Google Reader API compatible client. If you run into any issues or would like to report a client as working, please open up an issue.
| App | Platform | Status | Notes |
|---|---|---|---|
| Reeder Classic | iOS, macOS | Fully Functional | None |
| NetNewsWire | iOS, macOS | Fully Functional | None |
| lire | iOS, macOS | Fully Functional | None |
| Fiery Feeds | iOS, macOS | Fully Functional | None |
| ReadKit | iOS, macOS | Fully Functional | None |
| Fluent Reader Lite | iOS | Fully Functional | 1. Fluent Reader Lite supports Max 1500 unread articles across all types (unread, starred, etc). 2. The article count for Fluent Reader is oftentimes inaccurate. This is a Fluent Reader issue (tracked here yang991178/fluent-reader#537), not a FreshAPI issue. |
| Fluent Reader | macOS, Windows | Fully Functional | The article count for Fluent Reader is oftentimes inaccurate. This is a Fluent Reader issue (tracked here yang991178/fluent-reader#537), not a FreshAPI issue. |
| FeedMe | Android | Fully Functional | None |
| Read You | Android | Fully Functional | None |
| News Flash | Linux | Fully Functional | None |
FreshRSS and Google Reader compatible clients can natively use this API, but if you'd like to access it directly you can do so by making cURL calls. The Google Reader API spec is well documented, but here is an example of API usage:
- Authorization
Make a POST cURL call to your server's ClientLogin Endpoint using your TT-RSS username and password. If you have enabled 2FA you can use an App password generated in the TT-RSS preferences pane
foo@bar:~$ curl -X POST --data 'Email=yourusername&Passwd=yourpassword' https://example.com/tt-rss/plugins.local/freshapi/api/greader.php/accounts/ClientLogin/This will return your authorization credentials in the format 'username/session_id"
SID=yourusername/r4ih6gt412opqh11gptp3hodd6
LSID=
Auth=yourusername/r4ih6gt412opqh11gptp3hodd6
- Calling the API Directly
Take the username/session_id combination from step 1 and make a new cURL call to the endpoint you'd like to use. In this case we'll ask to export the subscription, folder, and tag OPML through the subscription export feature:
foo@bar:~$ curl -X POST --header 'Authorization: GoogleLogin auth=yourusername/r4ih6gt412opqh11gptp3hodd6' https://example.com/tt-rss/plugins.local/freshapi/api/greader.php/reader/api/0/subscription/exportIn the example above the cURL call will return your subscription OPML in XML form.
FreshAPI uses a rolling release approach, though I'll increment the version number for significant changes. If cloned into the plugins.local folder TT-RSS should keep the plugin up to date.
Issues, Contributions, and Pull Requests are welcome and encouraged - please feel free to open any of them.
This project is licensed under the GNU AGPL 3 License
- Major thanks to Tiny Tiny RSS, its original developer Andrew, and the current developer supahgreg for making the best self-hosted RSS reader available
- Thanks to the FreshRSS team for both expanding on the Google Reader API and for providing an excellent example of implementation using PHP found here
The Google Reader API is well documentated, below are some examples outlining its functionality:
- https://freshrss.github.io/FreshRSS/en/developers/06_GoogleReader_API.html
- https://code.google.com/archive/p/pyrfeed/wikis/GoogleReaderAPI.wiki
- https://web.archive.org/web/20130718025427/http://undoc.in/
- http://ranchero.com/downloads/GoogleReaderAPI-2009.pdf
- https://github.com/mihaip/google-reader-api
- https://web.archive.org/web/20210126113527/https://blog.martindoms.com/2009/08/15/using-the-google-reader-api-part-1
- https://github.com/noinnion/newsplus/blob/master/extensions/GoogleReaderCloneExtension/src/com/noinnion/android/newsplus/extension/google_reader/GoogleReaderClient.java
- https://github.com/ericmann/gReader-Library/blob/master/greader.class.php
- https://github.com/devongovett/reader
- https://github.com/theoldreader/api
- https://www.inoreader.com/developers/
- https://feedhq.readthedocs.io/en/latest/api/index.html
- https://github.com/bazqux/bazqux-api
- https://xueli-sherryli.github.io/friendlier-fresh-rss-api-doc/en/
- https://web.archive.org/web/20170426184845/http://www.niallkennedy.com/blog/2005/12/google-reader-api.html
- https://web.archive.org/web/20140919042419/http://code.google.com/p/google-reader-api/w/list
This project is not affiliated with or endorsed by FreshRSS, Google, or Tiny Tiny RSS. Use at your own risk.
Starting in September 2026 I used Claude Code to identify and fix security issues and potential bugs.
