What Discord Webhook Tester does
Discord Webhook Tester is a free, MIT-licensed CLI and local web form that posts a test message to a Discord webhook URL and builds the embed it sends. It does two things: it proves the webhook is alive, and it shows you what your message will look like before a channel full of people sees it.
| Feature | What it means |
|---|---|
| One-command test | discord-webhook-tester send posts a ready-made test embed, with no
options to fill in.
|
| Embed builder | Title, description, colour, author, fields, images, footer and timestamp, as CLI options or in the form, up to 10 embeds per message. |
| Live preview | The form renders your draft the way Discord will, and sent messages land in the mock channel with their delivery status. |
| Export | Copy the same message as a JSON payload, a curl command or a CLI command. |
| Local validation | Discord's limits are checked before anything is sent, so a typo fails instantly instead of after a round trip. |
| Readable errors |
Nested Discord error responses become lines like
embeds.0.title: Must be 256 or fewer in length. |
| Threads, forums, files | Post into a thread, create a forum post, attach files, or send without notifications. |
How do I test a Discord webhook?
Set DISCORD_WEBHOOK_URL to the webhook's URL and run
discord-webhook-tester send: it posts a ready-made embed to the channel and prints
the status Discord answered with. Nothing has to be installed if you run it with
uv:
export DISCORD_WEBHOOK_URL='https://discord.com/api/webhooks/<id>/<token>'
uvx --from git+https://github.com/webhooker-eu/discord-webhook-tester \
discord-webhook-tester send Or install it as a command:
uv tool install git+https://github.com/webhooker-eu/discord-webhook-tester
# or
pipx install git+https://github.com/webhooker-eu/discord-webhook-tester
discord-webhook-tester send Or run the published image, with nothing else on your machine:
# Web form on http://localhost:8080
docker run --rm -p 127.0.0.1:8080:8080 ghcr.io/webhooker-eu/discord-webhook-tester
# Or as the CLI
docker run --rm -e DISCORD_WEBHOOK_URL ghcr.io/webhooker-eu/discord-webhook-tester \
send --content 'Hello from Docker'
Get the webhook URL in Discord under Server Settings → Integrations → Webhooks → New
Webhook → Copy Webhook URL. Prefer the DISCORD_WEBHOOK_URL variable over
passing it as an argument: arguments end up in your shell history.
How do I send a Discord embed from the command line?
Every part of a Discord embed has an option, so a deploy notification is one command in your pipeline:
discord-webhook-tester send \
--title 'Build #128 passed' \
--description 'All **42** tests are green.' \
--url 'https://ci.example.com/builds/128' \
--color green \
--author 'CI' \
--field 'Branch|main|inline' \
--field 'Duration|3m 12s|inline' \
--footer 'ci.example.com' \
--timestamp now
Colours accept #RRGGBB, a decimal integer or a name such as blurple,
green or red. Fields take
'NAME|VALUE|inline' and repeat up to 25 times. A raw payload from a file or stdin
works too, with --payload-file, and any other options are layered on top of it.
What are Discord's webhook message limits?
A webhook message is capped at 2000 characters of content and 10 embeds, and all embeds together may not exceed 6000 characters. Discord enforces the rest per embed part, and a message that breaks any of them comes back as a 400 with a nested error body. Discord Webhook Tester checks every one of these locally, before the request leaves your machine, so a too-long field fails instantly instead of after a round trip.
| Message part | Limit |
|---|---|
| Message content | 2000 characters |
| Embeds per message | 10 |
| All embeds in one message | 6000 characters in total |
| Embed title | 256 characters |
| Embed description | 4096 characters |
| Fields per embed | 25 |
| Field name / field value | 256 / 1024 characters |
| Embed footer text | 2048 characters |
| Embed author name | 256 characters |
| Override username | 80 characters |
| File attachments per message | 10 |
The limits come from Discord's own reference: the
embed limits and the Execute Webhook endpoint. Rate limits are per webhook and Discord returns the wait in the response, so a short
429 is retried twice, with the number of attempts printed, instead of failing your
pipeline step on the first try. The error codes, rate limit headers and the invalid request
limit are covered in the Discord webhooks guide.
The web form
discord-webhook-tester serve --open starts a local form on
127.0.0.1:8080. Paste the webhook URL, build the message, press
Send message, and read what Discord answered. The draft is kept in your
browser's local storage; the webhook URL is stored only if you tick
Remember the URL in this browser.
Why run the tester locally instead of pasting the URL into a website?
A Discord webhook URL is a credential: anyone holding it can post to that channel under the
webhook's name, and it cannot be rotated without creating a new webhook. A browser-based tester
sends that credential to its own server, where it may be logged. Discord Webhook Tester runs on
your machine and talks to discord.com directly.
| Discord Webhook Tester | Browser-based tester | |
|---|---|---|
| Where the webhook URL goes | Your machine, then Discord | The website's server, then Discord |
| Runs in CI | Yes, exit codes and --json | No, it is a page in a browser |
| Account needed | No | Varies by site |
| Limits checked before sending | Yes, all of the table above | Usually not: Discord answers with the error |
| Works offline | The embed builder and preview do | No |
Using it in CI
The CLI is built for scripts: it reads the URL from an environment variable, prints JSON on request, and returns an exit code you can branch on.
# Confirm the webhook still exists, without posting anything
discord-webhook-tester info --json || echo 'The Discord webhook is broken'
# See the JSON that would be sent
discord-webhook-tester send --title 'Hello' --color '#5865F2' --dry-run | Exit code | Meaning |
|---|---|
0 | The message was sent, or the webhook is valid. |
1 | Discord rejected the request, or could not be reached. |
2 | Invalid input: a bad URL, a payload over Discord's limits, an unreadable file. |
Discord webhooks and the rest of your webhook traffic
A Discord webhook is an outgoing notification: your script posts a message and Discord shows it. That is the opposite direction from the webhooks a provider sends you, where a missed request means a missed payment or a missed order. If you also relay provider events into a Discord channel, the fragile part is not the message. It is whether the event reached your code at all.
Webhooker handles that half: one ingest URL receives the provider's events, verifies the signature, stores each one and delivers it to your services with retries and replay. Start with what a webhook is if the two directions still blur together.
Frequently asked questions
How do I test a Discord webhook?
Copy the webhook URL from Server Settings, Integrations, Webhooks, then run discord-webhook-tester send with DISCORD_WEBHOOK_URL set. A ready-made embed is posted to the channel, and the exit code tells you whether Discord accepted it. No message is sent by the info command, which only confirms that the webhook exists and shows its name, channel and server.
Where do I find my Discord webhook URL?
In Discord: Server Settings, then Integrations, then Webhooks, then New Webhook and Copy Webhook URL. It looks like https://discord.com/api/webhooks/<id>/<token>. Treat it as a credential: anyone who has it can post to that channel, so keep it in an environment variable rather than in code or shell history.
Can I build an embed without writing JSON?
Yes. Run discord-webhook-tester serve to open a local web form that looks like a Discord channel: set the title, description, colour, author, fields, images, footer and timestamp, and the preview renders the message as Discord will show it. The JSON, curl and CLI tabs give you the same message in a form you can paste into your code.
Why is Discord rejecting my webhook message?
Usually a limit: 2000 characters of content, 6000 characters across all embeds, 25 fields per embed, 10 embeds per message. The tool checks those locally before sending, and turns Discord's nested error response into one line per problem, such as embeds.0.title: Must be 256 or fewer in length. A 404 means the webhook was deleted; a 401 means the token in the URL is wrong.
Does the webhook URL leave my machine?
Only to Discord. The CLI and the local server parse the URL into an id and a token and rebuild the request from those parts, so nothing is sent anywhere else, and the form stores the URL in your browser only if you tick the box. That is the difference from pasting a webhook URL into a public tester website.
Can I use it in CI?
Yes. It reads the URL from an environment variable, prints machine-readable output with --json, and returns 0 only when Discord accepted the request, so a pipeline step can fail on a broken webhook. Files, threads, forum posts and silent messages are supported for the notification itself.
Further reading
- What is a webhook? Definition, payloads and use cases
- How webhooks work: the request, header by header
- Webhook security: signatures, replays and secrets
- Webhooks vs APIs: the difference, and what it costs you
More open-source tools
Self-hosted request bin in one Docker container.
Webhook Mock SenderSend signed Stripe, GitHub and Shopify events to your own endpoint.
Everything we publish lives in the webhooker-eu GitHub organisation, and the full list with a short description of each is on the open-source tools page.