claude-code-notifier
how it works guides faq
◐English
English العربية Deutsch Español Français עברית Italiano 日本語 한국어 Nederlands Polski Português (Brasil) Русский Türkçe Tiếng Việt 简体中文 繁體中文
Get started
All guides

The Claude Code Notification hook: when it fires and how to use it

Updated 31 October 2026 · 6 min read
on this page 01The notification types 02The timing rules 03What the hook receives 04What the hook can and can't do 05Examples 06Where Claude Code Notifier fits 07FAQ

The Claude Code Notification hook runs whenever Claude Code sends a notification, most often because a permission prompt is waiting (permission_prompt) or because Claude finished and you haven't replied (idle_prompt). It is timed for when you seem to be away: permission_prompt fires once the prompt has waited about six seconds without a keystroke, and idle_prompt about 60 seconds after Claude finished. The hook gets the notification text as JSON, cannot block anything, and is meant for side effects such as a desktop alert or a push to your phone.

01The notification types

The matcher on a Notification hook is the notification type. Leave it empty to run on all of them, or list the ones you want with |. The types you are most likely to use:

MatcherWhen it fires
permission_promptClaude needs you to approve a tool use (or a sandboxed command's network request) and the prompt has waited about six seconds
idle_promptClaude finished responding about 60 seconds ago and you haven't typed since
elicitation_dialogAn MCP server opened a form and you haven't typed for about six seconds
elicitation_url_dialogAn MCP server asked you to open a URL and you haven't typed for about six seconds
auth_successAuthentication completed

There are more, such as agent_needs_input and agent_completed for background sessions in agent view, and a set of quota_auto_resume_* types for usage-limit waits. The hooks reference has the full, current list.

02The timing rules

This is the part that catches people out. The Notification hook shares its timing with Claude Code's own desktop notifications, so in a terminal session it only fires when you look away:

  • permission_prompt starts a timer of about six seconds when the prompt appears. Every keystroke resets it. If you answer quickly, it never fires.
  • idle_prompt fires about 60 seconds after Claude finishes, only if you haven't typed since and no background agent is still running. It doesn't fire while Claude Code waits for a usage limit to reset.
  • A request that arrives while another dialog is open is timed from when it arrives, so its notification can reach you while it still waits behind the open dialog.

Hosts that answer permissions through the Agent SDK, such as Claude Desktop and the VS Code extension, time permission_prompt differently: about six seconds after the request, not deferred by typing, and skipped if you or a PermissionRequest hook answer first.

If you want a signal with no delay, use a different event:

You wantUse
An alert the instant Claude asks for permissionPermissionRequest
An alert the instant Claude finishesStop
A nudge only if you've really wandered offNotification with idle_prompt

03What the hook receives

On top of the common fields (session_id, transcript_path, cwd, hook_event_name), a Notification hook gets the notification's message, an optional title, and the notification_type:

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "Notification",
  "message": "Claude needs your permission",
  "title": "Permission needed",
  "notification_type": "permission_prompt"
}

The message is Claude Code's own wording, so it is safe to show as is. cwd is useful when you run several sessions and want to know which project is asking.

04What the hook can and can't do

A Notification hook cannot block, delay or change the notification. Its exit code and stderr are ignored, and Claude Code discards systemMessage and continue from its JSON output. It is purely for side effects.

There is one output field it can use: terminalSequence. Hooks run without a terminal, so they can't write escape sequences themselves, but they can hand one to Claude Code to emit. That lets a hook trigger a terminal-native notification in iTerm2, Ghostty, Kitty, WezTerm, Windows Terminal and others, even inside tmux. It only works in an interactive session with Claude Code's interface on screen.

The preferredNotifChannel setting doesn't stop the hook either. Even with built-in notifications turned off, the Notification event still fires. That setting only changes how Claude Code itself alerts you; see the terminal bell guide.

05Examples

Different handlers per type

Run a separate script for permission prompts and for idle reminders:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [{ "type": "command", "command": "~/.claude/hooks/permission-alert.sh" }]
      },
      {
        "matcher": "idle_prompt",
        "hooks": [{ "type": "command", "command": "~/.claude/hooks/idle-alert.sh" }]
      }
    ]
  }
}

Make each script executable with chmod +x. The desktop notification commands for Mac, Windows and Linux are in how to get a notification when Claude Code finishes, so they aren't repeated here.

Show the real message and project

This script (macOS and Linux) puts Claude Code's message and the project folder in the notification, instead of a fixed string:

