diff --git a/apps/landing/messages/en.json b/apps/landing/messages/en.json
index c781614bb..aafa4c72c 100644
--- a/apps/landing/messages/en.json
+++ b/apps/landing/messages/en.json
@@ -293,15 +293,21 @@
"alert_badge": "Alerting",
"alert_heading": "Alerts with the context attached",
- "alert_rules_title": "Alert rules",
- "alert_rules_desc": "7 built-in signal types \u2014 error rate, P95/P99 latency, Apdex, throughput, custom metrics, and custom queries. With severity levels, incident tracking, and auto-resolution.",
- "alert_route_title": "Route everywhere",
- "alert_route_desc": "Push alerts to Slack, Discord, PagerDuty, or any webhook. Your team gets notified where they already work.",
+ "alert_rules_title": "From error rate to raw SQL",
+ "alert_rules_desc": "Error rate, P95/P99 latency, Apdex, throughput, any metric \u2014 and when the presets run out, write the query yourself. You set the window, the threshold, and the severity.",
+ "alert_route_title": "Paged where you work",
+ "alert_route_desc": "Slack, Discord, PagerDuty, email, Hazel, or any webhook. Wire one rule to as many destinations as you want \u2014 on-call gets paged while the channel gets the summary.",
"alert_firing": "Firing",
"alert_triggered_ago": "Triggered 34s ago",
"alert_view": "View in Maple",
"alert_acknowledge": "Acknowledge",
"alert_webhook_note": "+ any custom webhook endpoint",
+ "alert_lede": "Threshold and anomaly rules watch your live telemetry around the clock. When one fires, the page arrives with the trace that tripped it, the blast radius, and a one-click AI diagnosis \u2014 not just a number that crossed a line.",
+ "alert_incidents_title": "Incidents, not noise",
+ "alert_incidents_desc": "A firing rule opens an incident, renotifies while it's still hot, and auto-resolves when the numbers recover. Fan out per group. Preview against real history before you ship it.",
+ "alert_ai_note": "AI diagnosis linked in every notification",
+ "alert_dest_email": "Email",
+ "alert_dest_webhook": "Webhook",
"how_badge": "Getting started",
"how_heading": "Three steps to observability",
@@ -328,6 +334,7 @@
"footer_metrics_dashboards": "Metrics & Dashboards",
"footer_service_catalog": "Service Catalog",
"footer_error_tracking": "Error Tracking",
+ "footer_alerting": "Alerting",
"footer_ai_mcp": "AI & MCP",
"footer_kubernetes": "Kubernetes Monitoring",
"footer_compare": "Compare",
diff --git a/apps/landing/messages/ja.json b/apps/landing/messages/ja.json
index 76610765f..5bc90bb32 100644
--- a/apps/landing/messages/ja.json
+++ b/apps/landing/messages/ja.json
@@ -293,15 +293,21 @@
"alert_badge": "\u30a2\u30e9\u30fc\u30c8",
"alert_heading": "\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u4ed8\u304d\u306e\u30a2\u30e9\u30fc\u30c8",
- "alert_rules_title": "\u30a2\u30e9\u30fc\u30c8\u30eb\u30fc\u30eb",
- "alert_rules_desc": "\u30a8\u30e9\u30fc\u7387\u3001P95/P99\u30ec\u30a4\u30c6\u30f3\u30b7\u3001Apdex\u3001\u30b9\u30eb\u30fc\u30d7\u30c3\u30c8\u3001\u30ab\u30b9\u30bf\u30e0\u30e1\u30c8\u30ea\u30af\u30b9\u3001\u30ab\u30b9\u30bf\u30e0\u30af\u30a8\u30ea\u306e7\u7a2e\u985e\u306e\u7d44\u307f\u8fbc\u307f\u30b7\u30b0\u30ca\u30eb\u3002\u91cd\u5927\u5ea6\u30ec\u30d9\u30eb\u3001\u30a4\u30f3\u30b7\u30c7\u30f3\u30c8\u8ffd\u8de1\u3001\u81ea\u52d5\u89e3\u6c7a\u4ed8\u304d\u3002",
- "alert_route_title": "\u3069\u3053\u3078\u3067\u3082\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0",
- "alert_route_desc": "\u30a2\u30e9\u30fc\u30c8\u3092Slack\u3001Discord\u3001PagerDuty\u3001\u4efb\u610f\u306eWebhook\u3078\u3002\u30c1\u30fc\u30e0\u304c\u666e\u6bb5\u3044\u308b\u5834\u6240\u306b\u901a\u77e5\u304c\u5c4a\u304d\u307e\u3059\u3002",
+ "alert_rules_title": "\u30a8\u30e9\u30fc\u7387\u304b\u3089\u751fSQL\u307e\u3067",
+ "alert_rules_desc": "\u30a8\u30e9\u30fc\u7387\u3001P95/P99\u30ec\u30a4\u30c6\u30f3\u30b7\u3001Apdex\u3001\u30b9\u30eb\u30fc\u30d7\u30c3\u30c8\u3001\u4efb\u610f\u306e\u30e1\u30c8\u30ea\u30af\u30b9\u3002\u30d7\u30ea\u30bb\u30c3\u30c8\u3067\u8db3\u308a\u306a\u3051\u308c\u3070\u3001\u30af\u30a8\u30ea\u3092\u81ea\u5206\u3067\u66f8\u3051\u307e\u3059\u3002\u30a6\u30a3\u30f3\u30c9\u30a6\u3001\u3057\u304d\u3044\u5024\u3001\u91cd\u5927\u5ea6\u306f\u3059\u3079\u3066\u81ea\u7531\u306b\u3002",
+ "alert_route_title": "\u666e\u6bb5\u3044\u308b\u5834\u6240\u306b\u901a\u77e5",
+ "alert_route_desc": "Slack\u3001Discord\u3001PagerDuty\u3001\u30e1\u30fc\u30eb\u3001Hazel\u3001\u4efb\u610f\u306eWebhook\u30021\u3064\u306e\u30eb\u30fc\u30eb\u3092\u8907\u6570\u306e\u5b9b\u5148\u3078 \u2014 \u30aa\u30f3\u30b3\u30fc\u30eb\u306b\u306f\u30da\u30fc\u30b8\u3001\u30c1\u30e3\u30f3\u30cd\u30eb\u306b\u306f\u30b5\u30de\u30ea\u30fc\u3092\u3002",
"alert_firing": "\u767a\u706b\u4e2d",
"alert_triggered_ago": "34\u79d2\u524d\u306b\u767a\u706b",
"alert_view": "Maple\u3067\u8868\u793a",
"alert_acknowledge": "\u78ba\u8a8d",
"alert_webhook_note": "+ \u4efb\u610f\u306e\u30ab\u30b9\u30bf\u30e0Webhook\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8",
+ "alert_lede": "\u3057\u304d\u3044\u5024\u3068\u7570\u5e38\u691c\u77e5\u306e\u30eb\u30fc\u30eb\u304c\u3001\u30e9\u30a4\u30d6\u306a\u30c6\u30ec\u30e1\u30c8\u30ea\u3092\u5e38\u6642\u76e3\u8996\u3002\u767a\u706b\u3057\u305f\u901a\u77e5\u306b\u306f\u3001\u539f\u56e0\u3068\u306a\u3063\u305f\u30c8\u30ec\u30fc\u30b9\u3001\u5f71\u97ff\u7bc4\u56f2\u3001\u30ef\u30f3\u30af\u30ea\u30c3\u30af\u306eAI\u8a3a\u65ad\u304c\u6dfb\u4ed8\u3055\u308c\u307e\u3059 \u2014 \u6570\u5b57\u304c\u5c4a\u304f\u3060\u3051\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002",
+ "alert_incidents_title": "\u30ce\u30a4\u30ba\u3067\u306f\u306a\u304f\u30a4\u30f3\u30b7\u30c7\u30f3\u30c8",
+ "alert_incidents_desc": "\u767a\u706b\u3057\u305f\u30eb\u30fc\u30eb\u306f\u30a4\u30f3\u30b7\u30c7\u30f3\u30c8\u3092\u958b\u304d\u3001\u7d9a\u304f\u9593\u306f\u518d\u901a\u77e5\u3057\u3001\u6570\u5024\u304c\u56de\u5fa9\u3059\u308c\u3070\u81ea\u52d5\u3067\u89e3\u6c7a\u3002\u30b0\u30eb\u30fc\u30d7\u3054\u3068\u306b\u30d5\u30a1\u30f3\u30a2\u30a6\u30c8\u3057\u3001\u4fdd\u5b58\u524d\u306b\u5b9f\u30c7\u30fc\u30bf\u3067\u30d7\u30ec\u30d3\u30e5\u30fc\u3067\u304d\u307e\u3059\u3002",
+ "alert_ai_note": "\u3059\u3079\u3066\u306e\u901a\u77e5\u306bAI\u8a3a\u65ad\u30ea\u30f3\u30af\u4ed8\u304d",
+ "alert_dest_email": "\u30e1\u30fc\u30eb",
+ "alert_dest_webhook": "Webhook",
"how_badge": "\u306f\u3058\u3081\u304b\u305f",
"how_heading": "3\u30b9\u30c6\u30c3\u30d7\u3067\u30aa\u30d6\u30b6\u30fc\u30d0\u30d3\u30ea\u30c6\u30a3",
@@ -328,6 +334,7 @@
"footer_metrics_dashboards": "\u30e1\u30c8\u30ea\u30af\u30b9 & \u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9",
"footer_service_catalog": "\u30b5\u30fc\u30d3\u30b9\u30ab\u30bf\u30ed\u30b0",
"footer_error_tracking": "\u30a8\u30e9\u30fc\u30c8\u30e9\u30c3\u30ad\u30f3\u30b0",
+ "footer_alerting": "\u30a2\u30e9\u30fc\u30c8",
"footer_ai_mcp": "AI & MCP",
"footer_kubernetes": "Kubernetes\u76e3\u8996",
"footer_compare": "\u6bd4\u8f03",
diff --git a/apps/landing/messages/ko.json b/apps/landing/messages/ko.json
index 5848bd885..143052ef8 100644
--- a/apps/landing/messages/ko.json
+++ b/apps/landing/messages/ko.json
@@ -293,15 +293,21 @@
"alert_badge": "\uc54c\ub9bc",
"alert_heading": "\ucee8\ud14d\uc2a4\ud2b8\uac00 \ubd99\uc5b4 \uc788\ub294 \uc54c\ub9bc",
- "alert_rules_title": "\uc54c\ub9bc \uaddc\uce59",
- "alert_rules_desc": "\uc5d0\ub7ec\uc728, P95/P99 \ub808\uc774\ud134\uc2dc, Apdex, \ucc98\ub9ac\ub7c9, \ucee4\uc2a4\ud140 \uba54\ud2b8\ub9ad, \ucee4\uc2a4\ud140 \ucffc\ub9ac \ub4f1 7\uac00\uc9c0 \ub0b4\uc7a5 \uc2dc\uadf8\ub110 \uc720\ud615. \uc2ec\uac01\ub3c4 \ub808\ubca8, \uc778\uc2dc\ub358\ud2b8 \ucd94\uc801, \uc790\ub3d9 \ud574\uacb0 \ud3ec\ud568.",
- "alert_route_title": "\uc5b4\ub514\ub85c\ub4e0 \ub77c\uc6b0\ud305",
- "alert_route_desc": "\uc54c\ub9bc\uc744 Slack, Discord, PagerDuty \ub610\ub294 \uc784\uc758\uc758 \uc6f9\ud6c5\uc73c\ub85c \ubcf4\ub0b4\uc138\uc694. \ud300\uc774 \uc774\ubbf8 \uc77c\ud558\ub294 \uacf3\uc73c\ub85c \uc54c\ub9bc\uc774 \uac11\ub2c8\ub2e4.",
+ "alert_rules_title": "\uc5d0\ub7ec\uc728\ubd80\ud130 raw SQL\uae4c\uc9c0",
+ "alert_rules_desc": "\uc5d0\ub7ec\uc728, P95/P99 \ub808\uc774\ud134\uc2dc, Apdex, \ucc98\ub9ac\ub7c9, \uc784\uc758\uc758 \uba54\ud2b8\ub9ad \u2014 \ud504\ub9ac\uc14b\uc73c\ub85c \ubd80\uc871\ud558\uba74 \ucffc\ub9ac\ub97c \uc9c1\uc811 \uc791\uc131\ud558\uc138\uc694. \uc708\ub3c4\uc6b0, \uc784\uacc4\uac12, \uc2ec\uac01\ub3c4\ub294 \ubaa8\ub450 \uc790\uc720\ub86d\uac8c.",
+ "alert_route_title": "\ud300\uc774 \uc77c\ud558\ub294 \uacf3\uc73c\ub85c",
+ "alert_route_desc": "Slack, Discord, PagerDuty, \uc774\uba54\uc77c, Hazel, \uc784\uc758\uc758 \uc6f9\ud6c5. \ud558\ub098\uc758 \uaddc\uce59\uc744 \uc5ec\ub7ec \ub300\uc0c1\uc5d0 \uc5f0\uacb0\ud558\uc138\uc694 \u2014 \uc628\ucf5c\uc740 \ud398\uc774\uc9c0\ub97c, \ucc44\ub110\uc740 \uc694\uc57d\uc744 \ubc1b\uc2b5\ub2c8\ub2e4.",
"alert_firing": "\ubc1c\uc0dd \uc911",
"alert_triggered_ago": "34\ucd08 \uc804 \ubc1c\uc0dd",
"alert_view": "Maple\uc5d0\uc11c \ubcf4\uae30",
"alert_acknowledge": "\ud655\uc778",
"alert_webhook_note": "+ \uc784\uc758\uc758 \ucee4\uc2a4\ud140 \uc6f9\ud6c5 \uc5d4\ub4dc\ud3ec\uc778\ud2b8",
+ "alert_lede": "\uc784\uacc4\uac12 \ubc0f \uc774\uc0c1 \ud0d0\uc9c0 \uaddc\uce59\uc774 \uc2e4\uc2dc\uac04 \ud154\ub808\uba54\ud2b8\ub9ac\ub97c \uc0c1\uc2dc \uac10\uc2dc\ud569\ub2c8\ub2e4. \uc54c\ub9bc\uc774 \ubc1c\uc0dd\ud558\uba74 \uc6d0\uc778\uc774 \ub41c \ud2b8\ub808\uc774\uc2a4, \uc601\ud5a5 \ubc94\uc704, \uc6d0\ud074\ub9ad AI \uc9c4\ub2e8\uc774 \ud568\uaed8 \ub3c4\ucc29\ud569\ub2c8\ub2e4 \u2014 \uc22b\uc790 \ud558\ub098\ub9cc \uc624\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.",
+ "alert_incidents_title": "\ub178\uc774\uc988\uac00 \uc544\ub2cc \uc778\uc2dc\ub358\ud2b8",
+ "alert_incidents_desc": "\ubc1c\uc0dd\ud55c \uaddc\uce59\uc740 \uc778\uc2dc\ub358\ud2b8\ub97c \uc5f4\uace0, \uc9c0\uc18d\ub418\ub294 \ub3d9\uc548 \uc7ac\uc54c\ub9bc\ud558\uba70, \uc218\uce58\uac00 \ud68c\ubcf5\ub418\uba74 \uc790\ub3d9\uc73c\ub85c \ud574\uacb0\ub429\ub2c8\ub2e4. \uadf8\ub8f9\ubcc4\ub85c \ud655\uc7a5\ud558\uace0, \uc800\uc7a5 \uc804\uc5d0 \uc2e4\uc81c \ub370\uc774\ud130\ub85c \ubbf8\ub9ac \ud655\uc778\ud558\uc138\uc694.",
+ "alert_ai_note": "\ubaa8\ub4e0 \uc54c\ub9bc\uc5d0 AI \uc9c4\ub2e8 \ub9c1\ud06c \ud3ec\ud568",
+ "alert_dest_email": "\uc774\uba54\uc77c",
+ "alert_dest_webhook": "\uc6f9\ud6c5",
"how_badge": "\uc2dc\uc791\ud558\uae30",
"how_heading": "3\ub2e8\uacc4\ub85c \uc635\uc800\ubc84\ube4c\ub9ac\ud2f0",
@@ -328,6 +334,7 @@
"footer_metrics_dashboards": "\uba54\ud2b8\ub9ad & \ub300\uc2dc\ubcf4\ub4dc",
"footer_service_catalog": "\uc11c\ube44\uc2a4 \uce74\ud0c8\ub85c\uadf8",
"footer_error_tracking": "\uc5d0\ub7ec \ucd94\uc801",
+ "footer_alerting": "\uc54c\ub9bc",
"footer_ai_mcp": "AI & MCP",
"footer_kubernetes": "Kubernetes \ubaa8\ub2c8\ud130\ub9c1",
"footer_compare": "\ube44\uad50",
diff --git a/apps/landing/src/components/Alerting.astro b/apps/landing/src/components/Alerting.astro
new file mode 100644
index 000000000..a94d62c99
--- /dev/null
+++ b/apps/landing/src/components/Alerting.astro
@@ -0,0 +1,152 @@
+---
+/**
+ * Homepage section — Alerting.
+ * Centered "stage" layout (like the Kubernetes section): eyebrow pill,
+ * gradient heading, the firing-incident artifact, a row of every supported
+ * notification destination, and a 3-card feature strip.
+ */
+import { getRelativeLocaleUrl } from "astro:i18n";
+import LiveAlertFeed from "./live/LiveAlertFeed.astro";
+import * as m from "../paraglide/messages";
+
+const locale = Astro.currentLocale ?? "en";
+const featurePath = getRelativeLocaleUrl(locale, "/features/alerting");
+
+const features = [
+ { title: m.alert_rules_title(), desc: m.alert_rules_desc() },
+ { title: m.alert_route_title(), desc: m.alert_route_desc() },
+ { title: m.alert_incidents_title(), desc: m.alert_incidents_desc() },
+];
+---
+
+
+
+
+
+
+
+
+
+
+ {m.alert_badge()}
+
+
+
+ {m.alert_heading()}
+
+
+ {m.alert_lede()}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Slack
+
+
+
+
+
+ Discord
+
+
+
+
+
+
+ {m.alert_dest_email()}
+
+
+
+
+
+ PagerDuty
+
+
+
+
+
+ {m.alert_dest_webhook()}
+
+
+
+
+
+ Hazel
+
+
+
{m.alert_webhook_note()}
+
+
+
+ {
+ features.map((f) => (
+
+ ))
+ }
+
+
+
diff --git a/apps/landing/src/components/Footer.astro b/apps/landing/src/components/Footer.astro
index 293286968..5be7cee8d 100644
--- a/apps/landing/src/components/Footer.astro
+++ b/apps/landing/src/components/Footer.astro
@@ -58,6 +58,7 @@ const stars = await getGitHubStars();
{m.footer_metrics_dashboards()}
{m.footer_service_catalog()}
{m.footer_error_tracking()}
+ {m.footer_alerting()}
{m.footer_ai_mcp()}
{m.footer_kubernetes()}
diff --git a/apps/landing/src/components/RelatedFeatures.astro b/apps/landing/src/components/RelatedFeatures.astro
index e49f158af..c8e7d411e 100644
--- a/apps/landing/src/components/RelatedFeatures.astro
+++ b/apps/landing/src/components/RelatedFeatures.astro
@@ -16,6 +16,7 @@ const features = [
{ slug: "metrics-dashboards", label: "Metrics & Dashboards", description: "Track every signal that matters" },
{ slug: "service-catalog", label: "Service Catalog & Map", description: "All your services at a glance" },
{ slug: "error-tracking", label: "Error Tracking", description: "Find and fix errors faster" },
+ { slug: "alerting", label: "Alerting", description: "Rules, incidents, and every destination" },
{ slug: "ai-mcp-integration", label: "AI & MCP Integration", description: "AI-powered diagnostics via MCP" },
{ slug: "kubernetes-monitoring", label: "Kubernetes Monitoring", description: "Pods, nodes, and workloads alongside spans" },
];
diff --git a/apps/landing/src/components/live/LiveAlertFeed.astro b/apps/landing/src/components/live/LiveAlertFeed.astro
new file mode 100644
index 000000000..c6d89cd7f
--- /dev/null
+++ b/apps/landing/src/components/live/LiveAlertFeed.astro
@@ -0,0 +1,97 @@
+---
+/**
+ * LiveAlertFeed — a firing alert incident, frozen mid-page.
+ * Fully SSR'd (no client island): an alert is a single moment in time, so a
+ * static card reads better than a loop. The only motion is a CSS pulse on the
+ * severity dot, gated on prefers-reduced-motion.
+ */
+import * as m from "../../paraglide/messages";
+---
+
+
+
+ alerts · incident feed
+
+
+ LIVE
+
+
+
+
+
+
+
+
+ {m.alert_firing()}
+
+ {m.alert_triggered_ago()}
+
+
+
+
+ payments · error rate > 2% for 5m
+ ·
+ 4.7%
+ (threshold 2%)
+
+
+
+
+
top endpoint: POST /v1/charges · 142 errors
+
sample trace: trace_9f3c · order 8421
+
group: region=eu-west-1 · 1 of 3 groups firing
+
+
+
+
+
+ {m.alert_view()}
+
+
+ {m.alert_acknowledge()}
+
+
+
+
+
+
→ slack #incidents · 200 OK
+
→ pagerduty · incident opened
+
+
+
+
+ 1 firing · 12 resolved this week
+ {m.alert_ai_note()}
+
+
+
+
diff --git a/apps/landing/src/pages/features/alerting.astro b/apps/landing/src/pages/features/alerting.astro
new file mode 100644
index 000000000..fb7344947
--- /dev/null
+++ b/apps/landing/src/pages/features/alerting.astro
@@ -0,0 +1,462 @@
+---
+import Layout from "../../layouts/Layout.astro";
+import Nav from "../../components/Nav.astro";
+import FeatureHero from "../../components/FeatureHero.astro";
+import FeatureDetailGrid from "../../components/FeatureDetailGrid.astro";
+import RelatedFeatures from "../../components/RelatedFeatures.astro";
+import SeoHead from "../../components/SeoHead.astro";
+import Breadcrumb from "../../components/Breadcrumb.astro";
+import BottomCTA from "../../components/BottomCTA.astro";
+import FAQ from "../../components/FAQ.astro";
+import Footer from "../../components/Footer.astro";
+import LiveAlertFeed from "../../components/live/LiveAlertFeed.astro";
+
+const pageTitle = "Alerting | Maple";
+const pageDescription =
+ "Threshold and anomaly alerting for OpenTelemetry data. Route notifications to Slack, Discord, PagerDuty, email, Hazel, or any webhook — with incidents, group fan-out, and one-click AI diagnosis.";
+
+// Stated plainly for AI extraction: these are the supported notification destinations.
+const destinations = [
+ {
+ name: "Slack",
+ description: "Post alerts to a Slack channel via incoming webhook.",
+ delivery: "→ #incidents · 200 OK",
+ },
+ {
+ name: "Discord",
+ description: "Send alerts to a Discord channel via webhook.",
+ delivery: "→ #alerts · 204",
+ },
+ {
+ name: "PagerDuty",
+ description: "Trigger incidents through a PagerDuty Events API v2 integration key.",
+ delivery: "→ Events API v2 · trigger",
+ },
+ {
+ name: "Email",
+ description: "Email workspace members directly — no external service required.",
+ delivery: "→ oncall@acme.dev",
+ },
+ {
+ name: "Webhook",
+ description: "POST a signed JSON payload to any HTTPS endpoint you control.",
+ delivery: "→ POST /hooks/maple · signed",
+ },
+ {
+ name: "Hazel",
+ description: "Connect via OAuth or webhook and route alerts into Hazel.",
+ delivery: "→ routed · OAuth",
+ },
+];
+
+// Group fan-out rows — one rule, one incident per group-by value.
+const fanoutGroups = [
+ { group: "region=eu-west-1", value: "4.7%", firing: true, delivery: "slack #incidents · pagerduty" },
+ { group: "region=us-east-1", value: "0.8%", firing: false, delivery: "quiet" },
+ { group: "region=ap-south-1", value: "1.1%", firing: false, delivery: "quiet" },
+];
+
+// Incident lifecycle — timestamps from the same incident as the demo card.
+const lifecycle = [
+ {
+ time: "14:35:08",
+ title: "Triggered",
+ desc: "error rate 4.7% ≥ 2%, sustained for 5m — incident opened",
+ color: "var(--severity-error)",
+ },
+ {
+ time: "14:35:10",
+ title: "Notified",
+ desc: "slack #incidents · pagerduty — 2s after trigger, AI diagnosis link attached",
+ color: "var(--primary)",
+ },
+ {
+ time: "14:50:08",
+ title: "Renotified",
+ desc: "still firing at 3.9% — same incident, no duplicate",
+ color: "var(--severity-warn)",
+ },
+ {
+ time: "15:04:20",
+ title: "Auto-resolved",
+ desc: "back under 2% for 10m — resolution posted to every destination",
+ color: "var(--severity-info)",
+ },
+];
+
+const alertingFaqs = [
+ {
+ question: "What alerting destinations does Maple support?",
+ answer:
+ "Maple delivers alert notifications to Slack, Discord, PagerDuty, email, Hazel, and any custom webhook. A single alert rule can notify multiple destinations at once — page on-call in PagerDuty while a summary lands in Slack.",
+ },
+ {
+ question: "What can I alert on?",
+ answer:
+ "Built-in signals cover error rate, P95/P99 latency, Apdex, and throughput, plus any custom metric. When the presets aren't enough, you can alert on a custom query with full comparator control — above, below, equal, or inside/outside a range.",
+ },
+ {
+ question: "Does Maple support anomaly detection?",
+ answer:
+ "Yes. Alongside threshold rules, Maple runs anomaly detection over your telemetry and can open triage issues automatically when a signal deviates from its baseline.",
+ },
+ {
+ question: "How does Maple reduce alert noise?",
+ answer:
+ "A firing rule opens an incident that renotifies while it's still active and auto-resolves when the numbers recover. Rules can fan out per group-by value so one rule covers every region or service, and you can preview any rule against real historical data before saving it.",
+ },
+ {
+ question: "Do alert notifications include AI diagnosis?",
+ answer:
+ "Every notification includes a link that opens an AI diagnosis of the incident in Maple, pre-loaded with the relevant traces, errors, and context.",
+ },
+];
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rule evaluation
+
+
+ From threshold breach to incident
+
+
+ The evaluator watches the signal, not snapshots: a breach has to hold for the full persistence
+ window before anything pages. Preview any rule against real history and see exactly where it
+ would have fired — before you save it.
+
+
+
+
+
+
+
+
+
+ alerts · rule preview
+ last 45m
+
+
+ rule
+ error_rate {service= "payments" }
+ > 2%
+ for 5m
+ · group by region
+
+
+
+
+
+
+
+
+ 5%
+ 0%
+
+
+
+
+
+
+ threshold 2%
+
+
+
+
+
+
+
+
+
+ fired · 14:35
+
+
+
+
+
+ for 5m
+
+
+ 14:00
+ 14:15
+ 14:30
+ 14:45
+
+
+
+ preview: this rule would have fired once in the shown window · region=eu-west-1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5m elapsed — incident opened
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Group fan-out
+
+
+ One rule watches every region
+
+
+ Add a group-by and the rule evaluates each value independently. Every region, service, or
+ endpoint gets its own incident — a spike in eu-west-1 never hides behind a healthy global
+ average, and only the group that breached pages anyone.
+
+
+
+
+
+ alerts · group fan-out
+ 3 groups · 1 firing
+
+
+ {
+ fanoutGroups.map((g) => (
+
+
+ {g.group}
+
+ {g.value}
+
+
+ {g.firing ? (
+ <>
+ firing
+ · {g.delivery}
+ >
+ ) : (
+ ok · {g.delivery}
+ )}
+
+
+ ))
+ }
+
+
+ each group opens and resolves its own incident
+
+
+
+
+
+
+
+
+
+
+ Destinations
+
+
+ Every destination Maple supports
+
+
+ Alert rules deliver to Slack, Discord, PagerDuty, email, Hazel, and any custom webhook. Attach as
+ many destinations to a rule as you want — each gets its own notification template.
+
+
+
+
+ {
+ destinations.map((d) => (
+
+
+ {d.name === "Slack" && (
+
+
+
+ )}
+ {d.name === "Discord" && (
+
+
+
+ )}
+ {d.name === "PagerDuty" && (
+
+
+
+ )}
+ {d.name === "Email" && (
+
+
+
+
+ )}
+ {d.name === "Webhook" && (
+
+
+
+ )}
+ {d.name === "Hazel" && (
+
+
+
+ )}
+
{d.name}
+
+
{d.description}
+
+ {d.delivery.slice(0, 1)} {d.delivery.slice(1)}
+
+
+ ))
+ }
+
+
+
+
+
+
+
+
+
+ Incident lifecycle
+
+
+ Incidents that resolve themselves
+
+
+ A firing rule opens exactly one incident. It renotifies while the breach is still hot, and when
+ the numbers recover it closes itself and says so — nobody has to remember to post the all-clear.
+
+
+
+
+ {
+ lifecycle.map((step) => (
+
+
+
{step.time}
+
{step.title}
+
{step.desc}
+
+ ))
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/landing/src/pages/index.astro b/apps/landing/src/pages/index.astro
index 913543f5b..fd7207c1c 100644
--- a/apps/landing/src/pages/index.astro
+++ b/apps/landing/src/pages/index.astro
@@ -9,6 +9,7 @@ import LiveLogsVolumeChart from "../components/live/LiveLogsVolumeChart.tsx";
import LiveServiceMap from "../components/live/LiveServiceMap.astro";
import LiveMcpTranscript from "../components/live/LiveMcpTranscript.astro";
import LiveBrowserSessions from "../components/live/LiveBrowserSessions.astro";
+import Alerting from "../components/Alerting.astro";
import Kubernetes from "../components/Kubernetes.astro";
import BillComparison from "../components/BillComparison.astro";
import Quickstart from "../components/Quickstart.astro";
@@ -154,7 +155,10 @@ const homeFaqs = [
-
+
+
+
+
diff --git a/apps/landing/src/pages/ja/index.astro b/apps/landing/src/pages/ja/index.astro
index ca862f0a5..b10af0b35 100644
--- a/apps/landing/src/pages/ja/index.astro
+++ b/apps/landing/src/pages/ja/index.astro
@@ -7,6 +7,7 @@ import LiveTrace from "../../components/live/LiveTrace.astro";
import LiveLogStream from "../../components/live/LiveLogStream.astro";
import LiveServiceMap from "../../components/live/LiveServiceMap.astro";
import LiveMcpTranscript from "../../components/live/LiveMcpTranscript.astro";
+import Alerting from "../../components/Alerting.astro";
import BillComparison from "../../components/BillComparison.astro";
import Quickstart from "../../components/Quickstart.astro";
import Footer from "../../components/Footer.astro";
@@ -86,6 +87,8 @@ const pageDescription = m.page_home_desc();
+
+
diff --git a/apps/landing/src/pages/ko/index.astro b/apps/landing/src/pages/ko/index.astro
index ca862f0a5..b10af0b35 100644
--- a/apps/landing/src/pages/ko/index.astro
+++ b/apps/landing/src/pages/ko/index.astro
@@ -7,6 +7,7 @@ import LiveTrace from "../../components/live/LiveTrace.astro";
import LiveLogStream from "../../components/live/LiveLogStream.astro";
import LiveServiceMap from "../../components/live/LiveServiceMap.astro";
import LiveMcpTranscript from "../../components/live/LiveMcpTranscript.astro";
+import Alerting from "../../components/Alerting.astro";
import BillComparison from "../../components/BillComparison.astro";
import Quickstart from "../../components/Quickstart.astro";
import Footer from "../../components/Footer.astro";
@@ -86,6 +87,8 @@ const pageDescription = m.page_home_desc();
+
+
diff --git a/apps/landing/src/paraglide/messages/en.js b/apps/landing/src/paraglide/messages/en.js
index 4b341b8bb..fa62d86dd 100644
--- a/apps/landing/src/paraglide/messages/en.js
+++ b/apps/landing/src/paraglide/messages/en.js
@@ -2183,7 +2183,7 @@ export const alert_heading = () => `Alerts with the context attached`
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_rules_title = () => `Alert rules`
+export const alert_rules_title = () => `From error rate to raw SQL`
/**
@@ -2191,7 +2191,7 @@ export const alert_rules_title = () => `Alert rules`
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_rules_desc = () => `7 built-in signal types — error rate, P95/P99 latency, Apdex, throughput, custom metrics, and custom queries. With severity levels, incident tracking, and auto-resolution.`
+export const alert_rules_desc = () => `Error rate, P95/P99 latency, Apdex, throughput, any metric — and when the presets run out, write the query yourself. You set the window, the threshold, and the severity.`
/**
@@ -2199,7 +2199,7 @@ export const alert_rules_desc = () => `7 built-in signal types — error rate, P
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_route_title = () => `Route everywhere`
+export const alert_route_title = () => `Paged where you work`
/**
@@ -2207,7 +2207,7 @@ export const alert_route_title = () => `Route everywhere`
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_route_desc = () => `Push alerts to Slack, Discord, PagerDuty, or any webhook. Your team gets notified where they already work.`
+export const alert_route_desc = () => `Slack, Discord, PagerDuty, email, Hazel, or any webhook. Wire one rule to as many destinations as you want — on-call gets paged while the channel gets the summary.`
/**
@@ -2250,6 +2250,54 @@ export const alert_acknowledge = () => `Acknowledge`
export const alert_webhook_note = () => `+ any custom webhook endpoint`
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_lede = () => `Threshold and anomaly rules watch your live telemetry around the clock. When one fires, the page arrives with the trace that tripped it, the blast radius, and a one-click AI diagnosis — not just a number that crossed a line.`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_incidents_title = () => `Incidents, not noise`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_incidents_desc = () => `A firing rule opens an incident, renotifies while it's still hot, and auto-resolves when the numbers recover. Fan out per group. Preview against real history before you ship it.`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_ai_note = () => `AI diagnosis linked in every notification`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_dest_email = () => `Email`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_dest_webhook = () => `Webhook`
+
+
/**
*
* @returns {string}
@@ -2434,6 +2482,14 @@ export const footer_service_catalog = () => `Service Catalog`
export const footer_error_tracking = () => `Error Tracking`
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const footer_alerting = () => `Alerting`
+
+
/**
*
* @returns {string}
diff --git a/apps/landing/src/paraglide/messages/ja.js b/apps/landing/src/paraglide/messages/ja.js
index 257c9f292..b749debfa 100644
--- a/apps/landing/src/paraglide/messages/ja.js
+++ b/apps/landing/src/paraglide/messages/ja.js
@@ -2183,7 +2183,7 @@ export const alert_heading = () => `コンテキスト付きのアラート`
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_rules_title = () => `アラートルール`
+export const alert_rules_title = () => `エラー率から生SQLまで`
/**
@@ -2191,7 +2191,7 @@ export const alert_rules_title = () => `アラートルール`
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_rules_desc = () => `エラー率、P95/P99レイテンシ、Apdex、スループット、カスタムメトリクス、カスタムクエリの7種類の組み込みシグナル。重大度レベル、インシデント追跡、自動解決付き。`
+export const alert_rules_desc = () => `エラー率、P95/P99レイテンシ、Apdex、スループット、任意のメトリクス。プリセットで足りなければ、クエリを自分で書けます。ウィンドウ、しきい値、重大度はすべて自由に。`
/**
@@ -2199,7 +2199,7 @@ export const alert_rules_desc = () => `エラー率、P95/P99レイテンシ、A
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_route_title = () => `どこへでもルーティング`
+export const alert_route_title = () => `普段いる場所に通知`
/**
@@ -2207,7 +2207,7 @@ export const alert_route_title = () => `どこへでもルーティング`
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_route_desc = () => `アラートをSlack、Discord、PagerDuty、任意のWebhookへ。チームが普段いる場所に通知が届きます。`
+export const alert_route_desc = () => `Slack、Discord、PagerDuty、メール、Hazel、任意のWebhook。1つのルールを複数の宛先へ — オンコールにはページ、チャンネルにはサマリーを。`
/**
@@ -2250,6 +2250,54 @@ export const alert_acknowledge = () => `確認`
export const alert_webhook_note = () => `+ 任意のカスタムWebhookエンドポイント`
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_lede = () => `しきい値と異常検知のルールが、ライブなテレメトリを常時監視。発火した通知には、原因となったトレース、影響範囲、ワンクリックのAI診断が添付されます — 数字が届くだけではありません。`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_incidents_title = () => `ノイズではなくインシデント`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_incidents_desc = () => `発火したルールはインシデントを開き、続く間は再通知し、数値が回復すれば自動で解決。グループごとにファンアウトし、保存前に実データでプレビューできます。`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_ai_note = () => `すべての通知にAI診断リンク付き`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_dest_email = () => `メール`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_dest_webhook = () => `Webhook`
+
+
/**
*
* @returns {string}
@@ -2434,6 +2482,14 @@ export const footer_service_catalog = () => `サービスカタログ`
export const footer_error_tracking = () => `エラートラッキング`
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const footer_alerting = () => `アラート`
+
+
/**
*
* @returns {string}
diff --git a/apps/landing/src/paraglide/messages/ko.js b/apps/landing/src/paraglide/messages/ko.js
index 06ef90245..712dbccbd 100644
--- a/apps/landing/src/paraglide/messages/ko.js
+++ b/apps/landing/src/paraglide/messages/ko.js
@@ -2183,7 +2183,7 @@ export const alert_heading = () => `컨텍스트가 붙어 있는 알림`
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_rules_title = () => `알림 규칙`
+export const alert_rules_title = () => `에러율부터 raw SQL까지`
/**
@@ -2191,7 +2191,7 @@ export const alert_rules_title = () => `알림 규칙`
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_rules_desc = () => `에러율, P95/P99 레이턴시, Apdex, 처리량, 커스텀 메트릭, 커스텀 쿼리 등 7가지 내장 시그널 유형. 심각도 레벨, 인시던트 추적, 자동 해결 포함.`
+export const alert_rules_desc = () => `에러율, P95/P99 레이턴시, Apdex, 처리량, 임의의 메트릭 — 프리셋으로 부족하면 쿼리를 직접 작성하세요. 윈도우, 임계값, 심각도는 모두 자유롭게.`
/**
@@ -2199,7 +2199,7 @@ export const alert_rules_desc = () => `에러율, P95/P99 레이턴시, Apdex,
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_route_title = () => `어디로든 라우팅`
+export const alert_route_title = () => `팀이 일하는 곳으로`
/**
@@ -2207,7 +2207,7 @@ export const alert_route_title = () => `어디로든 라우팅`
* @returns {string}
*/
/* @__NO_SIDE_EFFECTS__ */
-export const alert_route_desc = () => `알림을 Slack, Discord, PagerDuty 또는 임의의 웹훅으로 보내세요. 팀이 이미 일하는 곳으로 알림이 갑니다.`
+export const alert_route_desc = () => `Slack, Discord, PagerDuty, 이메일, Hazel, 임의의 웹훅. 하나의 규칙을 여러 대상에 연결하세요 — 온콜은 페이지를, 채널은 요약을 받습니다.`
/**
@@ -2250,6 +2250,54 @@ export const alert_acknowledge = () => `확인`
export const alert_webhook_note = () => `+ 임의의 커스텀 웹훅 엔드포인트`
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_lede = () => `임계값 및 이상 탐지 규칙이 실시간 텔레메트리를 상시 감시합니다. 알림이 발생하면 원인이 된 트레이스, 영향 범위, 원클릭 AI 진단이 함께 도착합니다 — 숫자 하나만 오지 않습니다.`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_incidents_title = () => `노이즈가 아닌 인시던트`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_incidents_desc = () => `발생한 규칙은 인시던트를 열고, 지속되는 동안 재알림하며, 수치가 회복되면 자동으로 해결됩니다. 그룹별로 확장하고, 저장 전에 실제 데이터로 미리 확인하세요.`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_ai_note = () => `모든 알림에 AI 진단 링크 포함`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_dest_email = () => `이메일`
+
+
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const alert_dest_webhook = () => `웹훅`
+
+
/**
*
* @returns {string}
@@ -2434,6 +2482,14 @@ export const footer_service_catalog = () => `서비스 카탈로그`
export const footer_error_tracking = () => `에러 추적`
+/**
+ *
+ * @returns {string}
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export const footer_alerting = () => `알림`
+
+
/**
*
* @returns {string}