Để nhận thông báo push của Claude Code qua ntfy, hãy cài app ntfy trên điện thoại, subscribe một topic có tên khó đoán, rồi thêm một hook cho Claude Code chạy lệnh curl -d "message" https://ntfy.sh/your-topic. Hook Notification báo cho bạn khi Claude cần cấp quyền hoặc đang chờ bạn, còn hook Stop báo ngay khi một lượt kết thúc. Cách này miễn phí, mất khoảng mười phút và chạy được trên Mac, Windows lẫn Linux.
01Bước 1: chọn topic và subscribe
ntfy không cần đăng ký. Topic được tạo ngay lần đầu có người publish hoặc subscribe, và ai biết tên topic cũng đọc được. Chính tài liệu của ntfy nói topic về cơ bản là một mật khẩu, nên hãy đặt tên dài và ngẫu nhiên, ví dụ claude-7f3k9q2xw4mz. Tên topic có thể gồm chữ cái, số, dấu gạch dưới và gạch ngang, tối đa 64 ký tự.
Cài app ntfy (App Store, Google Play hoặc F-Droid), nhấn + và subscribe topic của bạn trên ntfy.sh.
Kiểm tra từ terminal:
curl -H "Title: Test" -d "Hello from my computer" https://ntfy.sh/claude-7f3k9q2xw4mz
Điện thoại sẽ rung trong vòng một hai giây. Trên Windows, curl.exe có sẵn trong Windows 10 và 11 và chạy được đúng dòng lệnh này.
02Bước 2: script hook (Mac và Linux)
Claude Code truyền cho mỗi hook một object JSON qua standard input. Cả hai event đều có chung các trường như cwd và hook_event_name. Notification có thêm message và notification_type, còn Stop có thêm last_assistant_message là nội dung câu trả lời cuối của Claude. Script này chuyển cả hai thành một thông báo push dễ đọc. Script cần jq (brew install jq, hoặc apt install jq trên Debian và Ubuntu).
Lưu thành ~/.claude/ntfy-notify.sh rồi chạy chmod +x ~/.claude/ntfy-notify.sh:
#!/bin/sh
TOPIC_URL="https://ntfy.sh/claude-7f3k9q2xw4mz"
input=$(cat)
event=$(printf '%s' "$input" | jq -r '.hook_event_name')
project=$(basename "$(printf '%s' "$input" | jq -r '.cwd')")
if [ "$event" = "Stop" ]; then
title="Claude finished: $project"
body=$(printf '%s' "$input" | jq -r '(.last_assistant_message // "Done") | .[0:300]')
priority=3
else
title="Claude needs you: $project"
body=$(printf '%s' "$input" | jq -r '.message // "Needs your attention"')
priority=4
fi
curl -s -H "Title: $title" -H "Priority: $priority" -H "Tags: robot" \
-d "$body" "$TOPIC_URL" > /dev/null
exit 0
Priority đi từ 1 (min) đến 5 (urgent). Tags thêm emoji vào thông báo; robot hiển thị mặt robot.
03Bước 3: gắn vào settings.json
Thêm các hook vào ~/.claude/settings.json. Nếu file đã có object hooks, hãy thêm các event này vào bên trong thay vì ghi đè.
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{ "type": "command", "command": "~/.claude/ntfy-notify.sh" }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "~/.claude/ntfy-notify.sh", "async": true }
]
}
]
}
}
"async": true cho phép hook Stop gửi ở chế độ nền, nên mạng chậm cũng không làm Claude bị trễ. Hãy mở một session Claude Code mới, vì hook chỉ được load khi session khởi động.
Dùng Stop hay idle_prompt?
Stop kích hoạt ngay khi Claude xong việc, kể cả khi bạn đang ngồi trước bàn phím. Nếu thấy phiền, hãy bỏ block Stop và dùng matcher permission_prompt|idle_prompt. Theo tài liệu của Anthropic, idle_prompt kích hoạt khoảng 60 giây sau khi Claude xong, chỉ khi bạn chưa gõ gì từ lúc đó, còn permission_prompt kích hoạt khi một prompt xin quyền đã chờ khoảng sáu giây mà không có phím nào được nhấn. Như vậy bạn có sẵn một bộ lọc "chỉ báo khi tôi vắng mặt" tương đối mà không tốn công. Hướng dẫn Notification hook và hướng dẫn Stop hook trình bày đầy đủ mọi trường và thời điểm kích hoạt.
04Windows (PowerShell)
Trên Windows, lưu script này thành %USERPROFILE%\.claude\ntfy-notify.ps1. Không cần cài thêm gì:
$in = [Console]::In.ReadToEnd() | ConvertFrom-Json
$project = Split-Path $in.cwd -Leaf
if ($in.hook_event_name -eq 'Stop') {
$title = "Claude finished: $project"
$body = [string]$in.last_assistant_message
if ($body.Length -gt 300) { $body = $body.Substring(0, 300) }
$priority = '3'
} else {
$title = "Claude needs you: $project"
$body = [string]$in.message
$priority = '4'
}
Invoke-RestMethod -Method Post -Uri 'https://ntfy.sh/claude-7f3k9q2xw4mz' `
-Headers @{ Title = $title; Priority = $priority } `
-Body ([Text.Encoding]::UTF8.GetBytes($body)) | Out-Null
Sau đó dùng hook entry này thay cho các dòng command ở trên:
{
"type": "command",
"shell": "powershell",
"command": "powershell -NoProfile -ExecutionPolicy Bypass -File \"$HOME\\.claude\\ntfy-notify.ps1\""
}
Nếu bạn chạy Claude Code trong WSL, hãy dùng script cho Mac và Linux; với hook, WSL chính là Linux.
05Giữ bảo mật
Mọi nội dung push đều đi qua server ntfy, và trên ntfy.sh ai có tên topic cũng đọc được. Thông báo Stop ở trên có chứa phần đầu câu trả lời của Claude, có thể bao gồm code hoặc tên file. Có ba cách để siết chặt hơn:
- Gửi ít thông tin hơn. Thay nội dung
Stopbằng một chuỗi cố định như"Done"và chỉ giữ tên project ở tiêu đề. - Dùng access token. ntfy chấp nhận
-H "Authorization: Bearer tk_..."ở mọi lần publish. Trên server riêng, đặtauth-default-access: "deny-all", tạo user bằngntfy user addvà tạo token bằngntfy token add. - Tự host server. ntfy có thể self-host. Để app iPhone nhận thông báo tức thì, tài liệu của ntfy hướng dẫn đặt
upstream-base-url: "https://ntfy.sh"; khi đó chỉ có message ID và hash của topic được chuyển tới ntfy.sh để đánh thức điện thoại, sau đó app tự lấy nội dung từ server của bạn.
Nếu Claude Code chạy trên server từ xa, hook này vẫn dùng được nguyên vẹn, nên ntfy rất hợp cho thông báo qua SSH.
06Claude Code Notifier nằm ở đâu trong bức tranh này
Với thông báo một chiều, cách thiết lập trên là đủ và chúng tôi không khuyên bạn bỏ nó. Nhưng nó chỉ dừng ở việc báo tin. Khi push báo Claude cần cấp quyền, session vẫn phải chờ đến khi bạn quay lại bàn phím.
ntfy có hỗ trợ action button gửi HTTP request, nên bạn có thể tự dựng đường phản hồi: một hook PermissionRequest publish yêu cầu, chờ phản hồi trên một topic thứ hai rồi trả về quyết định. Một số dự án open source làm đúng như vậy (xem bài so sánh).
Claude Code Notifier đóng gói sẵn luồng đó. Khi đã ghép nối điện thoại, bạn có thể cho phép một lần, cho phép trong cả session hoặc từ chối quyền, chọn câu trả lời khi Claude hỏi, và gửi chỉ dẫn tiếp theo sau khi Claude xong, tất cả ngay trên điện thoại. Nó còn kiểm tra bạn có đang ở đó không: nếu bạn gõ phím trong 30 giây gần nhất, terminal hỏi như bình thường và không có gì chờ trên điện thoại. Nếu bạn vắng mặt, terminal chờ câu trả lời của bạn tối đa trong khoảng thời gian bạn đặt, và thôi chờ ngay khi bạn chạm vào bàn phím. ccn chạy trên Mac, Windows và Linux; xem trang ccn và bảng giá cho các app điện thoại.
07Câu hỏi thường gặp
ntfy có miễn phí cho thông báo Claude Code không?
Publish và subscribe trên ntfy.sh không cần tài khoản, và server mở cho mọi người. ntfy cũng có gói trả phí và có thể self-host. Hãy xem trang của ntfy để biết giới hạn hiện tại.
Vì sao hook ntfy của tôi không chạy?
Hãy mở session Claude Code mới sau khi sửa settings.json, vì hook được load lúc khởi động. Sau đó chạy tay dòng test curl, và pipe JSON mẫu vào script, ví dụ echo '{"hook_event_name":"Stop","cwd":"/tmp/x"}' | ~/.claude/ntfy-notify.sh. Checklist xử lý sự cố trình bày phần còn lại.
Tôi có thể trả lời Claude Code từ thông báo ntfy không?
Với publish thông thường thì không. Action button HTTP của ntfy có thể gửi request, nhưng bạn cần một hook chờ câu trả lời và chuyển nó thành quyết định mà Claude Code hiểu được.
Tôi có nhận push cho mọi loại thông báo không?
Chỉ với các matcher bạn liệt kê. Bỏ matcher ở entry Notification để nhận mọi loại, kể cả hộp thoại xác thực và MCP.