Routing Azure Monitor Alerts to Teams the Right Way
Azure Monitor's raw alert payloads are noisy and hard to read in Teams. Here's how to shape them into adaptive cards engineers can act on, not ignore.
- #microsoft-teams
- #azure-monitor
- #alerts
- #adaptive-cards
- #action-groups
- #observability
Wiring Azure Monitor to Teams looks like a ten-minute job: add a webhook to an action group, point it at a Teams workflow, done. Then the first alert lands and it’s a 4KB blob of JSON nobody can read, fires three times for one condition, and gives no way to acknowledge it. I’ve cleaned up this exact pipeline at more than one shop. The trick isn’t the connection — it’s the shaping. Here’s how to turn Azure Monitor’s common-schema payload into adaptive cards engineers actually act on.
Use the common alert schema, always
Azure Monitor has historically sent different JSON shapes for metric alerts, log alerts, and activity-log alerts. Trying to parse all three is misery. Enable the common alert schema on the action group and every alert type arrives in one predictable envelope:
{
"data": {
"essentials": {
"alertId": "...",
"alertRule": "checkout-p99-latency",
"severity": "Sev2",
"monitorCondition": "Fired",
"signalType": "Metric",
"firedDateTime": "2026-06-12T02:09:00Z",
"targetResource": "/subscriptions/.../checkout-aks"
},
"alertContext": { /* signal-specific detail */ }
}
}
Now you parse essentials once and branch on alertContext only when you need the gory detail. This single setting removes most of the pain.
Don’t point the action group straight at a channel webhook
The classic setup sends the webhook directly to a Teams incoming webhook. Two problems: the old connector-style webhooks are being retired in favor of Workflows, and a raw webhook can’t transform the payload — you get whatever Azure sends. Put a thin transform in the middle. Either a Teams Workflow (Power Automate) that parses and builds the card, or a small function that receives the Azure webhook and posts a shaped adaptive card via the Bot Framework. I prefer the function when I want real logic (dedup, routing, enrichment); a Workflow is fine for straight reshaping.
Shape the card around monitorCondition
The most important field is monitorCondition — Fired vs Resolved. Color and title the card on it so a glance tells the story:
function alertCard(essentials, ctx) {
const resolved = essentials.monitorCondition === "Resolved";
return {
type: "AdaptiveCard",
version: "1.5",
body: [
{
type: "Container",
style: resolved ? "good" : "attention",
items: [
{
type: "TextBlock", weight: "Bolder", size: "Large",
text: `${resolved ? "✅ Resolved" : "🔥 Fired"} · ${essentials.alertRule}`,
},
{
type: "FactSet",
facts: [
{ title: "Severity", value: essentials.severity },
{ title: "Signal", value: essentials.signalType },
{ title: "Resource", value: shortName(essentials.targetResource) },
{ title: "Time", value: essentials.firedDateTime },
],
},
],
},
],
actions: [
{ type: "Action.OpenUrl", title: "Open in Azure Portal", url: portalLink(essentials.alertId) },
{ type: "Action.Submit", title: "Acknowledge", data: { ack: essentials.alertId } },
],
};
}
shortName trims the resource ID to something human — nobody reads /subscriptions/8a.../resourceGroups/.../checkout-aks at a glance. The Acknowledge button gives your bot a way to record who’s on it.
Update the same message on resolve, don’t post a new one
The single biggest noise reducer: when an alert resolves, edit the original fired card instead of posting a fresh “resolved” message. Capture the message ID when you post the fired card, key it by alertId, and on the resolve webhook, update that card to green. The channel ends up with one card per incident that flips from red to green — instead of two cards per incident and a channel that scrolls forever.
const posted = await postCard(channelRef, alertCard(essentials, ctx));
await alertMsgStore.put(essentials.alertId, posted.id);
// later, on Resolved:
const msgId = await alertMsgStore.get(essentials.alertId);
await updateCard(channelRef, msgId, alertCard(resolvedEssentials, ctx));
Route by severity and resource
Action groups are dumb pipes; your transform is where routing lives. Two cheap rules:
- Severity gates the destination. Sev0/Sev1 go to the on-call channel and
@mentionthe rotation; Sev3/Sev4 go to a low-priority “noise” channel people check on their schedule. Dumping everything in one channel trains people to ignore all of it. - Resource tags pick the team. Read the resource group or a tag off
targetResourceand route to the owning team’s channel. The team that ownspaymentsshouldn’t be readingcheckoutalerts.
Suppress the flap
Metric alerts flap — a threshold hovers and fires/resolves every few minutes. Two guardrails:
- Tune at the source. Set the alert rule’s aggregation window and
Auto-resolvethresholds so the signal is stable before it ever reaches you. Most flapping is a too-tight evaluation window. - Debounce in the transform. Hold a brief suppression window per
alertIdso a fire→resolve→fire within, say, 90 seconds collapses into one notification. Cheaper than retraining humans to trust the channel.
Where this fits
The connection from Azure Monitor to Teams is trivial; the signal quality is the whole job. Turn on the common schema, put a transform in the middle, shape the card around fired-vs-resolved, update one message instead of spamming new ones, and route by severity and ownership. Do that and the alerts channel becomes something people actually watch. For adaptive card templates and transform-function snippets, see the prompt library, and find more alert-routing patterns in the Microsoft Teams category.
Azure Monitor schema fields and connector behavior change over time; validate the common alert schema and Workflows webhook setup against current Azure docs.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.