How to programatically change application's notification settings?

There are some applications like WhatsApp or Telegram that don't have a fast way of disabling notifications.

I would like to know if it's possible to change notification settings programatically. In my case it would suffice to change the "Allow Notifications" toggle. I want to set a shortcut or make a script to enable/disable notifications for certain apps.

Just in case, here is a screenshot of the settings I'm talking about.

enter image description here


Solution 1:

The example AppleScript code, shown below, was tested in Script Editor under macOS Big Sur with Language & Region settings in System Preferences set to English (US) — Primary and worked for me without issue1.

  • 1 Assumes necessary and appropriate settings in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.

All you should need to do is set the value of targetApp, at the start of the script, to the name of the target application as it's shown in the Notifications pane in System Preferences.

As currently coded the script toggles the Allow Notification button of the targetApp.

The script can be use in a number of different ways to trigger it, as an AppleScript application, as an Automator Service/Quick Action, as a shell script by adding a #!/usr/bin/osascript shebang to the top of it, saving it as a plain text file and making it executable with chmod, or any third-party utility capable of running AppleScript code., etc.

Example AppleScript code:

--  # Set the value of targetApp to the name of the
--  # target application as shown in the Notifications
--  # pane in System Preferences.

set targetApp to "Script Editor"


--  # Do not modify the code below unless necessary.

property |System Preferences| : name of ¬
    application id "com.apple.systempreferences"


--  # Check to see if System Preferences is 
--  # running and if yes, then close it.
--  # 
--  # This is done so the script will not fail 
--  # if it is running and a modal sheet is 
--  # showing, hence the use of 'killall' 
--  # as 'quit' fails when done so, if it is.
--  #
--  # This is also done to allow default behaviors
--  # to be predictable from a clean occurrence.

if running of application id "com.apple.systempreferences" then
    try
        tell application id "com.apple.systempreferences" to quit
    on error
        do shell script "killall '" & |System Preferences| & "'"
    end try
    delay 0.1
end if

--  # Make sure System Preferences is not running before
--  # opening it again. Otherwise there can be an issue
--  # when trying to reopen it while it's actually closing.

repeat while running of ¬
    application id "com.apple.systempreferences" is true
    delay 0.1
end repeat

--  # Open System Preferences to the Notifications pane.

tell application id "com.apple.systempreferences"
    run -- # Used as a workaround to an issue in Big Sur.
    delay 0.1
    reveal pane id "com.apple.preference.notifications"
end tell

--  # Use System Events to achieve the goal.

tell application id "com.apple.systemevents"
    run -- # Used as a workaround to an issue in Big Sur.
    delay 0.2
    tell window 1 of application process |System Preferences|
        
        --  # Wait for target pane to be available.
        
        my waitForUIelement(row -1 of table 1 of scroll area 1)
        
        --  # Ascertain the target row to select.
        
        set rowTargetApp to the first row of table 1 of ¬
            scroll area 1 whose value of static text 1 of ¬
            group 1 of UI element 1 is targetApp
        
        --  # Select the target row.
        
        select rowTargetApp
        
        --  # Wait for target checkbox to be available.
        
        my waitForUIelement(button 1 of group 1)
        
        --  # Click Allow Notifications.
        
        click button 1 of group 1
        
    end tell
end tell

delay 0.02

quit application id "com.apple.systempreferences"


--  ## Handler ##

on waitForUIelement(uiElement)
    tell application id "com.apple.systemevents"
        tell window 1 of application process ¬
            |System Preferences|
            set i to 0
            repeat until exists uiElement
                delay 0.1
                set i to i + 1
                if i ≥ 30 then return
            end repeat
        end tell
    end tell
end waitForUIelement

Notes:

As currently coded the script just toggles the Allow Notification button of the targetApp, however, the code can be easily modified to check the state of the target button and act accordingly. As an example, if one wants to just be sure it's toggled off.

Change:

click button 1 of group 1

To:

if value of button 1 of group 1 is "on" then ¬
    click button 1 of group 1


For use in macOS Catalina:

Change:

    --  # Ascertain the target row to select.
        
set rowTargetApp to the first row of table 1 of ¬
    scroll area 1 whose value of static text 1 of ¬
    group 1 of UI element 1 is targetApp

To:

    --  # Ascertain the target row to select.
    
set rowTargetApp to first item of (rows of table 1 of ¬
    scroll area 1 whose value of static text 1 of ¬
    group 1 of UI element 1 is targetApp)


Note: The example AppleScript code is just that and sans any included error handling does not contain any additional error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.