Fetch a random photo from Unsplash (optionally filtered by keyword) and display it in a Terminal Widget with --image.
Requirements
- Terminal Widget (
terminal-widgetCLI) - Free Unsplash Developers account and an application Access Key
curlandjq(brew install jq)
Demo apps are rate-limited (about 50 requests/hour). A 15-minute schedule uses 4 requests/hour per job — fine for a couple of widgets; don’t poll every minute.
1. Create an Unsplash Access Key
- Sign in (or register) at unsplash.com/developers.
- Click Your apps → New Application.
- Accept the API terms and create an app (any descriptive name is fine, e.g. “Terminal Widget”).
- Open the app and copy the Access Key (not the Secret Key).
The Secret is only needed for OAuth user login; this recipe uses the Access Key alone. - Store the key only in your local config file — never in the script or a public gist.
2. Create unsplash.env
mkdir -p ~/.config/terminal-widget
chmod 700 ~/.config/terminal-widget
Create ~/.config/terminal-widget/unsplash.env:
# Required
export UNSPLASH_ACCESS_KEY='your_access_key_here'
# Optional defaults when the script is run with no arguments
# export UNSPLASH_TARGET='unsplash'
# export UNSPLASH_QUERY='color splash' # or omit / use "-" for fully random
# export UNSPLASH_ORIENTATION='landscape' # landscape | portrait | squarish
# Optional: path to the CLI if it is not on PATH
# export TERMINAL_WIDGET='/opt/homebrew/bin/terminal-widget'
Lock it down:
chmod 600 ~/.config/terminal-widget/unsplash.env
Alternate config path: set UNSPLASH_ENV=/path/to/your.env before running the script.
3. Add a widget target
In Terminal Widget, create a target for the image. Defaults:
| Target ID | Purpose |
|---|
| unsplash | Default when no CLI args / env overrides are set |
For keyword-specific widgets, use distinct targets such as unsplash-color-splash or unsplash-ocean so each LaunchAgent can update its own widget.
4. Install and run
Save the script below as ~/bin/unsplash-random.sh (or wherever you keep widget scripts), then:
chmod +x ~/bin/unsplash-random.sh
Run once to verify:
~/bin/unsplash-random.sh
# or with an explicit target + keyword:
~/bin/unsplash-random.sh unsplash-color-splash "color splash" landscape
Add a Desktop / Notification Center widget and choose that target.
5. Schedule updates
Enable the launchd section on this recipe page (suggested interval: 15 minutes). That installs a basic agent that runs the script with no arguments, using your unsplash.env defaults.
Customize the LaunchAgent (target + keyword)
After you create the plist from the launchd section, edit ProgramArguments so the script receives target, keyword, and orientation. Example:
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/YOU/bin/unsplash-random.sh</string>
<string>unsplash-color-splash</string>
<string>color splash</string>
<string>landscape</string>
</array>
| Argument | Meaning |
|---|---|
| 1 — target | Terminal Widget target name |
| 2 — keyword | Search string, or - for fully random |
| 3 — orientation | landscape, portrait, or squarish |
Reload after editing (or use LaunchControl to edit and restart the job):
launchctl bootout "gui/$(id -u)/com.terminalwidget.unsplash-random" 2>/dev/null || true
launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/com.terminalwidget.unsplash-random.plist
(Use the Label from your plist if it differs.)
Multiple widgets with different keywords
- Duplicate the LaunchAgent plist.
- Give it a unique Label (and unique log paths).
- Change the three script arguments (target + keyword + orientation).
- Create a matching widget target in Terminal Widget.
- Bootstrap the new plist.
Example second job: target unsplash-ocean, keyword ocean, orientation landscape.
Environment variables reference
| Variable | Required | Default | Description |
|---|---|---|---|
UNSPLASH_ACCESS_KEY |
Yes | — | Access Key from your Unsplash application |
UNSPLASH_TARGET |
No | unsplash |
Widget target when arg 1 is omitted |
UNSPLASH_QUERY |
No | - (random) |
Search keyword when arg 2 is omitted |
UNSPLASH_ORIENTATION |
No | landscape |
Orientation when arg 3 is omitted |
UNSPLASH_ENV |
No | ~/.config/terminal-widget/unsplash.env |
Config file path |
TERMINAL_WIDGET |
No | terminal-widget |
Path to the CLI |
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Widget shows “UNSPLASH_ACCESS_KEY not set” | Missing or empty unsplash.env, or wrong UNSPLASH_ENV path |
| Widget shows “API request failed” / rate errors | Demo limit (50/hour); space out jobs or request a production upgrade from Unsplash |
| Image never changes | Same keyword pool is small, or LaunchAgent isn’t running — check /tmp/com.terminalwidget.…err |
terminal-widget not found under launchd |
Set TERMINAL_WIDGET=/opt/homebrew/bin/terminal-widget in unsplash.env, or add Homebrew to the plist EnvironmentVariables PATH |
| Tap does nothing | See Debugging widget taps below |
Debugging widget taps
run-command runs inside the sandboxed Terminal Widget app as /bin/zsh -lc '…'. That process:
- Uses a container
HOME(not your real home directory) - Cannot execute files under
~/Scriptsor/opt/homebrew/bin(operation not permitted) - Can write under the App Group
So a tap that runs this Unsplash script directly will fail. Prefer run-shortcut (below).
To confirm a tap is reaching the app, temporarily set:
terminal-widget --target YOUR_TARGET \
--action-kind run-command \
--action-value 'echo tapped-$(date) >>"$HOME/../../../../../Group Containers/group.brettterpstra.TerminalWidget/logs/tap-probe.log"'
(or patch the payload action to echo tapped >>"/Users/YOU/Library/Group Containers/group.brettterpstra.TerminalWidget/logs/tap-probe.log"), click the widget, then:
tail -f ~/Library/Group\ Containers/group.brettterpstra.TerminalWidget/logs/tap-probe.log
Also check the Terminal Widget menu bar app status panel for the last opened URL (terminalwidget://action?target=…).
Tap to refresh via Shortcuts (recommended)
- In Shortcuts, create Unsplash Widget Refresh with a Run Shell Script action:
/Users/YOU/Scripts/widget-unsplash.sh unsplash-color-splash "color splash" landscape
- Run it once and allow any prompts.
- Point the widget at the Shortcut instead of
run-command:
terminal-widget --target unsplash-color-splash \
--action-kind run-shortcut \
--action-value 'Unsplash Widget Refresh'
(Re-apply after each image update, or bake --action-kind run-shortcut into the script.)