diff --git a/external/lang b/external/lang
index 099fb74131c60955e8226ce0a290cb22e959d7d6..9cc46c3a4abab74e17e56597db10e2c16ac0f9b5 160000
--- a/external/lang
+++ b/external/lang
@@ -1 +1 @@
-Subproject commit 099fb74131c60955e8226ce0a290cb22e959d7d6
+Subproject commit 9cc46c3a4abab74e17e56597db10e2c16ac0f9b5
diff --git a/src/context/intermediate/Intermediate.tsx b/src/context/intermediate/Intermediate.tsx
index 12f0e442a014020699acbfef644ef1cdfb4325cd..e96a72a3b8671c35e41d459b0418592fdd747aac 100644
--- a/src/context/intermediate/Intermediate.tsx
+++ b/src/context/intermediate/Intermediate.tsx
@@ -116,7 +116,7 @@ export default function Intermediate(props: Props) {
                         screen.id
                     } /** By specifying a key, we reset state whenever switching screen. */
                 />
-                {/*<Prompt
+                <Prompt
                     when={[ 'modify_account', 'special_prompt', 'special_input', 'image_viewer', 'profile', 'channel_info', 'user_picker' ].includes(screen.id)}
                     message={(_, action) => {
                         if (action === 'POP') {
@@ -128,7 +128,7 @@ export default function Intermediate(props: Props) {
 
                         return true;
                     }}
-                />*/}
+                />
             </IntermediateActionsContext.Provider>
         </IntermediateContext.Provider>
     );
diff --git a/src/context/revoltjs/Notifications.tsx b/src/context/revoltjs/Notifications.tsx
index 51f610b8366858646cc4ca7654880d02150b4748..d9f4f1f9aba804f3d955297330a5e5ffd41ed2e4 100644
--- a/src/context/revoltjs/Notifications.tsx
+++ b/src/context/revoltjs/Notifications.tsx
@@ -8,9 +8,11 @@ import { connectState } from "../../redux/connector";
 import { Message, SYSTEM_USER_ID, User } from "revolt.js";
 import { NotificationOptions } from "../../redux/reducers/settings";
 import { Route, Switch, useHistory, useParams } from "react-router-dom";
+import { getNotificationState, Notifications } from "../../redux/reducers/notifications";
 
 interface Props {
     options?: NotificationOptions;
+    notifs: Notifications;
 }
 
 const notifications: { [key: string]: Notification } = {};
@@ -24,9 +26,9 @@ async function createNotification(title: string, options: globalThis.Notificatio
     }
 }
 
