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

# How are AWS SNS messages deduplicated?

> Choose how messages from an AWS SNS topic become alerts, and how Automatic recognizes CloudWatch, Inspector, GuardDuty and AWS Health messages.

## Context

An AWS SNS topic can carry messages from many AWS services. The **Deduplication key** setting on your SNS alert source decides which messages belong to the same alert. You'll find it under the setup steps when you create or edit the source.

> [!NOTE]
>
> If you only send CloudWatch alarms, use the AWS CloudWatch alert source instead. It's built for CloudWatch alarms and has its own deduplication settings. See [Alert sources](https://docs.incident.io/on-call/alert-sources).

## Choose a deduplication key

| Option | What happens |
| - | - |
| **Automatic** | We recognize common AWS payloads and give one alert per alarm, finding or event. Every other message creates its own alert. |
| **Each message** | Every message creates its own alert, and alerts don't resolve automatically. Grafana notifications are still grouped by their group key. |
| **Custom JSON path** | You choose the field that identifies an alert. Messages with the same value at that path update the same alert. |

New SNS sources start on **Automatic**. Sources created before this setting existed use **Each message** until you change it.

## How Automatic works

Automatic reads the message body (`MessageJSON`) and looks for these payloads:

| Message | Deduplication key | Status |
| - | - | - |
| CloudWatch alarm (metric, composite or log alarm) | `AlarmName` | `ALARM` fires, `OK` resolves, `INSUFFICIENT_DATA` is ignored |
| Inspector finding, sent through EventBridge | `detail.findingArn` | `CLOSED` resolves, every other status fires |
| GuardDuty finding, sent through EventBridge | `detail.arn` | Always fires |
| AWS Health event, sent through EventBridge | `detail.eventArn` and the affected account (`detail.affectedAccount`, or `account`) | `closed` resolves, every other status fires |

CloudWatch alarms use the same key and statuses as the AWS CloudWatch alert source, so an alarm behaves the same way whichever source receives it.

When a message doesn't match one of these payloads, it creates its own alert, the same as **Each message**.

### Alerts that don't resolve on their own

GuardDuty never sends a closed status for a finding, so its alert stays firing until you resolve it. Later messages about the same finding update that alert and don't page again. The same applies to a CloudWatch alarm that doesn't send its `OK` to your topic.

To resolve these alerts without doing it by hand, set an auto-resolve timeout on the alert source, or choose a different deduplication key.

## Use a custom JSON path

Choose **Custom JSON path** when Automatic doesn't fit how you want to group messages. The path reads the SNS payload, and the parsed message body is under `MessageJSON`. For example:

* `$.MessageJSON.AlarmArn` gives one alert per CloudWatch alarm, even when alarms in different accounts or regions share a name.
* `$.MessageJSON.detail.findingArn` gives one alert per Inspector finding.

When the path doesn't resolve for a message, that message creates its own alert.

With a custom path, a CloudWatch `OK`, a `CLOSED` Inspector finding or a `closed` AWS Health event still resolves its alert.
