Last Updated: October 30, 2026
Overview
"Duplicate alert" means two different things in a SOC, and D3 Morpheus handles each one with a different tool. Knowing which one you are looking at is the whole job:
-
The same alert arriving twice. One alert, sent or fetched more than once — a source that re-sends, or a scheduled fetch whose window overlaps the last one. You want one event, not two. This is handled at ingestion, by the event key in your field mapping.
-
Different alerts that belong to one incident. Ten alerts about the same host, the same phishing sender, or the same destination IP address. Each one is a real, separate alert, and you want them investigated together under a single incident. This is handled when an event is escalated, by a preprocessing playbook that looks for an existing incident before it creates a new one.
The two are configured in different places and neither one does the other's job. An event key will not group ten different alerts, and a playbook condition will not stop the same alert being ingested twice.
Which One Do You Want
In short
|
What you are trying to do |
The tool |
Where it is configured |
|---|---|---|
|
Stop one alert becoming two events when the source re-sends it, or when a fetch window overlaps |
The event key in the intake field mapping |
CONFIGURATION > Data Ingestion, on the data source's field mapping |
|
Put several related alerts into one incident automatically |
The Escalate task, in a preprocessing playbook |
CONFIGURATION > Preprocessing Playbooks, in the playbook that runs on the event |
|
Put several related events into one incident by hand, as an analyst |
The event's Event/Incident Correlation tab |
WORKSPACE > Events, on an open event |
|
Update the event you already have instead of adding another one |
The Update Identical Event utility command, in a preprocessing playbook |
CONFIGURATION > Preprocessing Playbooks, in the playbook that runs on the event |
The Same Alert Arriving Twice
An event key is the value D3 uses to recognize an alert it has already seen. Map it once on your data source, and a re-sent alert is dropped on arrival instead of becoming a second event for an analyst to read.
How a Repeat Is Recognized
When an alert is ingested, D3 reduces it to a single fingerprint value:
-
With an event key mapped, the fingerprint comes from the field you mapped as the event key. Choose a field the source guarantees is stable and unique for one alert, such as the vendor's own alert ID.
-
With no event key mapped, the fingerprint is taken from the whole alert exactly as it arrived. Two alerts match only when every byte of the payload is identical, so an alert carrying its own timestamp, a sequence number or a receipt ID is treated as new every time.
That is the practical reason to map an event key: without one, only byte-identical re-sends are recognized, and most sources do not re-send byte-identical payloads.
What Happens to the Repeat
A new alert is compared against the events already on the same site. When the fingerprint matches one of them, the first copy is kept and the new arrival is dropped. The analyst keeps the event they have already been working on, with its notes, its owner and its history intact.
Two things about the comparison are worth knowing before you choose a field:
-
The match is scoped to one site. The same alert ingested into two sites produces an event in each. This is deliberate in a multi-tenant setup, where each client's data stays its own.
-
There is no time window. The comparison is not limited to recent events, so an alert whose key repeats months later is still recognized as the same alert. Use a key that identifies one alert occurrence, not one object: a host name or a user name repeats forever and will collapse unrelated alerts into the first event ever raised for it. A vendor alert ID does not.
WARNING
Choose the event key field with care, because its effect is not limited in time. A field that repeats across genuinely separate alerts — a host name, a user name, a rule name — will cause later alerts to be dropped as repeats of a much older event.
Scheduled Fetches and Overlap
A scheduled data ingestion job deliberately overlaps its fetch window with the previous run, so that an alert written to the source slightly late is not missed. That overlap means the same alerts are pulled again on purpose. With an event key mapped, those re-pulled alerts are recognized and dropped, and you see each alert once. Overlap and the event key are designed to work together: the fetch is generous, and the event key does the tidying.
Events Deduplication
For a webhook data source, the check has its own switch: Events Deduplication, on the Fetch Event command’s Settings tab. It appears once the webhook listener is turned on for the command, and it is on by default.
While it is on, D3 ignores an incoming event whose payload is identical to one already received. Turn it off only when you need every delivery recorded separately — for example while testing a webhook sender, where you want to see each test post as its own event.
WARNING
With Events Deduplication turned off, every incoming payload is processed as a separate event and runs its playbook, including identical re-sends and automatic retries from the sender. Expect duplicate incidents and a sharp rise in event volume for that data source.
Alerts That Belong to One Incident
Grouping is a different job from recognizing a repeat. Ten alerts about one host are ten real alerts, and all ten deserve to be recorded — but an analyst wants one incident with ten events attached, not ten incidents to triage one at a time.
The tool is the Escalate task, used in the preprocessing playbook that runs on each ingested event. Instead of creating an incident unconditionally, the command first searches the incidents that already exist. When one matches your conditions, the event is attached to that incident. When none matches, a new incident is created and becomes the one that later events attach to.
OLDER PLAYBOOKS
An existing playbook may use a Create Incident With Conditions utility command instead. It does the same job and its settings read the same way. New playbooks use the Escalate task, which is what the task list offers.
Where to Put the Check
Put the search inside the Escalate task itself, not in a step before it.
The reason is that alerts about one attack usually arrive together, within the same second. A playbook that runs a separate "does an incident already exist?" step first, and then escalates, asks the question before any of those alerts has produced an incident — so every one of them gets the same answer, and every one creates its own incident. The Escalate task does the search and the creation as one step, which is what makes the first event's incident available to the second event.
Setting Up the Search
The task is added to a preprocessing playbook that runs on event ingestion. Its inputs are:
|
Input |
What it does |
|---|---|
|
Incident Type (Required) |
The incident type to create. |
|
Playbook (Required) |
The investigation playbook to run on the incident. |
|
Title (Optional) |
The incident title. |
|
Description (Optional) |
The incident description. |
|
Severity (Optional) |
The incident severity. |
|
Owner (Optional) |
The incident owner. |
|
External Key (Optional) |
A unique key from outside D3. Leave it empty if you do not have one. |
|
Custom Fields (Optional) |
Custom incident fields to set, as a JSON object. A field name is given the |
|
Search Conditions (Optional) |
The conditions that decide whether an existing incident counts as a match. See Writing the Search Conditions. |
|
The number of relevant incidents to link (Optional) |
How many of the oldest matching incidents the event links to. The default is 1. |
|
Link to Relevant Incidents (Optional) |
Whether to link the event when a matching incident is found. The default is true. |
|
Create a new Incident (Optional) |
Whether to create an incident when nothing matches. The default is true. |
|
Assignment Group (Optional) |
The name or id of the assignment group (queue) a new incident is filed into. An incident bound for a group starts unowned, so the queue decides who picks it up. |
Between the last two, you choose what the command does in each case: link to what exists, create when nothing matches, or only one of the two.
READER NOTE
When the playbook is run in testing mode, the command does not create or link an incident.
Writing the Search Conditions
LET MORPHEUS WRITE THE CONDITIONS
Rather than writing the JSON by hand, open the draft playbook and use Modify with AI on the editor toolbar. Describe the grouping you want in a sentence and Morpheus proposes the change for you to approve. For example: correlate all events ingested within 12 hours that have the same tactic or the same agent into the same incident. It works on drafts only, so a live playbook is untouched until you publish. See Modifying a Playbook with AI.
Search Conditions takes an array of JSON objects. Conditions inside one object are combined with AND; the objects themselves are combined with OR. So [ { "field1": "a", "field2": "b" }, { "field1": "c" } ] means (field1 = a AND field2 = b) OR (field1 = c).
Within a condition you can also use:
-
$inand$nin— the field value is, or is not, any value in an array:[ { "field": { "$nin": [ "a", "b" ] } } ] -
$ne— the field value is not the given value:[ { "field": { "$ne": "a" } } ] -
$regex— the field value matches a regular expression:[ { "field": { "$regex": "^value" } } ] -
$gt,$ltand$datefor a date field:[ { "field": { "$gt": { "$date": "2026-09-01T00:00:00Z" }, "$lt": { "$date": "2026-09-21T00:00:00Z" } } } ]
What matters in how you fill it in:
-
The search reads incident fields. It looks at the incidents that already exist, not at the raw alert, so a value matches only when an earlier event’s run already put it on the incident. In practice the same task both sets the value, through Custom Fields, and searches for it.
-
Only incident fields may be named. You can search on an incident’s own fields — among them
Number,Type,Status,Severity,Title,Description,Stage,DataSource,IncidentSource,Connection,Category,ExternalKey, and the created, modified, closed, reopened and SLA due times — and on any custom field, whose name begins withCustom. Naming anything else fails the task with a message listing the invalid fields. -
An artifact you ingest is a custom field. A value like an IP address or a host name is not one of the built-in incident fields, so write it to a custom field and search on that custom name. A field named
IPAddressin Custom Fields is stored and searched asCustomIPAddress, because theCustomprefix is added for you. -
Give the search a scope. The search is ordered oldest first and is not limited to recent or open incidents, so a condition as broad as "same incident type" keeps finding the oldest incident that ever matched. Add a
Statuscondition, or a created-time range, to limit matches to incidents still being worked. -
Matches are scoped to one site. The search is limited to the event’s own site, and to the incidents the running user may see.
-
With no conditions, every event creates its own incident. When Search Conditions is empty, there is nothing to match on and the event is escalated to a new incident. Set at least one condition that identifies the shared activity.
Updating the Event You Already Have
The Update Identical Event utility command covers a third case: an alert arrives that is a newer report of an event you already hold, and you want the existing event brought up to date rather than a second event added to the queue. Use it in a preprocessing playbook on the On Event Ingestion trigger.
When an existing event from the same data source and site matches the search condition you set, every newly ingested field is written onto that original event, and a field the original does not have is added to it. The newly arrived event is then dismissed, which is the default, or not created at all when you turn on Skip Event Creation. Incidents already linked to the original event are updated with the fields you name in Incident Fields.
Its inputs are:
|
Input |
What it does |
|---|---|
|
Search Conditions (Optional) |
A JSON object identifying the event to update, keyed on system field names. The value supports a regular expression, a string, a number, |
|
Incident Fields (Optional) |
A JSON object of incident fields to update on the linked incidents. Among them Title, SiteName, IncidentType, Status, SeverityName, Disposition, Tags, DueDate, Description, IncidentCategory, DateEnded, Owner, DateOccurred and CustomFields. Dates use |
|
Skip Event Creation (Optional) |
When on, no new event is created if an identical one already exists. Off by default, which creates the new event and then dismisses it. |
FAQ
I mapped an event key and I am still getting two events for the same alert. Why? The two events are on different sites, or the field you mapped is not the same in both arrivals. The comparison is per site, and it uses only the mapped event key. Check which site each event landed on, and compare the key value on both events.
I have no event key available from my source. What do I get? Without a mapped event key, an alert is recognized as a repeat only when the payload it arrives with is identical in full. If your source adds a timestamp, a sequence number or a receipt ID to each delivery, every delivery is a new event. If the source has any stable identifier for an alert, mapping it as the event key is worth doing.
Does the duplicate check expire, so an old alert can come back as a new event? No. There is no time limit on the comparison, which is why the event key should identify one alert occurrence rather than a thing that recurs, like a host or a user.
Why did ten alerts that arrived together create ten incidents? The grouping check ran before any incident existed. Alerts about one attack arrive within the same moment, so a playbook that checks for an existing incident in a step before escalation gets the same answer for all ten. Do the search and the escalation in one step, in the Escalate task.
Can I group events without writing a playbook? Yes. An analyst can do it from the event: the Event/Incident Correlation tab finds events and incidents that share artifacts with the event, and escalates the ones you pick into the same incident. See Event-Incident Correlation.
Does the event key group related alerts as well? No. The event key answers only "have I seen this exact alert before". Grouping different alerts is the preprocessing playbook's job.