Using Mattermost Incoming Webhooks for CI Notifications
Learn how to configure a Mattermost Incoming Webhook, build a JSON payload with attachments, and send CI build status updates from any script or pipeline.
22 Feb 2026, 17:50 UTC

When a CI pipeline finishes, you often want the result visible to the whole team without asking everyone to check a separate dashboard.
Setting up an Incoming Webhook
In Mattermost, open the target channel, choose Channel Settings → Integrations → Add Incoming Webhook. Mattermost creates a unique URL for that channel and optionally lets you define a Secret token. Only users with the manage_channel permission (typically channel admins) can create or edit the webhook.
Building the payload
The webhook expects a JSON object with a top‑level text field for the main message and an optional attachments array for richer formatting. Mattermost renders Markdown in text, so you can use **bold**, *italic*, or `code` blocks. Each attachment can include fallback, pretext, title, color (hex), and a fields array for key‑value data.
Sending a notification from a CI job
Assuming the webhook URL is stored as an environment variable WEBHOOK_URL and, if you enabled a secret, the token is in WEBHOOK_SECRET, a minimal Bash step looks like:
#!/usr/bin/env bash
set -euo pipefail
PAYLOAD=$(cat <
The script builds a JSON payload using the CI environment variables common to GitLab CI/GitHub Actions, sets the attachment color based on the job status, and posts it with curl. If a secret is configured, the Mattermost-Secret header is added; otherwise it is omitted.
Trade‑offs and limitations
- Security: The webhook URL is effectively a secret; if it is leaked anyone can post to the channel. Treat it like a password and store it in a protected CI secret store.
- Rate limiting: Mattermost enforces a default limit of 10 requests per second per webhook URL. Exceeding it returns HTTP 429. In CI pipelines this is rarely a problem, but if you fan‑out many services to the same webhook consider creating separate webhooks or implementing exponential back‑off.
- Attachment size: Individual attachments are limited to 8 MB. For larger artifacts use the Mattermost file upload API instead of embedding them.
Verifying the integration
- Save the webhook in Mattermost and copy the generated URL.
- Run a test curl from your workstation:
curl -X POST -H "Content-Type: application/json" \
-d '{\"text\":\"Test message\",\"attachments\":[{\"fallback\":\"test\",\"title\":\"Test\",\"color\":\"#00FF00\"}]}' \
https://your-mattermost/hooks/abcd1234
You should see a message appear in the channel with the attachment title “Test” and a green bar. To check the rate‑limit behavior, send a burst of requests, for example:
for i in {1..15}; do
curl -s -o /dev/null -w \"%{http_code}\\n\" -X POST -H \"Content-Type: application/json\" \
-d '{\"text\":\"Burst $i\"}' https://your-mattermost/hooks/abcd1234
done
The first 10 lines should show 200, followed by 5 lines of 429. If you configured a secret, repeat the test without the Mattermost-Secret header and verify that the responses are 401 Unauthorized.
Once the test succeeds, add the curl command (or the script above) to the appropriate stage of your CI pipeline. The message will appear automatically each time the pipeline runs, giving the team immediate visibility without extra tooling.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.