Signal RSS

approved

by hellokunzai

Subscribe to RSS and Atom feeds, read articles in a dedicated reader tab, and save any article to your vault as a Markdown note. - This plugin has not been manually reviewed by Obsidian staff.

33 downloadsUpdated 4d agoMIT

Signal RSS

English · 简体中文

Subscribe to RSS, Atom and RSS 1.0 (RDF) feeds, read them in a dedicated reader tab inside Obsidian, and turn any article into a Markdown note in your vault.

Features

  • Subscriptions — add a feed by pasting either its feed URL or the site's home page; RSS 2.0, Atom and RSS 1.0 (RDF) are supported. Feeds can be sorted into groups, and groups themselves can be created, renamed and deleted from the subscription tree.
  • Subscription list in the right sidebar — the search box, the filters, the feed tree, the article list and the drag handle between them all live in the right sidebar. The list is the only place you pick from, and what it picks is what the reader shows.
  • Reader tab — the selected article opens in its own tab in the main area. Its title becomes the tab label and the view header; a one-row toolbar above the body carries star, read/unread, fetch full text, open in the browser and save as note.
  • Full text extraction — when a feed only ships a summary, the article page is fetched and its main content extracted, so you read (and keep) the whole thing.
  • Markdown export — save any article as a note. The destination folder, the file name and both the front matter and the body templates are configurable.
  • Automatic refresh — feeds are polled in the background at an interval you choose. Set it to 0 to switch automatic refresh off. The ribbon icon's tooltip carries the current unread count.
  • Read state — unread counts per feed and per group, a global unread count, read/unread toggling and a star list.
  • Search — filters the article list as you type, matching against titles, authors and summaries.
  • OPML — import an OPML file exported by another reader, and export your subscriptions back out.
  • Interface language — English and Simplified Chinese, following the Obsidian language setting.

Installation

From the community plugin directory

Search for "Signal RSS" under Settings → Community plugins → Browse.

Manually

  1. Download main.js, manifest.json and styles.css from the latest release.
  2. Copy them into <your vault>/.obsidian/plugins/signal-rss/.
  3. Reload Obsidian and enable the plugin under Settings → Community plugins.

Usage

  1. Click the RSS icon in the ribbon. The subscription list opens in the right sidebar.
  2. Add a feed. The empty list offers an Add feed button, and Signal RSS: Add feed in the command palette works from anywhere; with feeds already sorted into groups, right-clicking a group header gives you an Add feed… that pre-fills that group. Pasting a site home page works too — Signal RSS looks for the feed link on the page.
  3. Articles show up under the three filters at the top of the list. Clicking one opens it in a reader tab in the main area.
  4. Use Save as note in the reader to write the article into your vault.

Right-click a feed in the sidebar for refresh, mark-as-read, edit and delete. The menu behind a group header also carries OPML import and export, mark-all-read/unread for that group, and rename/delete for the group itself — deleting a group moves its feeds back to Ungrouped instead of deleting them, and renaming it takes them along.

Right-click the empty space under the subscription tree to create a group, or to add a feed without filing it into one. A group you create stays in the tree even while it holds no feeds — instead of an empty space it shows an Add feed… row, which pre-fills the group — until you delete it again.

The list only ever lives in the sidebar, so there is no position to choose: Signal RSS: Toggle the subscription list sidebar shows and hides it, and while it is hidden the reader's empty state offers a button that brings it back.

The list pane

  • Search box — filters the article list as you type, paused briefly so typing does not fight the caret.
  • Three filtersAll articles, Unread and Starred, each carrying its own count. Picking a feed in the tree narrows the list to that feed instead.
  • Feed tree — a group header folds and unfolds on click, and shows its own unread total while folded.
  • Drag handle — the divider between the tree and the article list resizes the two. Drag it, double-click it to go back to the default, or focus it and use the arrow keys (hold Shift for bigger steps).

Commands

