Set up DingTalk webhook notifications for Argo CD application events—sync failures, health degradation, and successful deployments—so your team is alerted automatically without polling the Argo CD UI.
How Argo CD Notifications works
Argo CD Notifications uses four concepts to route alerts:
| Concept | Role |
|---|---|
| Trigger | Defines *when* to send a notification (the condition) |
| Template | Defines *what* to send (the message content) |
| Notification service | Defines *where* to send it (email, Slack, GitHub, webhook, etc.) |
| Subscription | Defines *who* receives which applications or triggers |
A subscription links an application to one or more triggers. Each trigger selects a template. The template renders a payload for the configured notification service.
DingTalk is integrated as a webhook-based notification service. Configure all four concepts in the argocd-notifications-cm ConfigMap in the argocd namespace.
Prerequisites
Before you begin, make sure you have:
-
Fleet management enabled. See Fleet management.
-
The kubeconfig file of your Fleet instance obtained from the ACK One console, with kubectl connected to the Fleet instance. See Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.
Step 1: Create a DingTalk chatbot
Creating a DingTalk chatbot generates an exclusive webhook URL. The webhook can be associated with other services, such as Argo Workflows, to receive notifications. Argo CD Notifications uses this webhook to post messages to your group.
-
Open DingTalk and go to the group where you want to receive notifications.
-
Add a custom chatbot:
-
Click the
icon in the upper-right corner of the group, then click Bot in the panel. -
In the Robot Management panel, click Add Robot, then click the Custom card and click Add.
-
Enter a Chatbot name, configure Security Settings, and click Finished. You must select at least one security setting. We recommend that you select at least one of the following security settings: Additional Signature and IP Address. > Important: For the chatbot to receive messages from the workflow cluster, the cluster's virtual private cloud (VPC) must have Internet access. Configure an Internet NAT gateway for the cluster and enter the gateway's elastic IP address (EIP) in the IP Address security setting.
-
-
Copy and save the webhook URL displayed after the chatbot is created.
Step 2: Configure application notifications
Edit the argocd-notifications-cm ConfigMap to register the DingTalk webhook, define message templates, configure triggers, and set up subscriptions.
kubectl edit cm argocd-notifications-cm -n argocd
The configuration has four parts:
-
Register the notification service — points Argo CD to your DingTalk webhook.
-
Define templates — specify the markdown message body for each notification type.
-
Configure triggers — set the conditions that fire each template.
-
Add subscriptions — subscribe your applications to the triggers.
Before applying the ConfigMap, replace the following placeholders:
| Placeholder | Value | How to get it |
|---|---|---|
url in service.webhook.dingtalk |
Your DingTalk chatbot webhook URL | Copied in Step 1 |
argocdUrl in context |
Load balancer IP of Argo CD Server | Run: kubectl get svc -nargocd argocd-server -ojsonpath='{.status.loadBalancer.ingress[0].ip}' |
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
# 1. Register the DingTalk webhook as a notification service
service.webhook.dingtalk: |
url: https://oapi.dingtalk.com/robot/send?access_token=535a56d**********
headers:
- name: Content-Type
value: application/json
# Argo CD Server URL — used to build deep links in notification messages
context: |
argocdUrl: <argocd server lb ip>
# 2. Templates — define the DingTalk markdown message for each notification type
template.app-sync-change: |
webhook:
dingtalk:
method: POST
body: |
{
"msgtype": "markdown",
"markdown": {
"title":"Argo CD application status",
"text": "### Argo CD application status\n> - Application name: {{.app.metadata.name}}\n> - Status: {{ .app.status.operationState.phase}}\n> - Time:{{.app.status.operationState.finishedAt}}\n> - Application URL: [Click to access]({{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true) \n"
}
}
template.app-sync-status-unknown: |
webhook:
dingtalk:
method: POST
body: |
{
"msgtype": "markdown",
"markdown": {
"title":"Unknown Argo CD application",
"text": "### Unknown Argo CD application\n> - <font color=\"warning\">Application name</font>: {{.app.metadata.name}}\n> - <font color=\"warning\">Application status</font>: {{.app.status.sync.status}}\n> - <font color=\"warning\">Application health status</font>: {{.app.status.health.status}}\n> - <font color=\"warning\">Time</font>: {{.app.status.operationState.startedAt}}\n> - <font color=\"warning\">Application URL</font>: [Click to access the Argo CD UI]({{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true)"
}
}
template.app-sync-failed: |
webhook:
dingtalk:
method: POST
body: |
{
"msgtype": "markdown",
"markdown": {
"title":"Argo CD application release failure",
"text": "### Argo CD application release failure\n> - <font color=\"danger\">Application name</font>: {{.app.metadata.name}}\n> - <font color=\"danger\">Application status</font>: {{.app.status.operationState.phase}}\n> - <font color=\"danger\">Application health status</font>: {{.app.status.health.status}}\n> - <font color=\"danger\">Time</font>: {{.app.status.operationState.startedAt}}\n> - <font color=\"danger\">Application URL</font>: [Click to access the Argo CD UI]({{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true)"
}
}
# 3. Triggers — define conditions that fire each template
trigger.on-deployed: |
- description: Application is synced and healthy. Triggered once per commit.
oncePer: app.status.sync.revision
send: [app-sync-change]
# trigger condition
when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy'
trigger.on-health-degraded: |
- description: Application has degraded
send: [app-sync-change]
when: app.status.health.status == 'Degraded'
trigger.on-sync-failed: |
- description: Application syncing has failed
send: [app-sync-failed]
when: app.status.operationState != nil and app.status.operationState.phase in ['Error',
'Failed']
trigger.on-sync-status-unknown: |
- description: Application status is 'Unknown'
send: [app-sync-status-unknown]
when: app.status.sync.status == 'Unknown'
trigger.on-sync-running: |
- description: Application is being synced
send: [app-sync-change]
when: app.status.operationState != nil and app.status.operationState.phase in ['Running']
trigger.on-sync-succeeded: |
- description: Application syncing has succeeded
send: [app-sync-change]
when: app.status.operationState != nil and app.status.operationState.phase in ['Succeeded']
# 4. Subscriptions — subscribe applications to triggers
subscriptions: |
- recipients: [dingtalk]
triggers: [on-sync-failed, on-sync-succeeded, on-sync-status-unknown,on-deployed]
Triggers at a glance
| Trigger | Condition | Template used |
|---|---|---|
on-deployed |
Sync succeeded and health is Healthy (once per commit) | app-sync-change |
on-health-degraded |
Health status is Degraded | app-sync-change |
on-sync-failed |
Sync phase is Error or Failed | app-sync-failed |
on-sync-status-unknown |
Sync status is Unknown | app-sync-status-unknown |
on-sync-running |
Sync phase is Running | app-sync-change |
on-sync-succeeded |
Sync phase is Succeeded | app-sync-change |
Customize notifications (optional)
-
Per-trigger templates: to use a different message format for a specific trigger, define a new template object and reference it in that trigger's
sendlist. -
Message color: use
<font color=>xxxx</font>inside thetextfield to color parts of the message. The examples above usewarning(yellow) anddanger(red).