#!/bin/bash
# ~/.claude/hooks/notify.sh
input=$(cat)
msg=$(jq -r '.message // "Claude Code needs your attention"' <<<"$input")
project=$(basename "$(jq -r '.cwd // "."' <<<"$input")")

if command -v osascript >/dev/null 2>&1; then
  osascript -e 'on run argv' \
            -e 'display notification (item 1 of argv) with title (item 2 of argv)' \
            -e 'end run' "$msg" "Claude Code: $project"
elif command -v notify-send >/dev/null 2>&1; then
  notify-send "Claude Code: $project" "$msg"
fi
exit 0

Passing the text as arguments (on run argv) avoids breaking the AppleScript when the message contains quotes. It needs jq installed.

A terminal-native notification

Anthropic's own example uses terminalSequence with OSC 777, which Ghostty, Warp and urxvt understand:

#!/bin/bash
input=$(cat)
title="Claude Code"
body=$(jq -r '.message // "Needs your attention"' <<<"$input")
seq=$(printf '\033]777;notify;%s;%s\007' "$title" "$body")
jq -nc --arg seq "$seq" '{terminalSequence: $seq}'

For iTerm2, Windows Terminal or WezTerm use OSC 9 instead, and for Kitty OSC 99. Anything outside the allowed sequences is ignored.

06Where Claude Code Notifier fits

A Notification hook that calls a push service gets the alert to your phone, and for many people that is enough. The ntfy guide shows that route.

The gap is the reply. By the time permission_prompt fires, Claude is waiting on a dialog that a Notification hook can't answer. Claude Code Notifier handles this with the hooks that can: PermissionRequest to return your decision and PreToolUse on AskUserQuestion to return your answer. Its free command line tool, ccn, runs on Mac, Windows and Linux and shows desktop notifications on its own. With the iPhone or Android app paired, you can allow once, allow for the session, or deny from the phone. If you typed in the last 30 seconds, nothing waits for the phone and the terminal asks as usual. It is independent and not made by Anthropic. Installation is on the ccn page.

07FAQ

Why does my Notification hook never fire?

Most often because you are still at the keyboard. Each keystroke defers permission_prompt, and idle_prompt only fires if you haven't typed for about a minute after Claude finished. To test, trigger a permission prompt, switch to another window and wait at least six seconds. If it still doesn't fire, check /hooks lists it and see the troubleshooting checklist.

What is idle_prompt?

It is the notification type Claude Code sends when Claude finished responding about 60 seconds ago and you haven't typed since. It is a reminder that it is your turn, not an instant "done" signal. For that, use a Stop hook.

Can a Notification hook approve a permission?

No. Notification hooks have no decision control, so nothing they print can answer the prompt. Use a PermissionRequest hook to allow or deny, as described in the PermissionRequest guide.

Does the Notification hook run if I set preferredNotifChannel to notifications_disabled?

Yes. That setting only changes how Claude Code alerts you itself. The Notification event and your hooks still run.

Why do I get two notifications?

Claude Code's built-in notification and your hook run side by side. In iTerm2, Ghostty or Kitty you may see both. Turn one off, for example with preferredNotifChannel, or keep only the hook.

Claude Code Notifier Get a push on your phone when Claude Code finishes or needs you, then approve, deny or answer from there. The ccn command line tool is free on Mac, Windows and Linux.
Download for iOS Download for Android Install ccn

Related guides

  • How to get a notification when Claude Code finishesUse a Stop hook for "finished" and a Notification hook for "needs input". Copy-paste setups for Mac, Windows and Linux, plus phone alerts.
  • Answering permission requests from a hook (PermissionRequest)How Claude Code's PermissionRequest hook works, how to allow or deny from a script, and why permission rules are often the better tool.
  • The Claude Code Stop hook: run something when Claude finishesHow Claude Code's Stop hook works, what input it gets, how to run a command when Claude finishes, and how to make Claude keep going safely.
  • Claude Code's built-in notifications: the terminal bell and preferredNotifChannelHow Claude Code's built-in alerts work, what each preferredNotifChannel value does, and how to set up iTerm2, Apple Terminal, Kitty, Ghostty and tmux.
claude-code-notifier

Claude Code Notifier is an independent third-party application. It is not affiliated with, endorsed by, or sponsored by Anthropic, PBC. "Claude" and "Claude Code" are trademarks of Anthropic, PBC.

apps iOS App Android App ccn for macOS, Windows & Linux All guides
legal Privacy Policy Terms of Service Other languages © 2026 touchtap. All rights reserved. TouchTap Ltd is registered in England and Wales, company number 13942589.