-function Notifier(props: Props) {
+function Notifier({ options, notifs }: Props) {
     const translate = useTranslation();
-    const showNotification = props.options?.desktopEnabled ?? false;
+    const showNotification = options?.desktopEnabled ?? false;
 
     const client = useContext(AppContext);
     const { guild: guild_id, channel: channel_id } = useParams<{
@@ -39,17 +41,27 @@ function Notifier(props: Props) {
     async function message(msg: Message) {
         if (msg.author === client.user!._id) return;
         if (msg.channel === channel_id && document.hasFocus()) return;
-        if (client.user?.status?.presence === Users.Presence.Busy) return;
-
-        playSound('message');
-        if (!showNotification) return;
+        if (client.user!.status?.presence === Users.Presence.Busy) return;
 
         const channel = client.channels.get(msg.channel);
         const author = client.users.get(msg.author);
+        if (!channel) return;
         if (author?.relationship === Users.Relationship.Blocked) return;
 
+        const notifState = getNotificationState(notifs, channel);
+        switch (notifState) {
+            case 'muted':
+            case 'none': return;
+            case 'mention': {
+                if (!msg.mentions?.includes(client.user!._id)) return;
+            }
+        }
+
+        playSound('message');
+        if (!showNotification) return;
+
         let title;
-        switch (channel?.channel_type) {
+        switch (channel.channel_type) {
             case "SavedMessages":
                 return;
             case "DirectMessage":
@@ -192,7 +204,7 @@ function Notifier(props: Props) {
             client.removeListener("message", message);
             client.users.removeListener("mutation", relationship);
         };
-    }, [client, playSound, guild_id, channel_id, showNotification]);
+    }, [client, playSound, guild_id, channel_id, showNotification, notifs]);
 
     useEffect(() => {
         function visChange() {
@@ -217,7 +229,8 @@ const NotifierComponent = connectState(
     Notifier,
     state => {
         return {
-            options: state.settings.notification
+            options: state.settings.notification,
+            notifs: state.notifications
         };
     },
     true
diff --git a/src/context/revoltjs/SyncManager.tsx b/src/context/revoltjs/SyncManager.tsx
index 95361cc5e5439218c9886878f33bc98ac54c8874..d3fd7ca7a1ecb1b3c7d91926403636840e0d6544 100644
--- a/src/context/revoltjs/SyncManager.tsx
+++ b/src/context/revoltjs/SyncManager.tsx
@@ -9,6 +9,7 @@ import { useContext, useEffect } from "preact/hooks";
 import { connectState } from "../../redux/connector";
 import { WithDispatcher } from "../../redux/reducers";
 import { Settings } from "../../redux/reducers/settings";
+import { Notifications } from "../../redux/reducers/notifications";
 import { AppContext, ClientStatus, StatusContext } from "./RevoltClient";
 import { ClientboundNotification } from "revolt.js/dist/websocket/notifications";
 import { DEFAULT_ENABLED_SYNC, SyncData, SyncKeys, SyncOptions } from "../../redux/reducers/sync";
@@ -16,7 +17,8 @@ import { DEFAULT_ENABLED_SYNC, SyncData, SyncKeys, SyncOptions } from "../../red
 type Props = WithDispatcher & {
     settings: Settings,
     locale: Language,
-    sync: SyncOptions
+    sync: SyncOptions,
+    notifications: Notifications
 };
 
 var lastValues: { [key in SyncKeys]?: any } = { };
@@ -78,7 +80,7 @@ function SyncManager(props: Props) {
     }
 
     let disabled = props.sync.disabled ?? [];
-    for (let [key, object] of [ ['appearance', props.settings.appearance], ['theme', props.settings.theme], ['locale', props.locale] ] as [SyncKeys, any][]) {
+    for (let [key, object] of [ ['appearance', props.settings.appearance], ['theme', props.settings.theme], ['locale', props.locale], ['notifications', props.notifications] ] as [SyncKeys, any][]) {
         useEffect(() => {
             if (disabled.indexOf(key) === -1) {
                 if (typeof lastValues[key] !== 'undefined') {
@@ -117,7 +119,8 @@ export default connectState(
         return {
             settings: state.settings,
             locale: state.locale,
-            sync: state.sync
+            sync: state.sync,
+            notifications: state.notifications
         };
     },
     true
diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx
index 89bdf8f49b38b678625b6b1bc320639f11f64610..875e9a4403d490d7034022f871b331a73f6994ff 100644
--- a/src/lib/ContextMenus.tsx
+++ b/src/lib/ContextMenus.tsx
@@ -5,7 +5,8 @@ import { Attachment, Channels, Message, Servers, Users } from "revolt.js/dist/ap
 import {
     ContextMenu,
     ContextMenuWithData,
-    MenuItem
+    MenuItem,
+    openContextMenu
 } from "preact-context-menu";
 import { ChannelPermission, ServerPermission, UserPermission } from "revolt.js/dist/api/permissions";
 import { QueuedMessage } from "../redux/reducers/queue";
@@ -18,6 +19,9 @@ import { Children } from "../types/Preact";
 import LineDivider from "../components/ui/LineDivider";
 import { connectState } from "../redux/connector";
 import { internalEmit } from "./eventEmitter";
+import { AtSign, Bell, BellOff, Check, CheckSquare, ChevronRight, Slash, Square } from "@styled-icons/feather";
+import { getNotificationState, Notifications, NotificationState } from "../redux/reducers/notifications";
+import { ArrowLeft } from "@styled-icons/bootstrap";
 
 interface ContextMenuData {
     user?: string;
@@ -68,11 +72,17 @@ type Action =
     | { action: "close_dm"; target: Channels.DirectMessageChannel }
     | { action: "leave_server"; target: Servers.Server }
     | { action: "delete_server"; target: Servers.Server }
+    | { action: "open_notification_options", channel: Channels.Channel }
     | { action: "open_channel_settings", id: string }
     | { action: "open_server_settings", id: string }
-    | { action: "open_server_channel_settings", server: string, id: string };
+    | { action: "open_server_channel_settings", server: string, id: string }
+    | { action: "set_notification_state", key: string, state?: NotificationState };
 
-function ContextMenus(props: WithDispatcher) {
+type Props = WithDispatcher & {
+    notifications: Notifications
+};
+
+function ContextMenus(props: Props) {
     const { openScreen, writeClipboard } = useIntermediate();
     const client = useContext(AppContext);
     const userId = client.user!._id;
@@ -301,9 +311,24 @@ function ContextMenus(props: WithDispatcher) {
                 case "ban_member":
                 case "kick_member": openScreen({ id: "special_prompt", type: data.action, target: data.target, user: data.user }); break;
 
+                case "open_notification_options": {
+                    openContextMenu("NotificationOptions", { channel: data.channel });
+                    break;
+                }
+
                 case "open_channel_settings": history.push(`/channel/${data.id}/settings`); break;
                 case "open_server_channel_settings": history.push(`/server/${data.server}/channel/${data.id}/settings`); break;
                 case "open_server_settings": history.push(`/server/${data.id}/settings`); break;
+
+                case "set_notification_state": {
+                    const { key, state } = data;
+                    if (state) {
+                        props.dispatcher({ type: "NOTIFICATIONS_SET", key, state });
+                    } else {
+                        props.dispatcher({ type: "NOTIFICATIONS_REMOVE", key });
+                    }
+                    break;
+                }
             }
         })().catch(err => {
             openScreen({ id: "error", error: takeError(err) });
@@ -567,6 +592,10 @@ function ContextMenus(props: WithDispatcher) {
                         pushDivider();
 
                         if (channel) {
+                            if (channel.channel_type !== 'VoiceChannel') {
+                                generateAction({ action: "open_notification_options", channel }, undefined, undefined, <ChevronRight size={24} />);
+                            }
+
                             switch (channel.channel_type) {
                                 case 'Group':
                                     // ! generateAction({ action: "create_invite", target: channel }); FIXME: add support for group invites
@@ -669,14 +698,50 @@ function ContextMenus(props: WithDispatcher) {
                     </MenuItem>
                 )}
             </ContextMenu>
+            <ContextMenuWithData id="NotificationOptions" onClose={contextClick}>
+                {({ channel }: { channel: Channels.Channel }) => {
+                    const state = props.notifications[channel._id];
+                    const actual = getNotificationState(props.notifications, channel);
+
+                    let elements: Children[] = [
+                        <MenuItem data={{ action: "set_notification_state", key: channel._id }}>
+                            <Text id={`app.main.channel.notifications.default`} />
+                            <div className="tip">
+                                { (state !== undefined) && <Square size={20} /> }
+                                { (state === undefined) && <CheckSquare size={20} /> }
+                            </div>
+                        </MenuItem>
+                    ];
+
+                    function generate(key: string, icon: Children) {
+                        elements.push(
+                            <MenuItem data={{ action: "set_notification_state", key: channel._id, state: key }}>
+                                { icon }
+                                <Text id={`app.main.channel.notifications.${key}`} />
+                                { (state === undefined && actual === key) && <div className="tip"><ArrowLeft size={20} /></div> }
+                                { (state === key) && <div className="tip"><Check size={20} /></div> }
+                            </MenuItem>
+                        );
+                    }
+
+                    generate('all', <Bell size={24} />);
+                    generate('mention', <AtSign size={24} />);
+                    generate('muted', <BellOff size={24} />);
+                    generate('none', <Slash size={24} />);
+
+                    return elements;
+                }}
+            </ContextMenuWithData>
         </>
     );
 }
 
 export default connectState(
     ContextMenus,
-    () => {
-        return {};
+    state => {
+        return {
+            notifications: state.notifications
+        };
     },
     true
 );
diff --git a/src/pages/settings/panes/Sync.tsx b/src/pages/settings/panes/Sync.tsx
index e563128695373e5e4a698ae2a73e24903b6d622e..ad7c84f82ba327c07bcc2845798da099b4e9a647 100644
--- a/src/pages/settings/panes/Sync.tsx
+++ b/src/pages/settings/panes/Sync.tsx
@@ -20,6 +20,7 @@ export function Component(props: Props & WithDispatcher) {
                     ['appearance', 'appearance.title'],
                     ['theme', 'appearance.theme'],
                     ['locale', 'language.title']
+                    // notifications sync is always-on
                 ] as [ SyncKeys, string ][]).map(
                     ([ key, title ]) =>
                         <Checkbox
diff --git a/src/redux/index.ts b/src/redux/index.ts
index 33e6bbdca61960d7406ecfa865594b954db4cdb3..dc90bec03a461bd90ec4a8730cc41942684a02c6 100644
--- a/src/redux/index.ts
+++ b/src/redux/index.ts
@@ -13,6 +13,7 @@ import { Settings } from "./reducers/settings";
 import { QueuedMessage } from "./reducers/queue";
 import { ExperimentOptions } from "./reducers/experiments";
 import { LastOpened } from "./reducers/last_opened";
+import { Notifications } from "./reducers/notifications";
 
 export type State = {
     config: Core.RevoltNodeConfiguration,
@@ -26,6 +27,7 @@ export type State = {
     sync: SyncOptions;
     experiments: ExperimentOptions;
     lastOpened: LastOpened;
+    notifications: Notifications;
 };
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -53,7 +55,8 @@ store.subscribe(() => {
         drafts,
         sync,
         experiments,
-        lastOpened
+        lastOpened,
+        notifications
     } = store.getState() as State;
 
     localForage.setItem("state", {
@@ -66,6 +69,7 @@ store.subscribe(() => {
         drafts,
         sync,
         experiments,
-        lastOpened
+        lastOpened,
+        notifications
     });
 });
diff --git a/src/redux/reducers/index.ts b/src/redux/reducers/index.ts
index 6c84f87fa76e405ad008e322275bc2e2bbecb620..fe47ccbdc3de006eed1f954b21004518c5e7516c 100644
--- a/src/redux/reducers/index.ts
+++ b/src/redux/reducers/index.ts
@@ -12,6 +12,7 @@ import { drafts, DraftAction } from "./drafts";
 import { sync, SyncAction } from "./sync";
 import { experiments, ExperimentsAction } from "./experiments";
 import { lastOpened, LastOpenedAction } from "./last_opened";
+import { notifications, NotificationsAction } from "./notifications";
 
 export default combineReducers({
     config,
@@ -24,7 +25,8 @@ export default combineReducers({
     drafts,
     sync,
     experiments,
-    lastOpened
+    lastOpened,
+    notifications
 });
 
 export type Action =
@@ -39,6 +41,7 @@ export type Action =
     | SyncAction
     | ExperimentsAction
     | LastOpenedAction
+    | NotificationsAction
     | { type: "__INIT"; state: State };
 
 export type WithDispatcher = { dispatcher: (action: Action) => void };
diff --git a/src/redux/reducers/notifications.ts b/src/redux/reducers/notifications.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2ca5b030ca9e9ab6355c1da5bd2a62c5c926d4d2
--- /dev/null
+++ b/src/redux/reducers/notifications.ts
@@ -0,0 +1,56 @@
+import { Channel } from "revolt.js";
+
+export type NotificationState = 'all' | 'mention' | 'none' | 'muted';
+
+export type Notifications = {
+    [key: string]: NotificationState
+}
+
+export const DEFAULT_STATES: { [key in Channel['channel_type']]: NotificationState } = {
+    'SavedMessages': 'all',
+    'DirectMessage': 'all',
+    'Group': 'all',
+    'TextChannel': 'mention',
+    'VoiceChannel': 'mention'
+};
+
+export function getNotificationState(notifications: Notifications, channel: Channel) {
+    return notifications[channel._id] ?? DEFAULT_STATES[channel.channel_type];
+}
+
+export type NotificationsAction =
+    | { type: undefined }
+    | {
+        type: "NOTIFICATIONS_SET";
+        key: string;
+        state: NotificationState;
+      }
+    | {
+        type: "NOTIFICATIONS_REMOVE";
+        key: string;
+      }
+    | {
+        type: "RESET";
+      };
+
+export function notifications(
+    state = {} as Notifications,
+    action: NotificationsAction
+): Notifications {
+    switch (action.type) {
+        case "NOTIFICATIONS_SET":
+            return {
+                ...state,
+                [action.key]: action.state
+            };
+        case "NOTIFICATIONS_REMOVE":
+            {
+                const { [action.key]: _, ...newState } = state;
+                return newState;
+            }
+        case "RESET":
+            return {};
+        default:
+            return state;
+    }
+}
diff --git a/src/redux/reducers/sync.ts b/src/redux/reducers/sync.ts
index 1e2d4a3196d127da3a307639a401124cdce037ca..0e2c8111bac0900819a98bcdbae8e3dd87a7dc72 100644
--- a/src/redux/reducers/sync.ts
+++ b/src/redux/reducers/sync.ts
@@ -1,19 +1,22 @@
 import { AppearanceOptions } from "./settings";
 import { Language } from "../../context/Locale";
 import { ThemeOptions } from "../../context/Theme";
+import { Notifications } from "./notifications";
 
-export type SyncKeys = "theme" | "appearance" | "locale";
+export type SyncKeys = "theme" | "appearance" | "locale" | "notifications";
 
 export interface SyncData {
     locale?: Language;
     theme?: ThemeOptions;
     appearance?: AppearanceOptions;
+    notifications?: Notifications;
 }
 
 export const DEFAULT_ENABLED_SYNC: SyncKeys[] = [
     "theme",
     "appearance",
     "locale",
+    "notifications"
 ];
 export interface SyncOptions {
     disabled?: SyncKeys[];