76

I'd like to be able to dismiss and open macOS Notification Center notifications with the keyboard.

(I'm not talking about opening/closing the Notification Center itself.)

Is this possible in some manner with a tool or setting or other software?

0

9 Answers 9

10

Here is a simplified JXA script which is confirmed working on macOS Ventura, Sonoma, and Sequoia (tested against 15.2+ only):

// Modified from
// https://gist.github.com/lancethomps/a5ac103f334b171f70ce2ff983220b4f
"use strict";

function run() {
  const CurrentApplication = (() => {
    const app = Application.currentApplication();
    app.includeStandardAdditions = true;
    return app;
  })();
  const SystemEvents = Application("System Events");
  const NotificationCenter =
    SystemEvents.processes.byName("NotificationCenter");
  const macOSSequoiaOrGreater =
    parseFloat(CurrentApplication.systemInfo().systemVersion) >= 15.0;
  const notificationGroups = () => {
    const windows = NotificationCenter.windows;
    if (windows.length === 0) {
      return [];
    }

    return macOSSequoiaOrGreater
      ? windows // "Clear all" heirarchy
          .at(0)
          .groups.at(0)
          .groups.at(0)
          .scrollAreas.at(0)
          .groups()
          .at(0)
          .uiElements()
          .concat(
            windows // "Close" heirarchy
              .at(0)
              .groups.at(0)
              .groups.at(0)
              .scrollAreas.at(0)
              .groups()
          )
      : windows.at(0).groups.at(0).scrollAreas.at(0).uiElements.at(0).groups();
  };

  const findCloseAction = group => {
    const [closeAllAction, closeAction] = group.actions().reduce(
      (matches, action) => {
        switch (action.description()) {
          case "Clear All":
            return [action, matches[1]];
          case "Close":
            return [matches[0], action];
          default:
            return matches;
        }
      },
      [null, null]
    );
    return closeAllAction ?? closeAction;
  };

  const actions = notificationGroups().map(findCloseAction);
  for (const action of actions) {
    action?.perform();
  }
}

It can be run via Automator as shown in @markhunt's answer or with Hammerspoon like this:

-- Close all visible notifications in Notification Center.
hs.hotkey.bind({"ctrl", "cmd"}, "delete", function()
  hs.task
    .new("/usr/bin/osascript", nil, {
      "-l",
      "JavaScript",
      os.getenv("HOME") .. "/.config/hammerspoon/jxa/close_notifications.js",
    })
    :start()
end)

Note: hs.task is preferred over hs.osascript due to Memory leak in hs.osascript.

4
  • This works on macOS 14.3.1. Commented Feb 19, 2024 at 14:33
  • This version works in Sequoia, thanks for updating it. Commented Oct 9, 2024 at 9:37
  • On Sqeuoia 15.3.2, it requires the notification window to be open, and it only clears the last (group of) notification(s). Commented Mar 19 at 17:07
  • 1
    Thank you. I have added using Shortcuts, and am triggering using Raycast. Works! Commented Mar 25 at 11:26
42

You can create an Automator service to run this Applescript and give it a keyboard shortcut in the System Preferences Keyboard shortcuts

This will close alert and banner notifications.


In Automator choose a new service

enter image description here


Add a Run Applescript Action

enter image description here

and replace its code with:

my closeNotif()
on closeNotif()
    
    tell application "System Events"
        tell process "Notification Center"
            set theWindows to every window
            repeat with i from 1 to number of items in theWindows
                set this_item to item i of theWindows
                try
                    click button 1 of this_item
                on error
                    
                    my closeNotif()
                end try
            end repeat
        end tell
    end tell
    
end closeNotif

Set the 'Service receives [no input] in [any application]'

Save the service.


Open the Keyboard shortcuts in System prefs and set your shortcut for your service under 'Services'

enter image description here

Now any newly launched app will pick the shortcut up.

(Note: I structured the script to counter throwing an error that will occur when the notifications/windows start to close.

Notifications/window are numbered 1 through to the total count. But as they close the script would still be working off the old count. But the system will be reassigning the index of the windows.

So where we say start at 1 -6 the script will try and close window 1, window 2, window 3 and so on. But the system has reassigned the window numbers 1,2,3 to the last remaining windows. But the script will try and close window 4 and throw an error because it does not exist. The script will catch this and deal with it.)


If you want to click the 'Show' button on an Alert Notification, change the button you click from 1 to 2.

click button 2 of this_item

Banner notifications do not have a button 2. But you can just click the window.

So this code should take care of showing.

my closeNotif()
on closeNotif()
    
    tell application "System Events"
        tell process "Notification Center"
            set theWindows to every window
            repeat with i from 1 to number of items in theWindows
                set this_item to item i of theWindows
                set cnt to count buttons of this_item
                try
                    if cnt > 1 then
                        
                        click button 2 of this_item
                    else
                        click this_item
                    end if
                on error
                    
                    closeNotif()
                end try
            end repeat
        end tell
    end tell
    
end closeNotif
1
  • 12
    This no longer works in Big Sur, but I found an updated script which works. Commented Jan 8, 2021 at 1:55
13

Not quite what you asking for:

You could limit the time displayed for banners type with

Terminal and paste in the following

defaults write com.apple.notificationcenterui bannerTime #

with the # number sign replaced with the amount of seconds you want banner notifications to stick around, then log off and back on.

To restore original function (5 seconds) use defaults delete com.apple.notificationcenterui bannerTime

I know you said no: but you could cycle the Notification on/off with a script and assign a keyboard short cut to it. Temporarily disable Notification Center in Mountain Lion from command line?

3
  • Thanks for posting; the time limit is also worth noting here :) Commented Nov 12, 2014 at 21:43
  • Does this work in High Sierra? I couldn't get it to have any effect. Commented Sep 17, 2018 at 14:57
  • No longer works, so what I've done instead is: (a) change important notifications to Alerts instead of Banners, and (b) use a script or Alfred Worfklow to dismiss-all-notifications. For a script, see @Gavin's answer, for an Alfred Workflow see here (github) Commented Aug 31, 2022 at 19:14