CommandDescription
Open RSS readerShow the reader tab — empty until an article is picked
Refresh all feedsFetch every subscription
Add feedOpen the add-feed dialog
Import OPML fileImport subscriptions from an OPML file
Export OPML fileWrite an OPML file to the vault root
Save current article as noteSave the article open in the reader
Mark all articles as readClear the unread state everywhere
Collapse all groupsFold every group in the feed tree shut
Expand all groupsUnfold every group in the feed tree
Toggle the subscription list sidebarShow or hide the list in the right sidebar

The three commands that need something to act on — save the current article, collapse all groups, expand all groups — are hidden from the command palette while they would do nothing.

Settings

The settings page is split into four tabs.

Basic settings

SettingDescription
Automatic refresh intervalBackground polling interval in minutes; 0 turns it off
Request timeoutHow long to wait for a feed before giving up (5–120 s)
Articles kept per feedUpper bound on stored articles per feed; the oldest are dropped past it
Mark as read when openedClear the unread flag as soon as an article is opened
Fetch full text when openedFetch the article page when a feed only ships a summary
Fetch full text while refreshingDo that during refresh instead, so articles are readable offline
Custom cache folderVault-relative folder holding the caches, with a Migrate cache button beside it

Subscriptions

The list of everything you subscribe to, with Import OPML, Export OPML and Add feed on the toolbar, a search box that filters by title, group or address, and one row per feed showing its title, its group and three actions: refresh, edit and delete.

Note export

SettingDescription
Open the note after savingOpen the created note in a new tab
Note folderDestination folder for saved articles; created when missing
File name templateTemplate for the note file name
Front matter templateYAML written between the --- markers at the top of every saved note
Note body templateWrapper around the article body

About

Shows the version, a Check for updates button that opens the plugin's page in Obsidian, and Reset settings, which restores every option on the page to its default while keeping your subscriptions.

Template variables

Both the file name and the two templates accept these variables:

VariableValue
{{title}}Article title
{{feed}}Feed title, falling back to its address
{{group}}Group the feed is filed under
{{author}}Article author
{{link}}Article address
{{published}}Publication date, YYYY-MM-DD by default
{{created}}Date the note is written, YYYY-MM-DD by default
{{summary}}Summary as shipped by the feed
{{content}}The article body, converted to Markdown — body template only

A date variable takes a Moment.js format after a colon, for example {{published:YYYY-MM-DD HH:mm}}. Appending :yaml escapes a value for the front matter, which is how the default front matter template writes {{title:yaml}} and {{author:yaml}}. The default file name template is {{published:YYYY-MM-DD}} {{title}}, and the default note folder is RSS Inbox.

Where data lives

  • Subscriptions, read/starred state and settings are stored in the plugin's data.json.
  • Article content is cached under .signal-rss/ at the root of your vault, one JSON file per feed — a dot folder, so it stays out of the file explorer and out of Obsidian's index. The folder is configurable; changing it does not move anything by itself, and Settings → Basic settings → Custom cache folder → Migrate cache is the deliberate second step that pulls the caches across from the folder previously in use, merging rather than overwriting so no read flag or extracted body is lost.
  • Versions up to 0.7.0 kept the caches inside the plugin folder instead (<config folder>/plugins/<plugin id>/cache/, with .obsidian as the usual config folder). If you have been using the plugin since before it was renamed from rss-subscribe to signal-rss, a cache left behind under the old plugin id needs to be moved into the current folder by hand.
  • Nothing is written into your notes folder unless you explicitly save an article.

Privacy and network access

This plugin makes network requests, but only to the addresses you subscribe to:

  • Feed URLs are requested to fetch articles.
  • An article's own URL is requested when full text extraction runs.

There is no account, no telemetry, no analytics and no third-party service. Requests go through Obsidian's requestUrl API, so they are not sent to any proxy of ours.

Troubleshooting a feed that will not load

Some addresses are unreachable, rate-limited, or hang on the server side. Signal RSS gives up after the configured request timeout and reports the reason rather than waiting indefinitely, and it stops early when the host itself is unreachable instead of retrying every guessed path.

