diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
index 9923043643e8983be4adc12d72877df2e5337b7b..9394f9d02ee249fc0bf9495e4f00df3fc6cb343b 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
@@ -32,6 +32,7 @@ import org.briarproject.briar.api.android.ScreenFilterMonitor;
 import org.briarproject.briar.api.blog.BlogManager;
 import org.briarproject.briar.api.blog.BlogPostFactory;
 import org.briarproject.briar.api.blog.BlogSharingManager;
+import org.briarproject.briar.api.client.MessageTracker;
 import org.briarproject.briar.api.feed.FeedManager;
 import org.briarproject.briar.api.forum.ForumManager;
 import org.briarproject.briar.api.forum.ForumSharingManager;
@@ -78,6 +79,8 @@ public interface AndroidComponent
 	@DatabaseExecutor
 	Executor databaseExecutor();
 
+	MessageTracker messageTracker();
+
 	LifecycleManager lifecycleManager();
 
 	IdentityManager identityManager();
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java
index eaeb7a06ec1c15fbc58e42a2d27c03bb8124eda8..6ae01b8a53ad11cac4857179ccf52f41c9b577b2 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java
@@ -17,7 +17,7 @@ public class DbControllerImpl implements DbController {
 	private static final Logger LOG =
 			Logger.getLogger(DbControllerImpl.class.getName());
 
-	private final Executor dbExecutor;
+	protected final Executor dbExecutor;
 	private final LifecycleManager lifecycleManager;
 
 	@Inject
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java
index 4c52f6154c90103da580c4206ffc2dd3b4a882fb..8d97e7810063d4a4d20209a469220b5a2b7e8f47 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java
@@ -17,6 +17,7 @@ import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
 import org.briarproject.briar.android.forum.ForumController.ForumListener;
 import org.briarproject.briar.android.threaded.ThreadListControllerImpl;
 import org.briarproject.briar.api.android.AndroidNotificationManager;
+import org.briarproject.briar.api.client.MessageTracker;
 import org.briarproject.briar.api.client.MessageTracker.GroupCount;
 import org.briarproject.briar.api.forum.Forum;
 import org.briarproject.briar.api.forum.ForumInvitationResponse;
@@ -55,10 +56,10 @@ class ForumControllerImpl extends
 			LifecycleManager lifecycleManager, IdentityManager identityManager,
 			@CryptoExecutor Executor cryptoExecutor,
 			ForumManager forumManager, ForumSharingManager forumSharingManager,
-			EventBus eventBus, Clock clock,
+			EventBus eventBus, Clock clock, MessageTracker messageTracker,
 			AndroidNotificationManager notificationManager) {
 		super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
-				eventBus, clock, notificationManager);
+				eventBus, clock, notificationManager, messageTracker);
 		this.forumManager = forumManager;
 		this.forumSharingManager = forumSharingManager;
 	}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java
index 0c75305591d4220540a76c85683760b273b31d76..db6029e57c002ad2f8365ee7cc915670b4e7c386 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java
@@ -17,6 +17,7 @@ import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
 import org.briarproject.briar.android.privategroup.conversation.GroupController.GroupListener;
 import org.briarproject.briar.android.threaded.ThreadListControllerImpl;
 import org.briarproject.briar.api.android.AndroidNotificationManager;
+import org.briarproject.briar.api.client.MessageTracker;
 import org.briarproject.briar.api.client.MessageTracker.GroupCount;
 import org.briarproject.briar.api.privategroup.GroupMember;
 import org.briarproject.briar.api.privategroup.GroupMessage;
@@ -60,9 +61,10 @@ class GroupControllerImpl extends
 			@CryptoExecutor Executor cryptoExecutor,
 			PrivateGroupManager privateGroupManager,
 			GroupMessageFactory groupMessageFactory, EventBus eventBus,
-			Clock clock, AndroidNotificationManager notificationManager) {
+			MessageTracker messageTracker, Clock clock,
+			AndroidNotificationManager notificationManager) {
 		super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
-				eventBus, clock, notificationManager);
+				eventBus, clock, notificationManager, messageTracker);
 		this.privateGroupManager = privateGroupManager;
 		this.groupMessageFactory = groupMessageFactory;
 	}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java