7

The previously accepted answer does not work in Big Sur. This script does work.

2
  • Thanks to @RussellZ who posted the script link in his comment above. Commented Feb 13, 2021 at 4:13
  • If you want to run this from an Alfred Workflow, it's easy to do so — see this comment Commented Aug 31, 2022 at 19:15
2

Closing all notification (alert/banner)

Similar to the answer by markhunte in that a bit of AppleScript is used, but the implementation is vastly improved.

Namely, unlike the script by markhunte, closes also banner notifications, doesn't crash when a notification doesn't have a close button, works even when notification center is open, works with notifications where the close button isn't the first button, detects stuck notifications, and so on...

Using an Alfred workflow

If you use Alfred, you have this workflow available: Notification dismisser. It will close all the currently displayed notifications with a shortcut or Alfred keyword. Super simple to use and works as expected.

Without using Alfred

If you don't use Alfred, you can take the main script from the workflow and (same as the answer by markhunte) using Automator save it as a "Quick Action". Then set a keyboard shortcut for it in System Preferences. Does the same as the workflow, albeit requires a bit more effort than clicking "install" as with Alfred.

1

An indirect approach is in System Preferences > Notifications, to set the alert style to Banners. The alerts will show briefly and then dismiss themselves. To see the alerts again using the keyboard, press Fn-N to show the Notification Center.

(If using a keyboard without a Fn key, you can assign a shortcut from System Preferences > Keyboard > Shortcuts > Mission Control > Show Notification Center.)

1

The original script by markhunte works but stops after a few windows. It may be that the list of windows only includes the ones that are currently visible. When you have too many this won't close all. I added a loop outside the main loop to query the windows until we get a window count of zero. Here is the code:

my closeNotif()
on closeNotif()
    
    tell application "System Events"
        tell process "Notification Center"
            set theWindows to every window
            set nWindows to number of items in theWindows
            repeat until nWindows is 0
                repeat with i from 1 to number of items in theWindows
                    set this_item to item i of theWindows
                    try
                        click button 1 of this_item
                        delay 0.2
                    on error
                        
                        my closeNotif()
                    end try
                end repeat
                set theWindows to every window
                set nWindows to number of items in theWindows
            end repeat
        end tell
    end tell
    
end closeNotif
1

Here's what worked for me (Big Sur). It's faster, more reliable, and more responsive than the accepted answer.

1. Create a clear_notifications script

You can do that by running this script from your terminal

write_target=~/bin/clear_notifications
mkdir ~/bin
cat << EOF > $write_target
#!/usr/bin/osascript

# Usage: clear_notifications [partial_title]
#
# Clears notifications from the notification center if they contain the string in [partial_title].
# If no arg is passed in, all notifications are cleared.

on run argv
  tell application "System Events"
     try
       set _groups to groups of UI element 1 of scroll area 1 of group 1 of window "Notification Center" of application process "NotificationCenter"
      repeat with _group in _groups
        set temp to value of static text 1 of _group
          set _actions to actions of _group # Get all the actions within this group
          set isInScope to true

          if (count of argv) > 0 then
            set searchTerm to item 1 of argv
            if temp does not contain searchTerm then
              log "Didn't find any notifications matching " & searchTerm
              set isInScope to false
            end if
          end if

          if isInScope then
            if exists (first action of _group where description is "Clear All") then
              log "Found 'clear all' for " & temp
              perform (first action of _group where description is "Clear All")
            else if exists (first action of _group where description is "Close") then
              log "Found close for " & temp
              perform (first action of _group where description is "Close")
            else
              log "Didn't find close action for " & temp
            end if
          end if

      end repeat
    on error errMsg
        log "Error: " & errMsg
    end try
  end tell
end run
EOF
chmod u+x $write_target

2. Connect the script to a keyboard shortcut.

You can do this using the keyboard shortcut instructions from the accepted answer (similar instructions here), but I find automator clunky and cumbersome for such a simple task. I much prefer using Better Touch Tool.

  • Go to Better Touch Tool configuration
  • In the left panel, select "All Apps"
  • Add a new keyboard shortcut of your choice and choose Execute Terminal Command (Async, non-blocking) as the trigger.
  • Enter ~/bin/clear_notifications into the textbox where it says Enter Terminal Command

better touch tool add shortcut

1

Here's an Applescript solution that works in Sequoia. It relies on there being a "clear all" button, which only appears if there's more than one notification on the screen. So, if there's only one, it sends a second one and then clears them both!

Credit to fortred2 for the original "clear all" version.

tell application "System Events"
    tell process "NotificationCenter"
        try
            -- First check if Notification Center window exists
            if exists window "Notification Center" then
                -- Then check if there are any notification elements
                if exists scroll area 1 of group 1 of group 1 of window "Notification Center" then
                    -- Check if there are any notification elements inside
                    set notificationElements to UI elements of scroll area 1 of group 1 of group 1 of window "Notification Center"
                    if (count of notificationElements) > 0 then
                        -- Notifications exist, proceed with your original code
                        display notification "..." with title "clearing..." subtitle "hiii"
                        delay 0.25
                        perform (actions of UI elements of UI element 1 of scroll area 1 of group 1 of group 1 of window "Notification Center" whose name starts with "Name:Close" or name starts with "Name:Clear All")
                    else
                        -- No notifications, skip
                        log "No notifications found."
                    end if
                end if
            else
                log "Notification Center not open or no notifications."
            end if
        on error errMsg
            log "Error checking notifications: " & errMsg
        end try
    end tell
end tell

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.