diff --git a/apps/ssb.json b/apps/ssb.json
index 81d1f20c..0c7f7294 100644
--- a/apps/ssb.json
+++ b/apps/ssb.json
@@ -1,5 +1,5 @@
 {
 	"type": "tildefriends-app",
 	"emoji": "π",
-	"previous": "&pySy2RopLJGGrJRpoyzKM7zDzQUCxRXLuE62kS4C5s4=.sha256"
+	"previous": "&0gBRfD+3EaZD2S82zAnXT3hgGuNTnUncOh5vGwZwbSw=.sha256"
 }
diff --git a/apps/ssb/tf-app.js b/apps/ssb/tf-app.js
index 6e7e3701..b18ab4e5 100644
--- a/apps/ssb/tf-app.js
+++ b/apps/ssb/tf-app.js
@@ -267,6 +267,34 @@ class TfElement extends LitElement {
 		}
 	}
 
+	async get_latest_private(following) {
+		let latest = (await tfrpc.rpc.query('SELECT MAX(rowid) AS latest FROM messages'))[0].latest;
+		const k_chunk_count = 256;
+		while (latest - k_chunk_count >= 0) {
+			let messages = await tfrpc.rpc.query(`
+					SELECT messages.rowid, messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
+						FROM messages
+						JOIN json_each(?1) AS following ON messages.author = following.value
+						WHERE
+							messages.rowid > ?2 AND
+							messages.rowid <= ?3 AND
+							json(messages.content) LIKE '"%'
+						ORDER BY sequence DESC
+					`,
+					[
+						JSON.stringify(following),
+						latest - k_chunk_count,
+						latest,
+					]);
+			messages = (await this.decrypt(messages)).filter(x => x.decrypted);
+			if (messages.length) {
+				return Math.max(...messages.map(x => x.rowid));
+			}
+			latest -= k_chunk_count;
+		};
+		return -1;
+	}
+
 	async load() {
 		let whoami = this.whoami;
 		let following = await tfrpc.rpc.following([whoami], 2);
@@ -302,6 +330,7 @@ class TfElement extends LitElement {
 				'"' + this.whoami.replace('"', '""') + '"',
 			]
 		);
+		let latest_private = this.get_latest_private(Object.keys(following));
 		this.channels_unread = JSON.parse(
 			(await tfrpc.rpc.databaseGet('unread')) ?? '{}'
 		);
@@ -320,6 +349,11 @@ class TfElement extends LitElement {
 		this.channels_latest = Object.fromEntries(
 			channels.map((x) => [x.channel, x.rowid])
 		);
+		let self = this;
+		latest_private.then(function(latest) {
+			self.channels_latest = Object.assign({}, self.channels_latest, {'π': latest});
+			console.log('private took', (new Date() - start_time) / 1000.0);
+		});
 		this.following = Object.keys(following);
 		this.users = users;
 		console.log(`load finished ${whoami} => ${this.whoami}`);
@@ -333,6 +367,30 @@ class TfElement extends LitElement {
 		tfrpc.rpc.databaseSet('unread', JSON.stringify(this.channels_unread));
 	}
 
+	async decrypt(messages) {
+		let whoami = this.whoami;
+		return Promise.all(messages.map(async function (message) {
+			let content;
+			try {
+				content = JSON.parse(message?.content);
+			} catch {}
+			if (typeof content === 'string') {
+				let decrypted;
+				try {
+					decrypted = await tfrpc.rpc.try_decrypt(whoami, content);
+				} catch {}
+				if (decrypted) {
+					try {
+						message.decrypted = JSON.parse(decrypted);
+					} catch {
+						message.decrypted = decrypted;
+					}
+				}
+			}
+			return message;
+		}));
+	}
+
 	render_tab() {
 		let following = this.following;
 		let users = this.users;
diff --git a/apps/ssb/tf-tab-news-feed.js b/apps/ssb/tf-tab-news-feed.js
index aa061218..609a8960 100644
--- a/apps/ssb/tf-tab-news-feed.js
+++ b/apps/ssb/tf-tab-news-feed.js
@@ -151,6 +151,21 @@ class TfTabNewsFeedElement extends LitElement {
 				);
 			}
 			result = [].concat(...(await Promise.all(promises)));
+		} else if (this.hash == '#π') {
+			result = await tfrpc.rpc.query(
+				`
+					SELECT messages.rowid, messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
+						FROM messages
+						JOIN json_each(?1) AS following ON messages.author = following.value
+						WHERE
+							messages.timestamp >= ?2 AND
+							messages.timestamp < ?3 AND
+							json(messages.content) LIKE '"%'
+						ORDER BY sequence DESC
+				`,
+				[JSON.stringify(this.following), start_time, end_time]
+			);
+			result = (await this.decrypt(result)).filter(x => x.decrypted);
 		} else {
 			let promises = [];
 			const k_following_limit = 256;
diff --git a/apps/ssb/tf-tab-news.js b/apps/ssb/tf-tab-news.js
index c7f7ce78..9202d5de 100644
--- a/apps/ssb/tf-tab-news.js
+++ b/apps/ssb/tf-tab-news.js
@@ -210,6 +210,12 @@ class TfTabNewsElement extends LitElement {
 					style=${this.hash == '#@' ? 'font-weight: bold' : undefined}
 					>@mentions ${this.unread_status('@')}
+				πprivate ${this.unread_status('π')}
 				${this.channels.map(
 					(x) => html`