CauselyBot is an open-source webhook service that allows users to send notifications to a variety of platforms. While Causely natively supports a number of notification endpoints (Alertmanager, Slack, Teams, etc), CauselyBot helps connect Causely's insights to any arbitrary endpoint. This server-side application validates bearer tokens included in the payload, then forwards notifications to the endpoints you configure.
To get up and running with CauselyBot, follow these steps:
- Configure CauselyBot - Set up your webhook configurations, authentication token, and filtering rules
- Deploy CauselyBot - Install and deploy the service using Docker or Helm
- Configure Causely - Update your Causely instance to send notifications to CauselyBot
- Test CauselyBot - Confirm your CauselyBot sends alerts to your webhook endpoints
See the sections below for detailed configuration and deployment instructions.
git clone https://github.com/causely-oss/causelybot.gitCauselyBot Docker images are pre-built and published to us-docker.pkg.dev/public-causely/public/bot:latest. See Appendix section for building image locally.
Create a causelybot-values.yaml file with your configuration. Use the example below and update the following fields:
<YOUR_CAUSELYBOT_TOKEN>[Required] Define your CauselyBot token here. This will be referenced in the Causely configurationcausely-values.yaml<FRIENDLY_WEBHOOK_NAME>[Required] Unique name for your webhook<YOUR_WEBHOOK_TYPE>[Required] Set to one of the following:generic,slack,teams,jira,opsgenie,debug<YOUR_WEBHOOK_URL>[Required] The URL of your webhook endpoint<YOUR_WEBHOOK_TOKEN>[Optional] If required by your webhook, provide a token
auth:
token: "<YOUR_CAUSELYBOT_TOKEN>" # Required - define your token here and then use in the Causely configuration (causely-values.yaml)
webhooks:
- name: "<FRIENDLY_WEBHOOK_NAME>" # Required
hook_type: "<YOUR_WEBHOOK_TYPE>" # Required [generic, slack, teams, jira, opsgenie, debug]
url: "<YOUR_WEBHOOK_URL>" # Required
token: "<YOUR_WEBHOOK_TOKEN>" # Optional
filters: # Optional - see Filtering Notifications
enabled: true
values:
- field: "severity"
operator: "in"
value: ["High", "Critical"]Note: Filters can also be configured in the Causely notification Secret (see Step 3), which lets you control which notifications are forwarded without modifying CauselyBot's own config.
For GitHub, causelybot expects a webhook where url is the repo as owner/repo and token is a GitHub token (repo + issues scope). Optional: assignee (e.g. copilot-swe-agent).
webhooks:
- name: "github"
url: "owner/repo" # required
token: "" # required; GitHub PAT or app token
assignee: "" # optional
filters:
enabled: true
values: []Install via Helm using the causelybot-values.yaml file:
helm upgrade --install causelybot ./causelybot/helm/causelybot --namespace causelybot --values causelybot-values.yamlTo configure Causely to send notifications to CauselyBot, first enable mediator notifications in your causely-values.yaml:
mediator:
notifications:
enabled: trueApply the change:
helm upgrade --install causely --create-namespace oci://us-docker.pkg.dev/public-causely/public/causely --version <version> --namespace=causely --values </path/to/causely-values.yaml>Then create a Kubernetes Secret in the causely namespace that points Causely at CauselyBot (use stringData so values are plain text; if you use data, values must be base64-encoded):
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: causelybot-notification-config
namespace: causely
labels:
causely.ai/notif-config: CauselyBot # Required
stringData:
notif_config_name: causelybot-webhook
notif_config_global: "false"
notif_config_type: CauselyBot
notif_config_url: http://causelybot.causelybot.svc.cluster.local.:5000/webhook
notif_config_token: "<YOUR_CAUSELYBOT_TOKEN>"
notif_config_filters: "[]"
notif_config_filters_enabled: "true"Important Notes:
notif_config_tokenmust match theauth.tokenyou set in CauselyBot's configuration. Causely sends it asAuthorization: Bearer <token>so CauselyBot can authenticate the request.notif_config_url: if CauselyBot is deployed in a different cluster or namespace, replace the in-cluster URL with the actual FQDN or IP of your CauselyBot instance.notif_config_filters: a JSON array of filter rules. When empty ("[]") ornotif_config_filters_enabledis"false", all notifications pass through. See Filtering Notifications for filter syntax.- See Causely's Documentation for additional details on
causely-values.yamlusage.
Apply the Secret:
kubectl apply -f causelybot-notification-config.yaml- To confirm your webhook has been configured correctly, in Causely, navigate to Settings > Notifications
- Click "Send Test Notification" to trigger a test payload.
- If the configuration is working, a test payload will be sent from Causely to CauselyBot to your webhook endpoint(s). If you do not receive the test notification, you can check the CauselyBot logs for more details:
kubectl logs -f deploy/causelybot -n causelybot
Below is an example of the raw payload sent from Causely to CauselyBot:
{
"link": "http://causely.localhost:3000/rootCauses/81703742-b81a-43b0-8509-1e9ac718e2e3",
"name": "Malfunction",
"slos": [
{
"status": "AT_RISK",
"slo_entity": {
"id": "988a33f8-afea-5b3b-b7e7-a578fe5184f1",
"link": "http://causely.localhost:3000/topology/988a33f8-afea-5b3b-b7e7-a578fe5184f1",
"name": "istio-system/prometheus-RequestSuccessRate",
"type": "RatioSLO"
},
"related_entity": {
"id": "6abdca4f-9574-42ec-a6c4-c4ba34f11c92",
"link": "http://causely.localhost:3000/topology/6abdca4f-9574-42ec-a6c4-c4ba34f11c92",
"name": "istio-system/prometheus",
"type": "KubernetesService"
}
}
],
"type": "ProblemDetected",
"entity": {
"id": "030fdbc4-8d3b-58f7-aa51-259b75374174",
"link": "http://causely.localhost:3000/topology/030fdbc4-8d3b-58f7-aa51-259b75374174",
"name": "istio-system/prometheus-7f467df8b6-zhmqc",
"type": "ApplicationInstance"
},
"labels": {
"k8s.cluster.uid": "919a6620-4466-454f-87d9-4b877a6ddf82",
"k8s.cluster.name": "dev",
"k8s.namespace.name": "istio-system"
},
"objectId": "81703742-b81a-43b0-8509-1e9ac718e2e3",
"severity": "High",
"timestamp": "2024-12-13T06:43:08.309296138Z",
"description": {
"summary": "An application is experiencing a high rate of errors, causing disruptions for clients. This can lead to degraded performance, failed requests, or complete service unavailability, significantly affecting the user experience.",
"remediationOptions": [
{
"title": "Check Logs",
"description": "Inspect the container logs for error messages or stack traces, which can provide clues about the issue.\n"
}
]
}
}Below is an example of what a root cause notification looks like in Slack:
Payload fields:
name: The event name, in this case it's the problem name.type: The type of notification (e.g., "ProblemDetected").entity: The details regarding the entity for which the notification is triggered:id: Id of the entityname: Name of the entitytype: Type of the entity
description: A description of the issue.timestamp: The timestamp when the issue was detected.labels: Metadata or tags that provide additional context (e.g., app name, Kubernetes namespace, and cluster information).objectId: A unique identifier for the specific object associated with this event, in this case it's the problem Id.severity: This is the severity of the problem detected/cleared.slos: If this field exists then it lists the impacted SLOs.
Filtering notifications can be done based on pre-defined fields or custom defined fields in FIELD_DEFINITIONS. A few examples of fields definitions are shown below:
{
"severity": {"type": "direct", "path": "severity"},
"entity.type": {"type": "direct", "path": "entity.type"},
"impactsSLO": {"type": "computed", "func": "compute_impact_slo"},
}The fields on which filtering can be done are defined in the field registry. There are two types of fields: direct and computed:
- Direct field means that the value of field can be parsed by following a path in nested dictionary. For example in the raw payload you have entity as the key and value is a dict containing more information and if you want to retrieve type then you provide the full path with a dot notation as shown above.
- Computed field means that some computation must be done on the payload to get the value of that field. Refer to the example
impactsSLOwhich is used to decide if a payload consisted of any impacted SLOs and use that as a filter.
CauselyBot provides support for certain operators to do the comparison between operand1 and operand2 for filtering:
equals: This is used to compare whether a specific field in a payload matches the given value:
webhooks:
- name: "slack-malfunction"
hook_type: "slack"
filters:
enabled: true
values:
- field: "name"
operator: "equals"
value: "Malfunction"in: This is used to check whether a specific field in a payload is present in the given set:
webhooks:
- name: "slack-severity"
hook_type: "slack"
filters:
enabled: true
values:
- field: "severity"
operator: "in"
value: ["High", "Critical"]CauselyBot also supports inverse operations like not_equals and not_in. Multiple filters can be provided for a webhook like:
webhooks:
- name: "slack-malfunction-slo"
hook_type: "slack"
filters:
enabled: true
values:
- field: "name"
operator: "equals"
value: "Malfunction"
- field: "impactsSLO"
operator: "equals"
value: TrueCauselyBot also supports providing multiple webhooks each with their own sets of filters:
webhooks:
- name: "slack-malfunction-slo"
hook_type: "slack"
url: "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX"
token: "xoxb-1234567890-1234567890-XXXXXXXXXXXXXXXXXXXXXXXX"
filters:
enabled: true
values:
- field: "name"
operator: "equals"
value: "Malfunction"
- field: "impactsSLO"
operator: "equals"
value: True
- name: "jira-critical-tickets"
hook_type: "jira"
url: "https://your-domain.atlassian.net/rest/api/3/issue"
token: "your-jira-token"
filters:
enabled: true
values:
- field: "severity"
operator: "in"
value: ["High", "Critical"]
- name: "teams-all-notifications"
hook_type: "teams"
url: "https://your-domain.webhook.office.com/webhookb2/..."
filters:
enabled: false # No filtering - receives all notificationsCauselyBot Docker images are pre-built and published to:
us-docker.pkg.dev/public-causely/public/bot:latest
If you need to build the image locally for development or custom modifications:
docker buildx build -t us-docker.pkg.dev/public-causely/public/bot --platform linux/amd64,linux/arm64 .To run the container locally:
docker run -p 5000:5000 \
-e AUTH_TOKEN=test-token-123 \
-e URL_DEBUG="https://debug.example.com/webhook" \
-e TOKEN_DEBUG="debug-token-456" \
-v $(pwd)/config.sample.yaml:/etc/causelybot/config.yaml \
us-docker.pkg.dev/public-causely/public/botThe webhook will be available at http://localhost:5000/webhook. You can send a test notification to the local webhook:
curl -X POST http://localhost:5000/webhook \
-H "Content-Type: application/json" \
-H "Authorization: Bearer test-token-123" \
-d '{
"name": "Test Problem",
"type": "ProblemDetected",
"entity": {
"id": "test-123",
"name": "test-service",
"type": "KubernetesService"
},
"severity": "High",
"timestamp": "2026-02-11T12:00:00Z"
}'Check the container logs to see the debug output with the formatted notification details.
