| name | slack-webhook |
| description | Use when sending Slack alerts or notifications. Automatically uses the configured SLACK_WEBHOOK_URL from environment. |
Slack Webhook Integration
Send alerts and notifications to Slack using the configured webhook.
Quick Start
The webhook URL is automatically loaded from the SLACK_WEBHOOK_URL environment variable.
import os
import json
from urllib.request import Request, urlopen
def send_slack_alert(message: dict) -> bool:
"""Send a message to Slack via webhook.
Args:
message: Slack Block Kit message payload
Returns:
True if sent successfully, False otherwise
"""
webhook_url = os.environ.get('SLACK_WEBHOOK_URL')
if not webhook_url:
raise ValueError("SLACK_WEBHOOK_URL environment variable not set")
request = Request(
webhook_url,
data=json.dumps(message).encode('utf-8'),
headers={'Content-Type': 'application/json'}
)
with urlopen(request, timeout=10) as response:
return response.status == 200
Message Formats
Simple Text Message
message = {
"text": "Hello from the agent!"
}
send_slack_alert(message)
Alert with Block Kit (Recommended)
message = {
"blocks": [
{
"type": "header",
"text": {"type": "plain_text", "text": "š“ Anomaly Detected"}
},
{
"type": "section",
"fields": [
{"type": "mrkdwn", "text": "*Metric:*\nConversion Rate"},
{"type": "mrkdwn", "text": "*Severity:*\nCritical"}
]
},
{
"type": "section",
"fields": [
{"type": "mrkdwn", "text": "*Expected:*\n4.2%"},
{"type": "mrkdwn", "text": "*Actual:*\n1.8%"}
]
},
{"type": "divider"},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Potential Causes:*\n⢠Checkout flow issue\n⢠Payment gateway error\n⢠Landing page test impact"
}
},
{
"type": "context",
"elements": [
{"type": "mrkdwn", "text": "š¤ Alert generated by AI Agent"}
]
}
]
}
Anomaly Alert Template
def build_anomaly_alert(
metric_name: str,
date: str,
expected: float,
actual: float,
severity: str = "Warning",
potential_causes: list = None
) -> dict:
"""Build a formatted anomaly alert message.
Args:
metric_name: Name of the metric (e.g., "Conversion Rate")
date: Date of the anomaly
expected: Expected value
actual: Actual value
severity: "Critical" or "Warning"
potential_causes: List of potential cause strings
Returns:
Slack Block Kit message payload
"""
emoji = "š“" if severity == "Critical" else "š”"
pct_change = ((actual - expected) / expected) * 100
direction = "drop" if pct_change < 0 else "spike"
blocks = [
{
"type": "header",
"text": {"type": "plain_text", "text": f"{emoji} Anomaly Detected: {metric_name}"}
},
{
"type": "section",
"fields": [
{"type": "mrkdwn", "text": f"*Date:*\n{date}"},
{"type": "mrkdwn", "text": f"*Severity:*\n{severity}"}
]
},
{
"type": "section",
"fields": [
{"type": "mrkdwn", "text": f"*Expected:*\n{expected:,.2f}"},
{"type": "mrkdwn", "text": f"*Actual:*\n{actual:,.2f}"}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"*Change:* {pct_change:+.1f}% {direction}"
}
}
]
if potential_causes:
causes_text = "\n".join([f"⢠{cause}" for cause in potential_causes])
blocks.extend([
{"type": "divider"},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"*Potential Causes:*\n{causes_text}"
}
}
])
blocks.append({
"type": "context",
"elements": [
{"type": "mrkdwn", "text": "š¤ Alert generated by AI Agent"}
]
})
return {"blocks": blocks}
Usage Example
# Build and send an anomaly alert
alert = build_anomaly_alert(
metric_name="Trial Conversion Rate",
date="2025-11-28",
expected=37.6,
actual=10.5,
severity="Critical",
potential_causes=[
"Onboarding flow broken",
"Integration setup failing",
"New user segment with different behavior"
]
)
success = send_slack_alert(alert)
if success:
print("ā
Alert sent to Slack")
else:
print("ā Failed to send alert")
Testing
To test without sending (dry run):
import json
print(json.dumps(alert, indent=2))
Error Handling
from urllib.error import URLError, HTTPError
try:
send_slack_alert(message)
except ValueError as e:
print(f"Configuration error: {e}")
except HTTPError as e:
print(f"Slack API error: {e.code} - {e.reason}")
except URLError as e:
print(f"Network error: {e.reason}")