A public RSS bridge (such as rsshub.app or one of the community instances) is often the culprit rather than the site you actually want:

  • Most public instances are heavily rate-limited and drop requests under load.
  • They may be unreachable from some networks and regions.
  • A single route can be broken on an otherwise healthy instance — the instance root answers instantly while one specific route never returns, because the instance's own upstream fetch is hanging. Try the same route on a different instance, or self-host an instance, which is by far the most reliable option.

To confirm a feed works before subscribing, open its URL in a browser. A working feed shows raw XML; a broken one shows an error, a blank page, or spins forever.

Security notes

Feed content is third-party markup and is treated as untrusted:

  • Before anything is displayed or saved, it is reduced to a small allowlist of tags and attributes. Attributes such as on* handlers, style, and any javascript: URL are dropped by construction.
  • Article bodies are inserted with Obsidian's sanitizeHTMLToDom; innerHTML is not used anywhere in this plugin.
  • Code blocks coming from a feed are re-fenced with a delimiter longer than any backtick run inside them, so a feed cannot smuggle a dataviewjs or templater fence into a saved note and get it executed later.
  • Files are only ever created inside your vault, and only when you ask for a note to be saved.

Mobile

The plugin works on mobile (isDesktopOnly: false). It uses only cross-platform Obsidian APIs — no Node.js file system access.

The layout adapts to a phone rather than merely fitting on it:

  • The subscription list lives in the right sidebar, which on a phone is a drawer. Tapping the RSS icon in the ribbon opens it; picking an article folds it away so the article is visible right away.
  • Long-pressing a subscription, a group header, or the empty space under the tree opens its menu (refresh, mark as read, edit, delete, OPML, mark all, new group, rename, delete group), since there is no right-click.
  • Touch targets, the search box, and the reader's margins are sized for a thumb and for iOS' minimum input font size.

Development

Requires Node.js 18 or newer (CI uses 22) and Obsidian 1.7.2 or newer.

npm install
npm run dev     # watch build
npm run build   # type check + production bundle

Copy main.js, manifest.json and styles.css into a test vault's .obsidian/plugins/signal-rss/ to try a build.

Layout

PathContents
src/main.tsPlugin entry: commands, view registration, shared list state, refresh and feed handling
src/settings.tsThe tabbed settings page
src/i18n/index.tsEvery user-visible string, in en and zh-cn
src/core/Feed parsing, fetching, error normalisation, full text extraction, OPML, HTML sanitising, the cache store
src/view/The sidebar list pane and the reader tab
src/note/Template rendering and note writing
src/ui/The add-feed and group-name dialogs
styles.cssPlugin styles, using Obsidian's CSS variables

Every user-visible string goes through t(); a literal is not allowed to reach the UI directly.

Checks

manifest.json, package.json and versions.json must carry the same version before anything ships:

node .github/scripts/check-version.mjs          # version consistency + manifest rules
node .github/scripts/check-version.mjs --tag X  # also assert a tag matches the manifest

CI runs this plus a type check, a production build and a scan of main.js for the dynamic-execution APIs Obsidian's review rejects.

Releases

Releases are driven by GitHub Actions and the built assets are attached by CI, since main.js is not tracked:

WorkflowTriggerResult
ci.ymlpush to main, any pull requesttype check, build, security scan, asset check
version-check.ymlpush, tags, pull requestsversion and manifest consistency
release.ymlpushing a tag, or a manual runGitHub release with main.js, manifest.json, styles.css
beta.ymlcommit on main whose subject starts with [beta] or [rc]pre-release tagged <version>-beta.N for BRAT

Bump the version in all three files, commit, then push a tag without a v prefix:

git tag 0.9.0 && git push origin 0.9.0

The same release can be cut from the Actions tab instead, by running Release and passing the version — the workflow creates the tag itself. For testing before a release, start the commit subject on main with [beta], or with [rc] to also clear older pre-releases, then install the resulting pre-release through BRAT. The keywords only count at the very start of the subject line, so a commit that merely mentions them in its body will not cut a pre-release.

License

MIT

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.