CircleCI’s webhook feature lets you push build status and other event data to external systems, enabling automated workflows beyond your CI/CD pipeline.
Let’s see it in action. Imagine you want to notify a Slack channel whenever a build fails.
Here’s a sample CircleCI workflow definition (.circleci/config.yml) that includes a notify job triggered on failure:
version: 2.1
jobs:
build-and-test:
docker:
- image: cimg/node:18.17.0
steps:
- checkout
- run: npm install
- run: npm test
notify:
docker:
- image: alpine:latest
steps:
- run: |
if [ "${CIRCLE_BRANCH}" == "main" ] && [ "${CIRCLE_BRANCH}" == "develop" ]; then
echo "Skipping notification for branch ${CIRCLE_BRANCH}"
else
echo "Sending notification for build ${CIRCLE_BUILD_NUM}"
curl -X POST -H 'Content-type: application/json' --data '{"text":"Build failed for job '"${JOB_NAME}"' on branch '"${CIRCLE_BRANCH}"' - <${CIRCLE_BUILD_URL}|Build Details>"}' YOUR_SLACK_WEBHOOK_URL
fi
workflows:
version: 2
build-flow:
jobs:
- build-and-test
- notify:
requires:
- build-and-test
filters:
failed: true
In this configuration:
- The
build-and-testjob runs your application’s build and test suite. - The
notifyjob is designed to send out notifications. It checks if the build is for themainordevelopbranch (and skips if so, you’d adjust this logic for your needs). - The
notifyjob usescurlto send a JSON payload to aYOUR_SLACK_WEBHOOK_URL. This URL is where Slack (or any other service) will listen for incoming messages. - The
workflowssection defines thebuild-flow. Thenotifyjobrequiresbuild-and-testto have completed. - Crucially, the
filters: failed: trueon thenotifyjob ensures this job only runs if a preceding job in the workflow (in this case,build-and-test) has failed.
The YOUR_SLACK_WEBHOOK_URL is a placeholder. You’d replace this with the actual webhook URL provided by your external service (like Slack, PagerDuty, or a custom endpoint). These URLs are typically long, unique strings that authenticate your request.
CircleCI provides several environment variables that are invaluable when constructing webhook payloads. For instance:
CIRCLE_BUILD_NUM: The unique number of the current build.CIRCLE_BUILD_URL: The URL to the build in CircleCI.CIRCLE_BRANCH: The branch the build is for.CIRCLE_PROJECT_REPONAME: The name of the repository.CIRCLE_USERNAME: The user who triggered the build.JOB_NAME: The name of the job that is running.
You can access these within your config.yml using shell variable syntax.
The core mechanism is HTTP POST requests. CircleCI’s run steps can execute shell commands, and curl is the go-to tool for making these requests. The Content-type: application/json header is essential for most modern APIs, and the --data flag carries the payload.
A common pattern is to store sensitive webhook URLs as environment variables in your CircleCI project settings. You can then access them in your config.yml like this: ${MY_SECRET_WEBHOOK_URL}. This keeps your secrets out of your version-controlled configuration files.
The filters in the workflows section are powerful. You can trigger jobs based on branches, tags, and importantly, the success or failure of other jobs. The failed: true filter is key for error-handling notifications.
You can also use CircleCI’s API to trigger workflows or retrieve build information, which can then be fed into your webhook payloads. This allows for more complex interactions where CircleCI doesn’t just send data but also initiates actions in external systems based on that data.
The actual format of the JSON payload depends entirely on the receiving service. Slack, for example, has specific formatting requirements for messages, while PagerDuty expects a different structure for incident creation. Always consult the documentation of the service you’re integrating with.
You can also use Orb for more abstract webhook integrations. Orbs are reusable packages of CircleCI configuration. There are Orbs available for common integrations like Slack, which can simplify the process of sending notifications without needing to write curl commands directly.
The most surprising aspect is how little control you have over the timing of the webhook delivery. While CircleCI aims for immediate delivery, network latency or temporary unavailability of the target endpoint can lead to delays or even dropped events, which is why implementing retry logic or using a more robust queuing system on the receiving end is often a good idea.
The next step is usually integrating with an incident management system or a deployment automation tool.