diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java
index 54238266b28389ad1146758590d6c441607c4046..7ae01fe47a056d4d1b7cf361ab3596032e52b25a 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java
@@ -68,8 +68,8 @@ import static org.briarproject.bramble.db.ExponentialBackoff.calculateExpiry;
 @NotNullByDefault
 abstract class JdbcDatabase implements Database<Connection> {
 
-	private static final int SCHEMA_VERSION = 29;
-	private static final int MIN_SCHEMA_VERSION = 29;
+	private static final int SCHEMA_VERSION = 30;
+	private static final int MIN_SCHEMA_VERSION = 30;
 
 	private static final String CREATE_SETTINGS =
 			"CREATE TABLE settings"
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/Blog.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/Blog.java
index b7e1d240fea96c14eed901a1fff18c2c9424dac9..a0e4fff021f700be77017977701959a79d2eca8a 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/blog/Blog.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/Blog.java
@@ -13,16 +13,22 @@ import javax.annotation.concurrent.Immutable;
 public class Blog extends BaseGroup implements Shareable {
 
 	private final Author author;
+	private final boolean rssFeed;
 
-	public Blog(Group group, Author author) {
+	public Blog(Group group, Author author, boolean rssFeed) {
 		super(group);
 		this.author = author;
+		this.rssFeed = rssFeed;
 	}
 
 	public Author getAuthor() {
 		return author;
 	}
 
+	public boolean isRssFeed() {
+		return rssFeed;
+	}
+
 	@Override
 	public boolean equals(Object o) {
 		return o instanceof Blog && super.equals(o);
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogFactory.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogFactory.java
index 4b0a89cf377b3f8c036cd206e1f15a8c78e9be4b..a9d057501da211b41d383b1cad7bf47f110e748f 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogFactory.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogFactory.java
@@ -13,6 +13,11 @@ public interface BlogFactory {
 	 */
 	Blog createBlog(Author author);
 
+	/**
+	 * Creates a RSS feed blog for a given author.
+	 */
+	Blog createFeedBlog(Author author);
+
 	/**
 	 * Parses a blog with the given Group
 	 */
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/feed/Feed.java b/briar-api/src/main/java/org/briarproject/briar/api/feed/Feed.java
index 51f53f10cde72093129db6cf37bbd1a8b61eb4fe..4932ecab75a390cd1757bac874dbab7bacad8e75 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/feed/Feed.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/feed/Feed.java
@@ -93,21 +93,9 @@ public class Feed {
 		if (this == o) return true;
 		if (o instanceof Feed) {
 			Feed f = (Feed) o;
-			return url.equals(f.url) && blog.equals(f.blog) &&
-					equalsWithNull(title, f.title) &&
-					equalsWithNull(description, f.description) &&
-					equalsWithNull(author, f.author) &&
-					added == f.added &&
-					updated == f.updated &&
-					lastEntryTime == f.lastEntryTime;
+			return blog.equals(f.blog);
 		}
 		return false;
 	}
 
-	private boolean equalsWithNull(@Nullable Object a, @Nullable Object b) {
-		if (a == b) return true;
-		if (a == null || b == null) return false;
-		return a.equals(b);
-	}
-
 }
diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java
index 26c1eb108c0f9e75301e3e2a8f854adb6bc91660..deaae2cfe643919c1d2fc1e7a9d422f898190eb4 100644
--- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogFactoryImpl.java
@@ -33,15 +33,25 @@ class BlogFactoryImpl implements BlogFactory {
 
 	@Override
 	public Blog createBlog(Author a) {
+		return createBlog(a, false);
+	}
+
+	@Override
+	public Blog createFeedBlog(Author a) {
+		return createBlog(a, true);
+	}
+
+	private Blog createBlog(Author a, boolean rssFeed) {
 		try {
 			BdfList blog = BdfList.of(
 					a.getName(),
-					a.getPublicKey()
+					a.getPublicKey(),
+					rssFeed
 			);
 			byte[] descriptor = clientHelper.toByteArray(blog);
 			Group g = groupFactory
 					.createGroup(BlogManagerImpl.CLIENT_ID, descriptor);
-			return new Blog(g, a);
+			return new Blog(g, a, rssFeed);
 		} catch (FormatException e) {
 			throw new RuntimeException(e);
 		}
@@ -54,7 +64,7 @@ class BlogFactoryImpl implements BlogFactory {
 		BdfList blog = clientHelper.toList(descriptor);
 		Author a =
 				authorFactory.createAuthor(blog.getString(0), blog.getRaw(1));
-		return new Blog(g, a);
+		return new Blog(g, a, blog.getBoolean(2));
 	}
 
 }
diff --git a/briar-core/src/main/java/org/briarproject/briar/feed/FeedFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/feed/FeedFactoryImpl.java
index 531f169ef57691c00312ea0e1d6e19b4f14df59c..14aca1559836f7d32625b22665626a015e81bd09 100644
--- a/briar-core/src/main/java/org/briarproject/briar/feed/FeedFactoryImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/feed/FeedFactoryImpl.java
@@ -52,7 +52,7 @@ class FeedFactoryImpl implements FeedFactory {
 				.createLocalAuthor(syndFeed.getTitle(),
 						keyPair.getPublic().getEncoded(),
 						keyPair.getPrivate().getEncoded());
-		Blog blog = blogFactory.createBlog(localAuthor);
+		Blog blog = blogFactory.createFeedBlog(localAuthor);
 		long added = clock.currentTimeMillis();
 
 		return new Feed(url, blog, localAuthor, added);
@@ -75,7 +75,7 @@ class FeedFactoryImpl implements FeedFactory {
 		byte[] privateKey = d.getRaw(KEY_PRIVATE_KEY);
 		LocalAuthor localAuthor = authorFactory
 				.createLocalAuthor(blogTitle, publicKey, privateKey);
-		Blog blog = blogFactory.createBlog(localAuthor);
+		Blog blog = blogFactory.createFeedBlog(localAuthor);
 
 		String title = d.getOptionalString(KEY_FEED_TITLE);
 		String desc = d.getOptionalString(KEY_FEED_DESC);
diff --git a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java
index 8db542e8b9a1034d2320990f7a526c3da80eefe4..969de52a3c5eb259c715fd418f100d6a59404824 100644
--- a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java
@@ -30,6 +30,7 @@ import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.system.Clock;
 import org.briarproject.bramble.api.system.Scheduler;
 import org.briarproject.bramble.util.StringUtils;
+import org.briarproject.briar.api.blog.Blog;
 import org.briarproject.briar.api.blog.BlogManager;
 import org.briarproject.briar.api.blog.BlogPost;
 import org.briarproject.briar.api.blog.BlogPostFactory;
@@ -74,7 +75,8 @@ import static org.briarproject.briar.util.HtmlUtils.clean;
 
 @ThreadSafe
 @NotNullByDefault
-class FeedManagerImpl implements FeedManager, Client, EventListener {
+class FeedManagerImpl implements FeedManager, Client, EventListener,
+		BlogManager.RemoveBlogHook {
 
 	private static final Logger LOG =
 			Logger.getLogger(FeedManagerImpl.class.getName());
@@ -158,7 +160,6 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
 
 	@Override
 	public void addFeed(String url) throws DbException, IOException {
-		// TODO check for existing feed?
 		// fetch syndication feed to get its metadata
 		SyndFeed f;
 		try {
@@ -207,15 +208,7 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
 		LOG.info("Removing RSS feed...");
 		Transaction txn = db.startTransaction(false);
 		try {
-			List<Feed> feeds = getFeeds(txn);
-			for (Feed f : feeds) {
-				if (f.getBlogId().equals(feed.getBlogId())) {
-					feed = f;
-					feeds.remove(f);
-					break;
-				}
-			}
-			storeFeeds(txn, feeds);
+			// this will call removingBlog() where the feed itself gets removed
 			blogManager.removeBlog(txn, feed.getBlog());
 			db.commitTransaction(txn);
 		} finally {
@@ -223,6 +216,23 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
 		}
 	}
 
+	@Override
+	public void removingBlog(Transaction txn, Blog b) throws DbException {
+		if (!b.isRssFeed()) return;
+
+		// delete blog's RSS feed if we have it
+		boolean found = false;
+		List<Feed> feeds = getFeeds(txn);
+		for (Feed f : feeds) {
+			if (f.getBlogId().equals(b.getId())) {
+				found = true;
+				feeds.remove(f);
+				break;
+			}
+		}
+		if (found) storeFeeds(txn, feeds);
+	}
+
 	@Override
 	public List<Feed> getFeeds() throws DbException {
 		List<Feed> feeds;
diff --git a/briar-core/src/main/java/org/briarproject/briar/feed/FeedModule.java b/briar-core/src/main/java/org/briarproject/briar/feed/FeedModule.java
index ab8dfbc29322ba6090ec4bcf6f9530e43c2d6980..c4b567c189977888c2e2927fc956e9cb2c40f079 100644
--- a/briar-core/src/main/java/org/briarproject/briar/feed/FeedModule.java
+++ b/briar-core/src/main/java/org/briarproject/briar/feed/FeedModule.java
@@ -2,6 +2,7 @@ package org.briarproject.briar.feed;
 
 import org.briarproject.bramble.api.event.EventBus;
 import org.briarproject.bramble.api.lifecycle.LifecycleManager;
+import org.briarproject.briar.api.blog.BlogManager;
 import org.briarproject.briar.api.feed.FeedManager;
 
 import javax.inject.Inject;
@@ -21,10 +22,12 @@ public class FeedModule {
 	@Provides
 	@Singleton
 	FeedManager provideFeedManager(FeedManagerImpl feedManager,
-			LifecycleManager lifecycleManager, EventBus eventBus) {
+			LifecycleManager lifecycleManager, EventBus eventBus,
+			BlogManager blogManager) {
 
 		lifecycleManager.registerClient(feedManager);
 		eventBus.addListener(feedManager);
+		blogManager.registerRemoveBlogHook(feedManager);
 		return feedManager;
 	}
 
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java
index 6f0df8e473b3db7b1e1361850adb2cff997523a8..f9b378ef7878628b4c29f323b54437e393d47f8d 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java
@@ -39,14 +39,20 @@ class BlogSharingValidator extends SharingValidator {
 	@Override
 	protected GroupId validateDescriptor(BdfList descriptor)
 			throws FormatException {
-		checkSize(descriptor, 2);
+		checkSize(descriptor, 3);
 		String name = descriptor.getString(0);
 		checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH);
 		byte[] publicKey = descriptor.getRaw(1);
 		checkLength(publicKey, 1, MAX_PUBLIC_KEY_LENGTH);
+		boolean rssFeed = descriptor.getBoolean(2);
 
 		Author author = authorFactory.createAuthor(name, publicKey);
-		Blog blog = blogFactory.createBlog(author);
+		Blog blog;
+		if (rssFeed) {
+			blog = blogFactory.createFeedBlog(author);
+		} else {
+			blog = blogFactory.createBlog(author);
+		}
 		return blog.getId();
 	}
 
diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java
index e2b5e8ef5206d162cc029c3cd945362f894eaa96..4ff1bb75c4826d35c093fc7a8815f9acaa32975f 100644
--- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java
@@ -297,7 +297,7 @@ public class BlogManagerImplTest extends BriarTestCase {
 		final LocalAuthor localAuthor =
 				new LocalAuthor(authorId, "Author", publicKey, privateKey,
 						created);
-		return new Blog(group, localAuthor);
+		return new Blog(group, localAuthor, false);
 	}
 
 	private BdfDictionary authorToBdfDictionary(Author a) {
diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
index 1ac77a550e8d3737eadd84e447e9981abb0d443f..d3731d19de9c9fcea112144ab37589e782081793 100644
--- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
@@ -79,7 +79,7 @@ public class BlogPostValidatorTest extends BriarTestCase {
 				new BdfEntry(KEY_AUTHOR_NAME, author.getName()),
 				new BdfEntry(KEY_PUBLIC_KEY, author.getPublicKey())
 		);
-		blog = new Blog(group, author);
+		blog = new Blog(group, author, false);
 
 		MessageId messageId = new MessageId(TestUtils.getRandomId());
 		long timestamp = System.currentTimeMillis();
diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java
index c67360d648b933c8a543e45ea640893f8621a9db..7c4c96ab267cb9f52f769abc2771221b911b75f1 100644
--- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java
@@ -23,8 +23,8 @@ public class BlogSharingValidatorTest extends SharingValidatorTest {
 	private final byte[] publicKey =
 			TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
 	private final Author author = new Author(authorId, authorName, publicKey);
-	private final Blog blog = new Blog(group, author);
-	private final BdfList descriptor = BdfList.of(authorName, publicKey);
+	private final Blog blog = new Blog(group, author, false);
+	private final BdfList descriptor = BdfList.of(authorName, publicKey, false);
 	private final String content =
 			TestUtils.getRandomString(MAX_INVITATION_MESSAGE_LENGTH);
 
@@ -64,7 +64,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest {
 
 	@Test(expected = FormatException.class)
 	public void testRejectsNullBlogName() throws Exception {
-		BdfList invalidDescriptor = BdfList.of(null, publicKey);
+		BdfList invalidDescriptor = BdfList.of(null, publicKey, false);
 		v.validateMessage(message, group,
 				BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
 						null));
@@ -72,7 +72,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest {
 
 	@Test(expected = FormatException.class)
 	public void testRejectsNonStringBlogName() throws Exception {
-		BdfList invalidDescriptor = BdfList.of(123, publicKey);
+		BdfList invalidDescriptor = BdfList.of(123, publicKey, false);
 		v.validateMessage(message, group,
 				BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
 						null));
@@ -80,7 +80,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest {
 
 	@Test(expected = FormatException.class)
 	public void testRejectsTooShortBlogName() throws Exception {
-		BdfList invalidDescriptor = BdfList.of("", publicKey);
+		BdfList invalidDescriptor = BdfList.of("", publicKey, false);
 		v.validateMessage(message, group,
 				BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
 						null));
@@ -89,7 +89,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest {
 	@Test
 	public void testAcceptsMinLengthBlogName() throws Exception {
 		String shortBlogName = TestUtils.getRandomString(1);
-		BdfList validDescriptor = BdfList.of(shortBlogName, publicKey);
+		BdfList validDescriptor = BdfList.of(shortBlogName, publicKey, false);
 		expectCreateBlog(shortBlogName, publicKey);
 		expectEncodeMetadata(INVITE);
 		BdfMessageContext messageContext = v.validateMessage(message, group,
@@ -102,7 +102,8 @@ public class BlogSharingValidatorTest extends SharingValidatorTest {
 	public void testRejectsTooLongBlogName() throws Exception {
 		String invalidBlogName =
 				TestUtils.getRandomString(MAX_BLOG_NAME_LENGTH + 1);
-		BdfList invalidDescriptor = BdfList.of(invalidBlogName, publicKey);
+		BdfList invalidDescriptor =
+				BdfList.of(invalidBlogName, publicKey, false);
 		v.validateMessage(message, group,
 				BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
 						null));
@@ -110,7 +111,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest {
 
 	@Test(expected = FormatException.class)
 	public void testRejectsNullPublicKey() throws Exception {
-		BdfList invalidDescriptor = BdfList.of(authorName, null);
+		BdfList invalidDescriptor = BdfList.of(authorName, null, false);
 		v.validateMessage(message, group,
 				BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
 						null));
@@ -118,7 +119,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest {
 
 	@Test(expected = FormatException.class)
 	public void testRejectsNonRawPublicKey() throws Exception {
-		BdfList invalidDescriptor = BdfList.of(authorName, 123);
+		BdfList invalidDescriptor = BdfList.of(authorName, 123, false);
 		v.validateMessage(message, group,
 				BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
 						null));
@@ -127,7 +128,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest {
 	@Test(expected = FormatException.class)
 	public void testRejectsTooLongPublicKey() throws Exception {
 		byte[] invalidKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1);
-		BdfList invalidDescriptor = BdfList.of(authorName, invalidKey);
+		BdfList invalidDescriptor = BdfList.of(authorName, invalidKey, false);
 		v.validateMessage(message, group,
 				BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor,
 						null));
@@ -136,7 +137,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest {
 	@Test
 	public void testAcceptsMinLengthPublicKey() throws Exception {
 		byte[] key = TestUtils.getRandomBytes(1);
-		BdfList validDescriptor = BdfList.of(authorName, key);
+		BdfList validDescriptor = BdfList.of(authorName, key, false);
 
 		expectCreateBlog(authorName, key);
 		expectEncodeMetadata(INVITE);