> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Alert recipes

> Concrete starting configurations for the alerts most production apps need, and guidance on when each one is worth setting up.

This page gives a starting configuration for each alert most production applications need. Every recipe lists what the trigger measures, when it is worth setting up, and values to start from.

Treat the values as starting points. Graph the metric over at least two weeks before committing to a threshold, then adjust using the guidance in [tune your alerts](/alerting/tuning).

Whichever recipe you start with, give the trigger a name that says what is wrong, a description that says what to do about it, and a linked dashboard. Those three fields are what turn the resulting notification into something a responder can act on, and they are covered in [make the notification explain itself](/alerting/tuning#make-the-notification-explain-itself).

## The four alerts to set up first

If you are setting up alerting from scratch, these four cover most real incidents:

1. An [uptime monitor](#is-the-app-reachable) on a health-check endpoint.
2. An [error rate](#are-users-hitting-errors) trigger on your `web` namespace.
3. A [p95 response time](#are-requests-getting-slow) trigger on user-facing traffic.
4. [Check-ins](#did-scheduled-work-run) for scheduled jobs.

Add host and saturation alerts once those are stable. Adding every recipe on this page at once is a reliable way to create alert fatigue.

## Is the app reachable?

**Use:** [Uptime monitoring](/uptime-monitoring/setup)

An external check that your endpoint still responds. It is the only alert that still works when your app cannot send anything to AppSignal at all, which is why most teams set it up first.

| Setting  | Starting value                                          |
| -------- | ------------------------------------------------------- |
| URL      | A dedicated health-check endpoint, including the scheme |
| Warm-up  | 1 minute or more                                        |
| Notifier | On-call                                                 |

AppSignal requests the URL every minute from four regions and reports a failure when the response is not in the `2xx` range or does not arrive within 30 seconds.

Each region is tracked separately, so a monitor opens one alert per failing region. A genuine outage opens up to four alerts, and a network problem between one region and your endpoint opens one alert while your application is fine. This is the main reason to set a warm-up on uptime monitors: a single-region failure that resolves within a minute does not send a notification.

An uptime monitor also produces metrics tagged by region and monitor name, so you can add [anomaly detection triggers](/anomaly-detection) on response time per region if you need finer alerting than up or down.

SSL certificate expiration monitoring is available as an [AppSignal Labs](/labs) feature. Once enabled, you turn it on for an individual `https://` monitor rather than building a trigger by hand, and AppSignal notifies you when the certificate has fewer than 14 days remaining, using the same notifiers as the monitor. Certificate expiry is a slow-moving problem, so route it to email or chat rather than on-call.

## Are users hitting errors?

**Use:** An anomaly detection trigger on error rate, scoped to a namespace

Error rate is the fastest indicator that users are experiencing errors, and it stays meaningful as traffic changes.

| Setting      | Starting value                                     |
| ------------ | -------------------------------------------------- |
| Trigger kind | Error rate                                         |
| Namespace    | `web`                                              |
| Threshold    | Above 5% for a mature app, above 20% for a new one |
| Warm-up      | 3–5 minutes                                        |
| Cooldown     | 5 minutes                                          |
| Notifier     | On-call                                            |

The suggested trigger in AppSignal starts at 20%, which is deliberately conservative so a new app does not immediately produce alerts. Lower it once you know your baseline.

Create a separate, more forgiving trigger for `background`. Job failures usually retry, so they rarely justify the same urgency as failing web requests.

Running two error rate triggers at different thresholds works well, as long as each one has a different destination. A trigger at your normal degradation threshold goes to chat, and a second one at a much higher threshold, such as 50%, means there is a serious issue and should notify on-call. Two thresholds pointing at the same notifier only double the notifications.

### When to use error count instead

Error count crosses a fixed threshold whenever traffic grows, so it notifies you on busy days regardless of whether anything is wrong. Use it only where any occurrence matters and volume is naturally low, such as a payment or signup namespace. Scope it tightly and set a low threshold.

## Are requests getting slow?

**Use:** An anomaly detection trigger on performance, measured in milliseconds

Averages hide slow requests for part of your traffic. If one request in 20 takes 8 seconds while the rest are quick, the average barely moves, but 5% of users experience a slow request.

Percentiles fix this. A p95 of 400 ms means 95 out of every 100 requests finished within 400 ms, and the slowest five took longer. Alert on p90 or p95 rather than the average, so you notice a problem that affects part of your traffic.

| Setting      | Starting value                   |
| ------------ | -------------------------------- |
| Trigger kind | Slow performance for a namespace |
| Field        | `p95`                            |
| Threshold    | Roughly twice your normal p95    |
| Warm-up      | 5 minutes                        |
| Cooldown     | 5 minutes                        |
| Notifier     | Team chat                        |

AppSignal's suggested trigger uses a mean above 500 ms, which is a reasonable first alert but will miss partial degradation. Move to p95 once you have a baseline.

To watch one critical path rather than a whole namespace, use an action-scoped performance trigger. Checkout, sign-in, and search are common candidates. Give each a threshold that fits it: a page that calls a third-party API may reasonably take 10 seconds, while a homepage should not.

## Did traffic disappear?

**Use:** An anomaly detection trigger on throughput, measured in requests per minute

A sharp drop in throughput usually means a failure happened before requests reached your app: an expired domain, a misconfigured load balancer, or a CDN outage. This failure is invisible to your other alerts, because an app receiving no traffic reports no errors and no slow requests.

| Setting      | Starting value                       |
| ------------ | ------------------------------------ |
| Trigger kind | Throughput for a namespace           |
| Comparison   | Below                                |
| Threshold    | Well under your quietest normal hour |
| Warm-up      | 1–5 minutes                          |
| Cooldown     | 10 minutes                           |
| Notifier     | On-call                              |

Set the threshold against your quietest period, not your average, or the trigger will notify you every night. If your traffic varies too much for a fixed floor to work, alert on traffic reaching exactly zero instead, as described in the following section.

### Alerting on traffic that is too high

Traffic far above your normal peak can also need a trigger. It can come from expected growth, such as a successful campaign, or from a problem, such as a bot scraping your catalog or a client retrying in a loop. In both cases, the alert helps you respond before the traffic exhausts your capacity.

Set the comparison to **More than**, with a threshold well over your busiest normal hour, and route it to chat. It is rarely urgent enough for on-call notification, but it explains many other alerts that arrive shortly afterwards.

## Did activity stop?

**Use:** An anomaly detection trigger with a threshold of exactly zero

Some of the most valuable alerts are about absence rather than excess. A queue consumer that stops consuming, a namespace that stops receiving traffic, or a pipeline stage that stops producing output can show no errors, no slow requests, and no saturation. The missing activity is the problem.

| Setting      | Starting value                                                  |
| ------------ | --------------------------------------------------------------- |
| Comparison   | Equal to `0`                                                    |
| Missing data | Enable **treat missing datapoints as 0**                        |
| Warm-up      | 3–5 minutes, based on how much the work varies minute to minute |
| Notifier     | On-call for anything customer-facing                            |

Enabling **treat missing datapoints as 0** is what makes this work. Without it, a metric that stops reporting entirely sends no data points, so the trigger has nothing to evaluate and the alert never opens. With it, AppSignal treats missing data as zero and the alert opens as intended.

Good candidates are throughput per namespace, a counter of successfully processed jobs, or a process count that should never drop to zero. This pattern is also the reliable way to notice a worker that has died rather than slowed down.

<Note>
  Use this for continuous work that should always be happening. For work that runs on a schedule, use [check-ins](/check-ins) instead, which are built for it and do not need a warm-up long enough to span the gap between runs.
</Note>

## Is work backing up?

**Use:** An anomaly detection trigger on queue time, measured in milliseconds

Queue time measures how long a request or job waited before your app started processing it. Rising queue time is an early warning that capacity is short, usually before response times or error rates react. Your app may report no errors and no slow requests while users are still waiting: an order confirmed hours after it was placed, or a report that arrives a day late.

| Setting      | Starting value                               |
| ------------ | -------------------------------------------- |
| Trigger kind | Queue time for a namespace                   |
| Field        | `mean` or `p95`                              |
| Threshold    | Several times your normal queue time         |
| Warm-up      | 5 minutes                                    |
| Cooldown     | 5 minutes                                    |
| Notifier     | Team chat, or on-call for user-facing queues |

In practice, queue depth is often the easier signal to alert on. If you already track pending job count or unprocessed message count as a [custom metric](/metrics/custom), a depth threshold is concrete, easy to reason about, and easy to set from history. Tag it by queue name so a backlog in one queue does not read as a general outage.

Use both where you can. Depth tells you the backlog is growing; queue time tells you it is already affecting someone.

## Are hosts running out of resources?

**Use:** Host metric triggers

Host alerts describe causes rather than user-visible symptoms, so route them to lower-urgency channels than user-facing alerts. A host at 95% CPU with healthy response times is not an incident. Host alerts are useful because they warn you before a resource runs out completely, which is when an app can stop abruptly and other alerts can start opening at once.

Every host trigger accepts a hostname, and its default value of `*` matches every host. Set a specific name or a prefix such as `web-*` unless you genuinely want one alert per host in the fleet.

### Disk usage

This is the clearest host alert to configure, because a full disk reliably causes failures and disk usage often increases predictably.

| Setting    | Starting value                                             |
| ---------- | ---------------------------------------------------------- |
| Metric     | `disk_usage`, in percent                                   |
| Mountpoint | `/`, plus any data volume                                  |
| Threshold  | Above 80% generally, above 60% for hosts that fill quickly |
| Warm-up    | 0–10 minutes                                               |
| Notifier   | Team chat                                                  |

Set the threshold from how fast the disk fills, not from how full it is. A general-purpose host that gains a percentage point a week is fine at 80%. A database or queue host that can gain 20 points in an hour needs to warn you at 60%, because the remaining time matters more than the remaining space.

That usually means several disk triggers rather than one, each scoped to a group of hosts with a wildcard, such as `db-*` at 60% and `web-*` at 80%. Set one trigger per mountpoint you care about too. A trigger without a mountpoint tag matches every mounted filesystem, including short-lived container mounts.

### Memory usage

| Setting   | Starting value                                             |
| --------- | ---------------------------------------------------------- |
| Metric    | `memory`                                                   |
| State     | `used`, `free`, or `available`                             |
| Threshold | Above 90% used, or a free-memory floor that suits the host |
| Warm-up   | 0–5 minutes                                                |
| Notifier  | Team chat                                                  |

Percentage is usually easier to reuse across differently sized hosts. Absolute values are better when you know how much free capacity a specific workload needs.

### Swap usage

When a server runs low on memory it starts moving data to disk, which is far slower than memory. The application keeps working, so no error may occur, but requests can become slower. This is useful to alert on because the impact can be gradual and easy to miss.

| Setting   | Starting value                                            |
| --------- | --------------------------------------------------------- |
| Metric    | `swap`                                                    |
| State     | `used` or `total`                                         |
| Threshold | Above 20% used for an early warning, above 50% for action |
| Warm-up   | 0–5 minutes                                               |
| Notifier  | Team chat                                                 |

The suggested trigger in AppSignal notifies you when a host uses any swap at all, which is a reasonable way to discover whether your hosts swap. It is usually too sensitive to keep long term: many healthy hosts allocate a little swap and never touch it again. Once you know your baseline, move to a percentage threshold so the alert opens for real memory pressure rather than for a few megabytes allocated at boot.

### CPU usage and load average

| Setting   | Starting value                                                               |
| --------- | ---------------------------------------------------------------------------- |
| Metric    | `cpu` in percent, or `load_avg`                                              |
| State     | `user`, `nice`, `system`, `idle`, or `iowait`, each reported as a percentage |
| Threshold | Above 90% CPU, or a load average around the host's core count                |
| Warm-up   | 5 minutes                                                                    |
| Notifier  | Team chat                                                                    |

The agent reports CPU per state rather than as a single total, so pick the state that describes the work you care about, and use `iowait` when you suspect the host is waiting on disk rather than computing.

Short CPU increases are normal. Only sustained high CPU usage usually needs a notification, and even then it belongs in chat rather than on-call unless it is already affecting response times.

Load average is often the more useful of the two on database and worker hosts, because it counts processes waiting on disk as well as on CPU. It is not comparable across machines, though: a load average of 60 is saturation on a 16-core host and healthy on a 128-core one. Scope a load average trigger to one class of host with a wildcard and set the threshold from that machine's core count, rather than running a single trigger across a mixed fleet.

### Disk and network throughput

The disk I/O and network traffic triggers cover data read from and written to every disk, and data received and transmitted through every network interface. These make better dashboard graphs than alerts for most teams, because a meaningful threshold depends heavily on the workload. Alert on them when you have a known ceiling, such as a provisioned IOPS limit.

## Did scheduled work run?

**Use:** [Check-ins](/check-ins)

Anomaly detection cannot reliably tell you that scheduled work did not happen, because a trigger only evaluates data that arrives. Use check-ins for this.

* **Cron check-in**, for jobs that run on a schedule. Its key setting is the cron expression, plus a timezone.
* **Heartbeat check-in**, for workers and processes that should keep running. Its key setting is the maximum duration since the last heartbeat.

Both use a **Maximum duration** in minutes rather than a warm-up. For a cron process monitor, AppSignal reports a failure when no event arrives between the start time set by the schedule and the end of that duration. For a heartbeat, it reports a failure when no event arrives within that duration of the last one. Set it longer than the job's normal variation in start time and run time, so a job that occasionally runs a few minutes late does not notify anyone.

Good candidates are nightly billing runs, backups, data exports, cache warmers, and any long-running consumer.

## Is one dependency failing?

**Use:** [Log triggers](/logging/triggers)

Some failures never become an incident or a metric. A payment provider that times out and then succeeds on retry leaves no error and no latency spike large enough to notice, but a sustained pattern is worth knowing about.

Start from the query that finds the lines. If you are already looking at them in the terminal, that query is the one you have:

```sh Shell theme={null}
appsignal-cli logs search --app "MyApp" --environment production \
  --query 'provider=bank-a message:timeout' --severities error --limit 20
```

Once the query matches the expected lines only, create the trigger from it. The same query text is reused:

```sh Shell theme={null}
appsignal-cli logs triggers create --app "MyApp" --environment production \
  --name "Bank A timing out" \
  --query 'provider=bank-a message:timeout' \
  --severity ERROR \
  --description "Bank A is timing out. Check their status page before investigating our own code." \
  --notifier-id <NOTIFIER_ID>
```

To do the same in the interface, filter the Logs page to the lines you care about, select one to open **Log details**, and create the trigger from the **Actions** section, which carries your query, severity, and source across. See [log triggers](/logging/triggers) for the full flow.

Log triggers work differently from metric triggers, and the difference matters for noise. A log trigger is evaluated against individual log lines as they arrive, so it does not have the anomaly trigger warm-up and cooldown settings. Control notification volume with the threshold setting instead:

* **First After Close** for a problem that recovers on its own, so you get one notification each time the problem returns after closing.
* **Nth in an hour** for a log pattern that matches intermittently by design, where the number of matching log lines is the important signal.
* **Every Occurrence** only where a single line genuinely matters.

Use **Never Notify** for patterns you want to track and count without notifying anyone.

### Getting warm-up and cooldown on log data

When a log pattern is too noisy for any of those thresholds, convert it into a metric instead of alerting on the lines directly. Extract a [log-based metric](/logging/metrics) from the matching lines, then point an [anomaly detection trigger](/anomaly-detection) at that metric.

That is two commands. First, count the matching lines into a metric. A `counter` needs no field, because it is counting lines rather than reading a value out of them:

```sh Shell theme={null}
appsignal-cli logs metrics create --app "MyApp" --environment production \
  --name "Bank A timeouts" \
  --query 'provider=bank-a message:timeout' \
  --metric 'name=bank_a_timeouts,type=counter'
```

Then alert on that metric, which is where warm-up and cooldown become available:

```sh Shell theme={null}
appsignal-cli triggers create --app "MyApp" --environment production \
  --name "Bank A timing out repeatedly" \
  --metric-name bank_a_timeouts --kind Advanced --field counter \
  --comparison-operator ">" --condition-value 10 \
  --warmup-duration 5 --cooldown-duration 10 \
  --description "Bank A has timed out more than 10 times in a minute for 5 minutes. Check their status page first." \
  --notifier-ids <NOTIFIER_ID>
```

This gives log-derived data the full state machine: a threshold, a warm-up so a brief increase is ignored, and a cooldown so one recurring problem produces one alert. This is the recommended approach for a dependency that fails in short periods several times a day.

## Is a business metric wrong?

**Use:** An anomaly detection trigger on a [custom metric](/metrics/custom)

Custom metrics are the only way to alert on application-specific values AppSignal cannot infer, such as successful payments per minute, signups, or the size of a work queue.

| Setting      | Guidance                                                                                               |
| ------------ | ------------------------------------------------------------------------------------------------------ |
| Field        | `gauge` for a current value, `counter` for a rate of events, `mean` or a percentile for measurements   |
| Format       | Set `duration`, `size`, `percent`, or `throughput` so thresholds and notifications show the right unit |
| Tags         | Filter to the series you care about, such as `provider=bank-a`                                         |
| Missing data | Enable **treat missing datapoints as 0** for counters that stop reporting when idle                    |

This is the one failure no other alert on this page can detect. If a change at your payment provider starts rejecting every transaction, your app stays up, fast, and error-free while nothing is being sold, so only a metric you send yourself can detect it. Graph the metric first, then set the threshold from what you see.

To verify a custom metric in the alerting UI, open **Anomaly detection**, go to **Triggers**, select **Add trigger**, then choose **Custom metrics** under **Other**. Enter the metric name and use the chart preview and tag combinations to confirm AppSignal has received the metric.

## Next steps

* Tune what you have set up with [tune your alerts](/alerting/tuning).
* Read how [anomaly detection](/anomaly-detection) evaluates triggers.
* Send custom metrics with [custom metrics](/metrics/custom).
* Review [notification settings](/application/notification-settings) for error and performance incidents.
* Check for coverage gaps with [alerting in production](/alerting/production).
