Given a shell script that calls the macOS screencapture utility, a proper screenshot (meaning, a full capture of what is on the screen, including any application windows visible) is produced when calling that shell script from the terminal. However, using launchd to periodically call the same script does not produce the desired result, in this case the screenshot only shows an empty desktop background and a menu bar. I am running macOS 12.5 Monterey.
My desired goal is to automatically take screenshots by using launchd to call a shell script periodically. I specifically want to call a shell script or unix executable file, and do not want to use cron or any application other than launchd for scheduling purposes. My actual screenshot shell script is more involved than in the example. In the past I have been able to successfully load other daemons calling shell scripts as in the example through launchctl, but never ran into permission problems like this before.
Example
screenshot.sh
#!/bin/zsh
# save as `~/Library/bin/screenshot.sh`
# make executable by ways of the following command: `chmod +x ~/Library/bin/screenshot.sh`
screencapture -C ~/Desktop/test$( date +'%H%M%S' ).png;
Save this script in ~/Library/bin/
and make it executable by calling chmod +x
.
Note that calling running this script works fine if Terminal.app (or equivalent...) has been given screen recording permissions (see 'Permissions' below).
com.example.screenshot.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!--
save as `~/Library/LaunchAgents/com.example.screenshot.plist`
load this by ways of the following command: `sudo launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.screenshot.plist`
unloading this: `sudo launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.example.screenshot.plist`
-->
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.screenshot</string>
<!-- replace <<USERNAME>> with the actual username -->
<key>Program</key>
<string>/Users/<<USERNAME>>/Library/bin/screenshot.sh</string>
<key>StartInterval</key>
<integer>10</integer>
<key>ProcessType</key>
<string>Background</string>
<key>StandardErrorPath</key>
<string>/tmp/launchd.example.screenshot_stderr.log</string>
<key>StandardOutPath</key>
<string>/tmp/launchd.example.screenshot_stdout.log</string>
</dict>
</plist>
First, make sure that under <key>Program</key>
<USERNAME> is set to your actual username, or that the path to the screenshot.sh file is absolute. Save this .plist in ~/Library/LaunchAgents/
and load by calling sudo launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.screenshot.plist
. Unloading works by changing the subcommand to bootout. The launchctl manpage can be found here.
Permissions
Screen recording permissions can be given to applications in System Preferences → Security & Privacy → Privacy → Screen Recording → '+'. Adding Terminal.app to this list, and restarting the application gives proper screenshots when calling screenshot.sh directly from the terminal. I have tried adding /bin/launchd, /bin/launchctl, /usr/sbin/screencapture, Terminal.app, and the screenshot script (saved without the .sh suffix) to the list of allowed apps and then rebooting, but I am still not able to produce proper screenshots through launchd.
Question in short
For the set-up given above, what settings do I change or permissions do I give such that I get proper screenshots that show open applications?
Questions pertaining to the same problem have been asked here and here, but the answers aren't satisfactory (don't work or don't use launchd).