Claude Code Notifications Not Working? Here's How to Fix It
A step-by-step troubleshooting guide for when Claude Code notifications, hooks, or alerts stop firing — from settings.json mistakes to silent shells and iOS permissions.
You set up Claude Code notifications, walked away confident, and came back to silence — the agent finished ten minutes ago and never told you. Notification problems almost always come down to one of a handful of causes. This guide walks through them in the order worth checking, from most common to most obscure.
1. Confirm the hook is actually in settings.json
The number-one cause is that the hook isn't where Claude Code looks for it. Check the file directly:
cat ~/.claude/settings.jsonYou should see a hooks block with your webhook command. Two common mistakes:
- It's in the wrong file — project-level
.claude/settings.jsonvs. global~/.claude/settings.json. If you set it globally but run in a project that overrides hooks, yours won't fire. - The JSON is malformed. A trailing comma or missing bracket makes Claude Code silently ignore the whole block. Paste it into a JSON validator.
2. Restart Claude Code after editing hooks
Hooks are read when a session starts. If you edited settings.json while a session was already running, the old config is still in memory. Exit and restart Claude Code (you can /resume your conversation afterward). This single step fixes a surprising number of "it's configured but nothing happens" reports.
3. Test the webhook command on its own
Isolate the problem: is it the hook firing, or the request failing? Run your curl command directly in the same shell Claude Code uses:
curl -v -X POST "YOUR_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"state":"needs_you","test":true}'If that doesn't produce a notification, the problem is downstream (URL, token, or the app) — not your hooks. If it does, but Claude Code still doesn't fire it, the problem is the hook config or the shell.
4. The silent-shell trap (PATH and non-interactive shells)
Hooks run in a non-interactive shell, which doesn't load your ~/.zshrc or ~/.bashrc. If your command relies on a tool that's only on your PATH because of those files, it'll work when you test it manually and fail when the hook runs it. Use absolute paths (/usr/bin/curl) and avoid depending on shell aliases or functions inside hooks.
5. You're using the wrong hook event
Different events fire at different moments. If you only hooked Stop, you won't hear about permission prompts mid-task. For full coverage you generally want:
Stop— the agent finished and is waiting on youNotification— Claude explicitly notifies you about somethingSessionStart— a new agent came online
See the complete hooks guide for the full event list and what each one carries.
6. iOS settings (if you're using a phone app)
If the webhook is firing but your phone stays quiet, the issue is on the device:
- Notifications enabled for the app in Settings → Notifications?
- Is Focus / Do Not Disturb silencing it? Allow the app through your Focus filters.
- Live Activities turned on (Settings → Face ID & Passcode → Live Activities, and per-app)?
- Token still valid? If you regenerated it, re-run setup so your hooks use the new URL.
Still stuck?
Work top to bottom — config, restart, isolate the webhook, check the shell, confirm the event, then the device. Ninety percent of cases are fixed by step two.
If you'd rather skip the manual debugging, Agentfy gives you a ready-made setup prompt that configures the hooks correctly, and a built-in "Having Issues" flow that regenerates your token and re-tests the connection. New here? Start with getting Claude Code notifications on your iPhone.
Ready to stop babysitting your terminal?
Download Agentfy