How to Set Up a Discord Webhook in Claude Code
In this article
- What are Claude Code hooks and why use them for Discord?
- How to create a Discord webhook URL
- How to configure the hook in Claude Code
- Sending richer Discord notifications with context
- Which hook events should you use?
- Scoping hooks to specific projects
- Staying aware of usage limits while running automated hooks
- Troubleshooting common issues
- Key takeaways
- Sources
The fastest way to set up Discord webhook notifications in Claude Code is via Claude Code hooks — shell scripts that fire at lifecycle events like task completion, errors, or tool use. Create a Discord webhook URL in your server settings, then add a PostToolUse or Stop hook that sends a curl POST request to that URL. No plugins required. Works on any project, any OS.
- Claude Code hooks support
PreToolUse,PostToolUse,Notification,Stop, andSubagentStopevents - Discord webhooks accept a simple JSON payload:
{"content": "your message"} - Setup takes under 5 minutes and requires only a Discord server with "Manage Webhooks" permission
What are Claude Code hooks and why use them for Discord?
Claude Code hooks are user-defined shell commands that run automatically at specific points in the agent's lifecycle. They let you integrate Claude Code with external services without writing a plugin or modifying your project code. According to the Claude Code documentation, hooks execute in your shell environment with full access to environment variables and system tools like curl.
Pairing hooks with Discord webhooks means you can get a ping in your team server the moment Claude Code finishes a long-running task, hits an error, or completes a sub-agent job. This is especially useful when you step away from your machine and need to know when a complex PR build or migration script wraps up.
How to create a Discord webhook URL
Before touching Claude Code, you need a webhook URL from Discord:
- Open your Discord server and go to Server Settings (right-click the server icon).
- Navigate to Integrations and then Webhooks.
- Click New Webhook, give it a name (e.g., "Claude Code Alerts"), and choose the channel where notifications should post.
- Click Copy Webhook URL and save it somewhere safe. It looks like
https://discord.com/api/webhooks/1234567890/xxxx...
Keep this URL private. Anyone with it can post to your channel. Store it as an environment variable rather than hard-coding it in config files.
How to configure the hook in Claude Code
Claude Code hooks are configured in your settings.json file (located at ~/.claude/settings.json for global hooks, or .claude/settings.json inside a project for project-scoped hooks).
Step 1: Store your webhook URL as an environment variable
Add the following to your shell profile (~/.zshrc, ~/.bashrc, etc.):
export DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_TOKEN"
Then reload your shell: source ~/.zshrc
Step 2: Add a Stop hook to settings.json
Open (or create) ~/.claude/settings.json and add a hooks block:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "curl -s -H 'Content-Type: application/json' -d '{\"content\":\"Claude Code task finished!\"}' \"$DISCORD_WEBHOOK_URL\""
}
]
}
]
}
}
The Stop event fires when Claude Code finishes a response turn. This is the most useful trigger for "task done" notifications.
Step 3: Test the webhook
Run any Claude Code task — even a simple one like /help. Check your Discord channel. You should see the "Claude Code task finished!" message appear within a second or two of Claude completing its response.
Sending richer Discord notifications with context
The basic example sends a static string. You can make notifications more useful by including dynamic context from Claude Code's hook environment. Hooks receive JSON on stdin describing the event, which you can pipe through jq to extract fields.
A more informative hook script (save as ~/.claude/discord-notify.sh):
#!/bin/bash
# Read the event JSON from stdin
INPUT=$(cat)
SESSION=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
MSG="Claude Code session \`$SESSION\` just finished a task."
curl -s \
-H "Content-Type: application/json" \
-d "{\"content\": \"$MSG\"}" \
"$DISCORD_WEBHOOK_URL"
Make it executable: chmod +x ~/.claude/discord-notify.sh
Then reference the script in your settings:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/discord-notify.sh"
}
]
}
]
}
}
Using Discord embed format for styled alerts
Discord webhooks support rich embeds. Replace the plain content payload with an embeds array for color-coded, structured messages:
curl -s -H 'Content-Type: application/json' \
-d '{
"embeds": [{
"title": "Claude Code: Task Complete",
"description": "Your agent finished running.",
"color": 5763719
}]
}' "$DISCORD_WEBHOOK_URL"
The color field is a decimal integer (5763719 = green). Use red (15548997) for error hooks.
Which hook events should you use?
Claude Code exposes several hook events. The right one depends on what you want to monitor:
| Event | When it fires | Best for |
|---|---|---|
Stop | Claude finishes a response turn | "Task done" pings |
SubagentStop | A sub-agent completes | Multi-agent workflow alerts |
PostToolUse | After any tool (Bash, Write, etc.) runs | Monitoring specific tool calls |
Notification | Claude sends a notification event | Forwarding Claude's own alerts |
PreToolUse | Before a tool runs | Blocking or logging tool calls |
For most "notify my team when the agent is done" use cases, Stop is sufficient. If you're running long agentic pipelines with complex hook setups, consider SubagentStop to get per-agent granularity.
Scoping hooks to specific projects
Global hooks in ~/.claude/settings.json fire for every Claude Code session on your machine. To scope a Discord webhook to one project only, place the settings file at <project-root>/.claude/settings.json instead. This is useful when different projects should post to different Discord channels.
You can also use the matcher field to filter PostToolUse hooks to specific tools. For example, a matcher of "Bash" fires only when Claude runs a bash command — handy for alerting your team to any shell execution during a sensitive migration. See the full slash commands and hooks guide for matcher syntax details.
Staying aware of usage limits while running automated hooks
When you start wiring up hooks and leaving Claude Code running unattended, you can burn through your usage window faster than expected. Claude Code usage operates on a 5-hour rolling window — and hitting the limit mid-task means a hard stop until the window resets. You can check your current usage at any time with the /usage command inside Claude Code, or by visiting claude.ai/settings/usage.
For a passive, always-visible signal, Usagebar sits in your macOS menu bar and shows your Claude Code usage at a glance. It sends proactive alerts at 50%, 75%, and 90% of your limit, so you know well before you hit a wall. It uses macOS Keychain for secure credential storage and is available on a pay-what-you-want basis, including free for students. When you're relying on Discord webhooks to tell you when a job finishes, the last thing you want is to discover the job stalled because your usage limit ran out mid-task.
Get Usagebar and stop getting surprised by usage resets.
Troubleshooting common issues
- No message appears in Discord: Check that
$DISCORD_WEBHOOK_URLis exported in the same shell environment Claude Code runs in. Runecho $DISCORD_WEBHOOK_URLin the terminal where you launch Claude Code. - curl: command not found: Install curl (
brew install curlon macOS) or use an alternative likewgetor a small Node.js script. - Hook runs but Discord returns a 400 error: Your JSON payload likely has a quoting issue. Test the curl command directly in your terminal before adding it to settings.
- Hook fires too frequently: Switch from
PostToolUse(fires on every tool call) toStop(fires once per response turn) to reduce noise. - Webhook URL expired or invalid: Regenerate the webhook in Discord's Integrations settings and update your environment variable.
Key takeaways
- Create a Discord webhook URL in your server's Integrations settings and store it as an environment variable.
- Add a
Stophook in~/.claude/settings.jsonwith acurlcommand targeting your webhook URL. - Use a shell script for richer notifications that include session context via
jq. - Scope hooks to individual projects using a project-level
.claude/settings.jsonfile. - Monitor your usage limits passively with Usagebar so automated tasks don't get cut off mid-run.
Sources
Never Get Locked Out Mid-Task Again
Never hit your usage limits unexpectedly. Usagebar lives in your menu bar and shows your 5-hour and weekly limits at a glance.
Get Usagebar$9 — one-time, lifetime updates