diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d9619c..d1cc10d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ the public changelog at [castora.social/changelog](https://castora.social/change
> `src/app/changelog/entries.ts` (the website source of truth, newest first) and
> mirror it here. Keep wording user-friendly. See `AGENTS.md`.
+## 2026-06-22 — Tabbed notifications
+- Notifications now have tabs — All, Replies, Mentions, Likes, Recasts, and Follows — so you can jump straight to the type you care about.
+- Replies and mentions now show the cast they're responding to, inline, so you get the full context without opening the thread.
+
## 2026-06-22 — Multiple accounts are back
- Connect more than one Farcaster account and switch between them from the profile menu — browse, post, and get notifications as any of your accounts.
- The "Add account" button works again (sign in with Neynar): a new account is attached alongside your existing ones instead of replacing them.
diff --git a/src/app/api/notifications/route.ts b/src/app/api/notifications/route.ts
index 62146e4..c690601 100644
--- a/src/app/api/notifications/route.ts
+++ b/src/app/api/notifications/route.ts
@@ -27,18 +27,27 @@ export const GET = withAuthInfra(async (req: Request) => {
const url = new URL(req.url)
const cursor = url.searchParams.get("cursor")
- const mode = url.searchParams.get("mode")
const priority = url.searchParams.get("priority")
+ // New tabbed inbox: filter by a Neynar notification type (comma-separated ok).
+ const type = url.searchParams.get("type")
+ // Legacy two-tab UI: mode=all | mentions.
+ const mode = url.searchParams.get("mode")
- let response;
+ const NEYNAR_NOTIFICATION_TYPES = new Set(["follows", "recasts", "likes", "mentions", "replies", "quotes"])
- if (mode === "all") {
- response = await neynar.get(`/v2/farcaster/notifications/?fid=${targetFid}&priority_mode=${priority}&cursor=${cursor}`)
+ let typeFilter = ""
+ if (type) {
+ if (!type.split(",").every((t) => NEYNAR_NOTIFICATION_TYPES.has(t))) {
+ return Response.json({ "error": "Invalid notification type" }, { status: 400 })
+ }
+ typeFilter = `&type=${type}`
} else if (mode === "mentions") {
- response = await neynar.get(`/v2/farcaster/notifications/?fid=${targetFid}&type=mentions,replies&priority_mode=${priority}&cursor=${cursor}`)
- } else {
+ typeFilter = "&type=mentions,replies"
+ } else if (mode && mode !== "all") {
return Response.json({ "error": "Invalid mode (expected 'all' or 'mentions')" }, { status: 400 })
}
+ const response = await neynar.get(`/v2/farcaster/notifications/?fid=${targetFid}${typeFilter}&priority_mode=${priority}&cursor=${cursor}`)
+
return Response.json({ "unread": response.data.unseen_notifications_count, "notifications": response.data.notifications, "cursor": response.data.next.cursor })
})
\ No newline at end of file
diff --git a/src/app/changelog/entries.ts b/src/app/changelog/entries.ts
index 8331a8c..70e3287 100644
--- a/src/app/changelog/entries.ts
+++ b/src/app/changelog/entries.ts
@@ -18,6 +18,15 @@ export type ChangelogEntry = {
}
export const changelog: ChangelogEntry[] = [
+ {
+ date: '2026-06-22',
+ title: 'Tabbed notifications',
+ tag: 'feature',
+ items: [
+ 'Notifications now have tabs — All, Replies, Mentions, Likes, Recasts, and Follows — so you can jump straight to the type you care about.',
+ 'Replies and mentions now show the cast they\'re responding to, inline, so you get the full context without opening the thread.',
+ ],
+ },
{
date: '2026-06-22',
title: 'Multiple accounts are back',
diff --git a/src/components/NotificationsFeed.tsx b/src/components/NotificationsFeed.tsx
index 52136eb..4182dca 100644
--- a/src/components/NotificationsFeed.tsx
+++ b/src/components/NotificationsFeed.tsx
@@ -7,7 +7,7 @@ import PullToRefresh from 'react-simple-pull-to-refresh';
import { isMobile } from 'react-device-detect'
import { useInView } from 'react-intersection-observer';
import FeedHeader from './FeedHeader';
-import { useNotifications } from '@/providers/NotificationsProvider'
+import { useNotifications, NOTIFICATION_TABS } from '@/providers/NotificationsProvider'
import { useNotificationsRefresh } from '@/providers/FeedRefreshProvider'
import CastInFeedSkeleton from './casts/CastInFeedSkeleton'
import { Cog6ToothIcon } from '@heroicons/react/24/outline'
@@ -165,27 +165,21 @@ export default function NotificationsFeed() {
}
/>
-