index 72b03a03fc133340218e0f45ddb801446c9349db..1c10a8b3608939bccbed4fb33687b5e2290ce93e 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java
@@ -1,5 +1,6 @@
 package org.briarproject.briar.android.threaded;
 
+import android.os.Handler;
 import android.support.annotation.Nullable;
 import android.support.annotation.UiThread;
 import android.support.v7.widget.LinearLayoutManager;
@@ -26,6 +27,7 @@ public class ThreadItemAdapter<I extends ThreadItem>
 	protected final NestedTreeList<I> items = new NestedTreeList<>();
 	private final ThreadItemListener<I> listener;
 	private final LinearLayoutManager layoutManager;
+	private final Handler handler = new Handler();
 
 	private volatile int revision = 0;
 
@@ -64,6 +66,17 @@ public class ThreadItemAdapter<I extends ThreadItem>
 		revision++;
 	}
 
+	void setItemWithIdVisible(MessageId messageId) {
+		int pos = 0;
+		for (I item : items) {
+			if (item.getId().equals(messageId)) {
+				layoutManager.scrollToPosition(pos);
+				break;
+			}
+			pos++;
+		}
+	}
+
 	public void setItems(Collection<I> items) {
 		this.items.clear();
 		this.items.addAll(items);
@@ -144,7 +157,7 @@ public class ThreadItemAdapter<I extends ThreadItem>
 	/**
 	 * Returns the position of the first unread item below the current viewport
 	 */
-	public int getVisibleUnreadPosBottom() {
+	int getVisibleUnreadPosBottom() {
 		final int positionBottom = layoutManager.findLastVisibleItemPosition();
 		if (positionBottom == NO_POSITION) return NO_POSITION;
 		for (int i = positionBottom + 1; i < items.size(); i++) {
@@ -156,7 +169,7 @@ public class ThreadItemAdapter<I extends ThreadItem>
 	/**
 	 * Returns the position of the first unread item above the current viewport
 	 */
-	public int getVisibleUnreadPosTop() {
+	int getVisibleUnreadPosTop() {
 		final int positionTop = layoutManager.findFirstVisibleItemPosition();
 		int position = NO_POSITION;
 		for (int i = 0; i < items.size(); i++) {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemList.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemList.java
new file mode 100644
index 0000000000000000000000000000000000000000..f517e8e9ccb5c359c3864afe3f05a26dba75cc7f
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemList.java
@@ -0,0 +1,15 @@
+package org.briarproject.briar.android.threaded;
+
+import org.briarproject.bramble.api.sync.MessageId;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+public interface ThreadItemList<I extends ThreadItem> extends List<I> {
+
+	@Nullable
+	MessageId getFirstVisibleItemId();
+
+	void setFirstVisibleId(@Nullable MessageId bottomVisibleItemId);
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemListImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemListImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..2886607edce8eecc24a62075dfe07b385e21b94b
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemListImpl.java
@@ -0,0 +1,22 @@
+package org.briarproject.briar.android.threaded;
+
+import org.briarproject.bramble.api.sync.MessageId;
+
+import java.util.ArrayList;
+
+import javax.annotation.Nullable;
+
+public class ThreadItemListImpl<I extends ThreadItem> extends ArrayList<I>
+		implements ThreadItemList<I> {
+
+	private MessageId bottomVisibleItemId;
+
+	@Override
+	public MessageId getFirstVisibleItemId() {
+		return bottomVisibleItemId;
+	}
+
+	public void setFirstVisibleId(@Nullable MessageId bottomVisibleItemId) {
+		this.bottomVisibleItemId = bottomVisibleItemId;
+	}
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java
index 8106be7edb5fc6b1cd50a9bbd5a7257f4984f4e0..fba82cc144d6a71eded33b37966306235f976818 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java
@@ -26,6 +26,7 @@ import org.briarproject.briar.android.controller.SharingController;
 import org.briarproject.briar.android.controller.SharingController.SharingListener;
 import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
 import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener;
+import org.briarproject.briar.android.threaded.ThreadListController.ThreadListDataSource;
 import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener;
 import org.briarproject.briar.android.view.BriarRecyclerView;
 import org.briarproject.briar.android.view.TextInputView;
@@ -51,7 +52,7 @@ import static org.briarproject.briar.android.threaded.ThreadItemAdapter.UnreadCo
 public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadItemAdapter<I>, I extends ThreadItem, H extends PostHeader>
 		extends BriarActivity
 		implements ThreadListListener<H>, TextInputListener, SharingListener,
-		ThreadItemListener<I> {
+		ThreadItemListener<I>, ThreadListDataSource {
 
 	protected static final String KEY_REPLY_ID = "replyId";
 
@@ -68,6 +69,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
 	private MessageId replyId;
 
 	protected abstract ThreadListController<G, I, H> getController();
+
 	@Inject
 	protected SharingController sharingController;
 
@@ -104,6 +106,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
 							updateUnreadCount();
 						}
 					}
+
 					@Override
 					public void onScrollStateChanged(RecyclerView recyclerView,
 							int newState) {
@@ -144,6 +147,18 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
 		loadSharingContacts();
 	}
 
+	@Override
+	@Nullable
+	public MessageId getFirstVisibleMessageId() {
+		if (layoutManager != null && adapter != null) {
+			int position =
+					layoutManager.findFirstVisibleItemPosition();
+			I i = adapter.getItemAt(position);
+			return i == null ? null : i.getId();
+		}
+		return null;
+	}
+
 	protected abstract A createAdapter(LinearLayoutManager layoutManager);
 
 	protected void loadNamedGroup() {
@@ -167,16 +182,16 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
 	protected void loadItems() {
 		final int revision = adapter.getRevision();
 		getController().loadItems(
-				new UiResultExceptionHandler<Collection<I>, DbException>(this) {
+				new UiResultExceptionHandler<ThreadItemList<I>, DbException>(
+						this) {
 					@Override
-					public void onResultUi(Collection<I> items) {
+					public void onResultUi(ThreadItemList<I> items) {
 						if (revision == adapter.getRevision()) {
 							adapter.incrementRevision();
 							if (items.isEmpty()) {
 								list.showData();
 							} else {
-								adapter.setItems(items);
-								list.showData();
+								initList(items);
 								updateTextInput(replyId);
 							}
 						} else {
@@ -192,6 +207,15 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
 				});
 	}
 
+	private void initList(final ThreadItemList<I> items) {
+		adapter.setItems(items);
+		MessageId messageId = items.getFirstVisibleItemId();
+		if (messageId != null)
+			adapter.setItemWithIdVisible(messageId);
+		updateUnreadCount();
+		list.showData();
+	}
+
 	protected void loadSharingContacts() {
 		getController().loadSharingContacts(
 				new UiResultExceptionHandler<Collection<ContactId>, DbException>(
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java
index caebd1ec65d53dad3c590e0d1cf287703073e0d2..d39c8b453a6c1c5852d9c56663edd1d7ca0fe4fa 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java
@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.contact.ContactId;
 import org.briarproject.bramble.api.db.DbException;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.GroupId;
+import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.android.DestroyableContext;
 import org.briarproject.briar.android.controller.ActivityLifecycleController;
 import org.briarproject.briar.android.controller.handler.ExceptionHandler;
@@ -30,7 +31,7 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem
 
 	void loadItem(H header, ResultExceptionHandler<I, DbException> handler);
 
-	void loadItems(ResultExceptionHandler<Collection<I>, DbException> handler);
+	void loadItems(ResultExceptionHandler<ThreadItemList<I>, DbException> handler);
 
 	void markItemRead(I item);
 
@@ -41,7 +42,7 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem
 
 	void deleteNamedGroup(ExceptionHandler<DbException> handler);
 
-	interface ThreadListListener<H> extends DestroyableContext {
+	interface ThreadListListener<H> extends ThreadListDataSource {
 		@UiThread
 		void onHeaderReceived(H header);
 
@@ -52,4 +53,10 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem
 		void onInvitationAccepted(ContactId c);
 	}
 
+	interface ThreadListDataSource extends DestroyableContext {
+
+		@UiThread @Nullable
+		MessageId getFirstVisibleMessageId();
+	}
+
 }
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java
index a2db5242d9cd8bba435fa1cd50bf28d0e79e8a5e..0793d785adf6ec8744748cf8df28175da1df766a 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java
@@ -22,14 +22,13 @@ import org.briarproject.briar.android.controller.handler.ExceptionHandler;
 import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
 import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener;
 import org.briarproject.briar.api.android.AndroidNotificationManager;
+import org.briarproject.briar.api.client.MessageTracker;
 import org.briarproject.briar.api.client.NamedGroup;
 import org.briarproject.briar.api.client.PostHeader;
 import org.briarproject.briar.api.client.ThreadedMessage;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
@@ -55,18 +54,21 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 	protected final AndroidNotificationManager notificationManager;
 	protected final Executor cryptoExecutor;
 	protected final Clock clock;
+	private final MessageTracker messageTracker;
 	protected volatile L listener;
 
 	protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor,
 			LifecycleManager lifecycleManager, IdentityManager identityManager,
 			@CryptoExecutor Executor cryptoExecutor, EventBus eventBus,
-			Clock clock, AndroidNotificationManager notificationManager) {
+			Clock clock, AndroidNotificationManager notificationManager,
+			MessageTracker messageTracker) {
 		super(dbExecutor, lifecycleManager);
 		this.identityManager = identityManager;
 		this.cryptoExecutor = cryptoExecutor;
 		this.notificationManager = notificationManager;
 		this.clock = clock;
 		this.eventBus = eventBus;
+		this.messageTracker = messageTracker;
 	}
 
 	@Override
@@ -97,6 +99,19 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 
 	@Override
 	public void onActivityDestroy() {
+		dbExecutor.execute(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					messageTracker
+							.storeMessageId(groupId,
+									listener.getFirstVisibleMessageId());
+				} catch (DbException e) {
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				}
+			}
+		});
 	}
 
 	@CallSuper
@@ -144,7 +159,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 
 	@Override
 	public void loadItems(
-			final ResultExceptionHandler<Collection<I>, DbException> handler) {
+			final ResultExceptionHandler<ThreadItemList<I>, DbException> handler) {
 		checkGroupId();
 		runOnDbThread(new Runnable() {
 			@Override
@@ -293,11 +308,16 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 	@DatabaseExecutor
 	protected abstract void deleteNamedGroup(G groupItem) throws DbException;
 
-	private List<I> buildItems(Collection<H> headers) {
-		List<I> items = new ArrayList<>();
+	private ThreadItemList<I> buildItems(Collection<H> headers)
+			throws DbException {
+		ThreadItemList<I> items = new ThreadItemListImpl<>();
 		for (H h : headers) {
 			items.add(buildItem(h, bodyCache.get(h.getId())));
 		}
+		MessageId msgId = messageTracker.loadStoredMessageId(groupId);
+		if (LOG.isLoggable(INFO))
+			LOG.info("Loaded last top visible message id " + msgId);
+		items.setFirstVisibleId(msgId);
 		return items;
 	}
 
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java b/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java
index e7f4fa92f5387377a72ea82ba02f7b0d1b3ae9bf..4a5360043e21128e68b15c276db786f1d7c01d14 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java
@@ -36,8 +36,7 @@ public class UnreadMessageButton extends FrameLayout {
 
 		LayoutInflater inflater = (LayoutInflater) context
 				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-		inflater
-				.inflate(R.layout.unread_message_button, this, true);
+		inflater.inflate(R.layout.unread_message_button, this, true);
 
 		fab = (FloatingActionButton) findViewById(R.id.fab);
 		unread = (TextView) findViewById(R.id.unreadCountView);
@@ -64,15 +63,11 @@ public class UnreadMessageButton extends FrameLayout {
 
 	public void setUnreadCount(int count) {
 		if (count == 0) {
-			fab.setVisibility(GONE);
-//			fab.hide();
-			unread.setVisibility(GONE);
+			setVisibility(INVISIBLE);
 		} else {
 			// FIXME: Use animations when upgrading to support library 24.2.0
 			//        https://code.google.com/p/android/issues/detail?id=216469
-			fab.setVisibility(VISIBLE);
-//			if (!fab.isShown()) fab.show();
-			unread.setVisibility(VISIBLE);
+			setVisibility(VISIBLE);
 			unread.setText(String.valueOf(count));
 		}
 	}
diff --git a/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java b/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java
index 8a3461c2eb1c4472cbf86a1d20db8ce08f06e8ff..96ffc88eb15de617846e5c5aba9d4c6242651f8d 100644
--- a/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java
+++ b/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java
@@ -13,6 +13,8 @@ import org.briarproject.briar.BuildConfig;
 import org.briarproject.briar.android.TestBriarApplication;
 import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
 import org.briarproject.briar.android.threaded.ThreadItemAdapter;
+import org.briarproject.briar.android.threaded.ThreadItemList;
+import org.briarproject.briar.android.threaded.ThreadItemListImpl;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,10 +25,7 @@ import org.robolectric.Robolectric;
 import org.robolectric.RobolectricGradleTestRunner;
 import org.robolectric.annotation.Config;
 
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
@@ -81,7 +80,7 @@ public class ForumActivityTest {
 
 	private TestForumActivity forumActivity;
 	@Captor
-	private ArgumentCaptor<UiResultExceptionHandler<Collection<ForumItem>, DbException>>
+	private ArgumentCaptor<UiResultExceptionHandler<ThreadItemList<ForumItem>, DbException>>
 			rc;
 
 	@Before
@@ -93,7 +92,7 @@ public class ForumActivityTest {
 				.withIntent(intent).create().resume().get();
 	}
 
-	private List<ForumItem> getDummyData() {
+	private ThreadItemList<ForumItem> getDummyData() {
 		ForumItem[] forumItems = new ForumItem[6];
 		for (int i = 0; i < forumItems.length; i++) {
 			AuthorId authorId = new AuthorId(TestUtils.getRandomId());
@@ -103,13 +102,15 @@ public class ForumActivityTest {
 					AUTHORS[i], System.currentTimeMillis(), author, UNKNOWN);
 			forumItems[i].setLevel(LEVELS[i]);
 		}
-		return new ArrayList<>(Arrays.asList(forumItems));
+		ThreadItemList<ForumItem> list = new ThreadItemListImpl<>();
+		list.addAll(Arrays.asList(forumItems));
+		return list;
 	}
 
 	@Test
 	public void testNestedEntries() {
 		ForumController mc = forumActivity.getController();
-		List<ForumItem> dummyData = getDummyData();
+		ThreadItemList<ForumItem> dummyData = getDummyData();
 		verify(mc, times(1)).loadItems(rc.capture());
 		rc.getValue().onResult(dummyData);
 		ThreadItemAdapter<ForumItem> adapter = forumActivity.getAdapter();
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTracker.java b/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTracker.java
index 44c26fef4d583fc947e5e59e35954513c5ec3d98..5d6418f0aceaf17b46714509ec96c881187a31f1 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTracker.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTracker.java
@@ -7,6 +7,8 @@ import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.sync.MessageId;
 
+import javax.annotation.Nullable;
+
 @NotNullByDefault
 public interface MessageTracker {
 
@@ -38,6 +40,19 @@ public interface MessageTracker {
 	void trackMessage(Transaction txn, GroupId g, long timestamp, boolean read)
 			throws DbException;
 
+	/**
+	 *  Loads the stored message id for the respective group id or returns null
+	 *  if none is available.
+	 */
+	@Nullable
+	MessageId loadStoredMessageId(GroupId g) throws DbException;
+
+	/**
+	 * Stores the message id for the respective group id. Exactly one message id
+	 * can be stored for any group id at any time, older values are overwritten.
+	 */
+	void storeMessageId(GroupId g, MessageId m) throws DbException;
+
 	/**
 	 * Marks a message as read or unread and updates the group count.
 	 */
diff --git a/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerConstants.java b/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerConstants.java
index ca689fc1ca2543ecb6ae80e922831233a9daf319..81a1d603bfedd505c1b10f3ec4d321d862c27067 100644
--- a/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerConstants.java
+++ b/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerConstants.java
@@ -2,6 +2,7 @@ package org.briarproject.briar.client;
 
 public interface MessageTrackerConstants {
 
+	String GROUP_KEY_STORED_MESSAGE_ID = "storedMessageId";
 	String GROUP_KEY_MSG_COUNT = "messageCount";
 	String GROUP_KEY_UNREAD_COUNT = "unreadCount";
 	String GROUP_KEY_LATEST_MSG = "latestMessageTime";
diff --git a/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerImpl.java b/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerImpl.java
index bd230dca8ea0ab8efda10cc9f1c6744a0186bbda..18e034027c906507119141a3b5e99993f9f7429d 100644
--- a/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerImpl.java
@@ -13,11 +13,13 @@ import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.api.client.MessageTracker;
 
+import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 
 import static org.briarproject.briar.client.MessageTrackerConstants.GROUP_KEY_LATEST_MSG;
 import static org.briarproject.briar.client.MessageTrackerConstants.GROUP_KEY_MSG_COUNT;
+import static org.briarproject.briar.client.MessageTrackerConstants.GROUP_KEY_STORED_MESSAGE_ID;
 import static org.briarproject.briar.client.MessageTrackerConstants.GROUP_KEY_UNREAD_COUNT;
 import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
 
@@ -57,6 +59,30 @@ class MessageTrackerImpl implements MessageTracker {
 				latestMsgTime));
 	}
 
+	@Nullable
+	@Override
+	public MessageId loadStoredMessageId(GroupId g) throws DbException {
+		try {
+			BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(g);
+			byte[] msgBytes = d.getOptionalRaw(GROUP_KEY_STORED_MESSAGE_ID);
+			return msgBytes != null ? new MessageId(msgBytes) : null;
+		} catch (FormatException e) {
+			throw new DbException(e);
+		}
+	}
+
+	@Override
+	public void storeMessageId(GroupId g, MessageId m) throws DbException {
+		BdfDictionary d = BdfDictionary.of(
+				new BdfEntry(GROUP_KEY_STORED_MESSAGE_ID, m)
+		);
+		try {
+			clientHelper.mergeGroupMetadata(g, d);
+		} catch (FormatException e) {
+			throw new DbException(e);
+		}
+	}
+
 	@Override
 	public GroupCount getGroupCount(GroupId g) throws DbException {
 		GroupCount count;
diff --git a/briar-core/src/test/java/org/briarproject/briar/client/MessageTrackerTest.java b/briar-core/src/test/java/org/briarproject/briar/client/MessageTrackerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7e8603202c358a92e625380282fbba3e35d619e
--- /dev/null
+++ b/briar-core/src/test/java/org/briarproject/briar/client/MessageTrackerTest.java
@@ -0,0 +1,50 @@
+package org.briarproject.briar.client;
+
+import org.briarproject.bramble.api.client.ClientHelper;
+import org.briarproject.bramble.api.data.BdfDictionary;
+import org.briarproject.bramble.api.data.BdfEntry;
+import org.briarproject.bramble.api.db.DatabaseComponent;
+import org.briarproject.bramble.api.sync.GroupId;
+import org.briarproject.bramble.api.sync.MessageId;
+import org.briarproject.bramble.test.BrambleMockTestCase;
+import org.briarproject.bramble.test.TestUtils;
+import org.briarproject.briar.api.client.MessageTracker;
+import org.jmock.Expectations;
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.briarproject.briar.client.MessageTrackerConstants.GROUP_KEY_STORED_MESSAGE_ID;
+
+public class MessageTrackerTest extends BrambleMockTestCase {
+
+	protected final GroupId groupId = new GroupId(TestUtils.getRandomId());
+	protected final ClientHelper clientHelper =
+			context.mock(ClientHelper.class);
+	private final DatabaseComponent db = context.mock(DatabaseComponent.class);
+	private final MessageId messageId = new MessageId(TestUtils.getRandomId());
+	private final MessageTracker messageTracker =
+			new MessageTrackerImpl(db, clientHelper);
+	private final BdfDictionary dictionary = BdfDictionary.of(
+			new BdfEntry(GROUP_KEY_STORED_MESSAGE_ID, messageId)
+	);
+
+	@Test
+	public void testMessageStore() throws Exception {
+		context.checking(new Expectations() {{
+			oneOf(clientHelper).mergeGroupMetadata(groupId, dictionary);
+		}});
+		messageTracker.storeMessageId(groupId, messageId);
+	}
+
+	@Test
+	public void testMessageLoad() throws Exception {
+		context.checking(new Expectations() {{
+			oneOf(clientHelper).getGroupMetadataAsDictionary(groupId);
+			will(returnValue(dictionary));
+		}});
+		MessageId loadedId = messageTracker.loadStoredMessageId(groupId);
+		Assert.assertNotNull(loadedId);
+		Assert.assertTrue(messageId.equals(loadedId));
+	}
+
+}