How to Get Powder Day Alerts on Your Mac

Updated August 2026

The morning routine is always the same. Wake up, open the resort’s snow report, refresh, check the webcam, refresh again. Some mornings it pays off. Most mornings it’s four minutes you spent finding out that nothing happened.

The problem with this ritual isn’t the four minutes — it’s that it fails exactly when it matters. The surprise overnight dump is the one you sleep through, and by the time a friend texts, the fresh tracks are gone. What you want is the inverse: silence on normal days, and a shove on the good ones.

Here’s how to build that on a Mac, free, and where the free version stops being enough.

What a useful alert actually needs

Three things, and most tools give you only the first:

  1. A threshold. “It snowed” is not information. “It snowed more than 15 cm at the elevation I ski” is. Without a threshold you get notified about every dusting and start ignoring the alerts within a week.
  2. A check time you choose. A powder alert that arrives at 11 a.m. is a notification, not an alert. It needs to land before you decide what your day looks like.
  3. The right coordinates. Resort base areas are often 600+ metres below where you’ll actually be. A base-area number systematically understates a storm.

The free DIY route

You can build a real powder alert with tools already on your Mac. Three pieces: a weather API, a shell script, and launchd to run it on a schedule.

The data

Open-Meteo serves forecast data with no API key and no account. The snowfall endpoint looks like this:

curl -s "https://api.open-meteo.com/v1/forecast?latitude=40.5883&longitude=-111.6372&daily=snowfall_sum&timezone=auto&forecast_days=1"

Those coordinates are Alta, Utah. Swap in your own — grab them by right-clicking a spot in Apple Maps and choosing to copy the coordinates. The response is JSON with a daily.snowfall_sum array, in centimetres.

The script

Save this as ~/bin/powdercheck.sh and chmod +x it:

#!/bin/zsh
LAT=40.5883
LON=-111.6372
THRESHOLD_CM=15
NAME="Alta"

snow=$(curl -fsS "https://api.open-meteo.com/v1/forecast?latitude=$LAT&longitude=$LON&daily=snowfall_sum&timezone=auto&forecast_days=1" \
  | /usr/bin/jq -r '.daily.snowfall_sum[0] // 0')

if (( $(printf '%.0f' "$snow") >= THRESHOLD_CM )); then
  osascript -e "display notification \"${snow}cm forecast today\" with title \"Powder day: $NAME\" sound name \"Glass\""
fi

curl -fsS fails loudly on an HTTP error instead of feeding you an error page, and the // 0 in the jq filter means a missing value becomes zero rather than the string null. On recent macOS versions jq ships at /usr/bin/jq; if it isn’t there, brew install jq.

The schedule

launchd runs it every morning. Save this as ~/Library/LaunchAgents/local.powdercheck.plist, replacing YOURNAME:

<?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">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>local.powdercheck</string>
  <key>ProgramArguments</key>
  <array>
    <string>/bin/zsh</string>
    <string>/Users/YOURNAME/bin/powdercheck.sh</string>
  </array>
  <key>StartCalendarInterval</key>
  <dict>
    <key>Hour</key><integer>6</integer>
    <key>Minute</key><integer>0</integer>
  </dict>
  <key>StandardErrorPath</key>
  <string>/tmp/powdercheck.err</string>
</dict>
</plist>

Load it:

launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/local.powdercheck.plist

Test it immediately rather than waiting until tomorrow:

launchctl kickstart -p gui/$(id -u)/local.powdercheck
cat /tmp/powdercheck.err     # empty is good

That’s a working powder alert for free. If a shell script and a plist are your idea of a good time, you can stop reading here — this genuinely does the job.

Where the DIY version runs out

Having built roughly this before building an app, here’s honestly where it breaks down.

It only knows about tomorrow. One number, one day. It can’t tell you a storm cycle is building — that four of the next five days show snow, which is the pattern actually worth requesting a day off for. Getting that from the raw API means fetching a multi-day array and writing the logic yourself.

Sleep is a problem. StartCalendarInterval fires when the Mac is awake. If your Mac was asleep at 6 a.m., launchd runs the job when it wakes — which may be at your desk at 9, after the decision point. Handling this properly means thinking about wake schedules.

One location per script. Multiple resorts means multiple scripts and multiple plists, or a real loop and a config file. It grows.

No history. A number with no yesterday is hard to read. Was that 20 cm on top of a solid base or on top of rocks?

Centimetres and no elevation nuance. You’ll be converting units in your head, and the single coordinate you picked represents one point on a mountain.

Every one of these is solvable with more code. At some point you’re writing an app.

Or let something else watch

That’s the app I ended up building — Powder Alert — so weigh this section knowing it’s mine.

It lives in the menu bar and does the parts above that are tedious to hand-roll: a threshold you set from 1 to 24 inches (or centimetres), a daily check time, and alerts that catch up after your Mac wakes rather than silently missing the window. It watches 165+ resorts across 16 countries, or any coordinates you drop a pin on. Beyond the single-day alert it flags storm cycles when three or more of the next five days show snow, and gives an advance warning days ahead — which is the one that lets you arrange coverage at work before everyone else notices.

Same data source as the DIY version above, incidentally: Open-Meteo, no account, nothing leaving your Mac but the forecast request.

It’s $4.99 on the Mac App Store. The free script is a completely reasonable alternative if you want one resort and one number.

The part worth taking away

Whichever route you pick, set a threshold and a check time and then stop checking manually. The value isn’t the notification — it’s deleting the morning ritual. If you find yourself opening the snow report anyway, the alert isn’t tuned right yet, and the fix is usually to raise the threshold until an alert genuinely means something.