Understanding the Notification Manager in OpenCTI: Architecture and Operation
The notification manager in OpenCTI is a background service that monitors the platform's SSE event stream, evaluates user-defined triggers against incoming data, and generates real-time alerts or scheduled digest summaries for security analysts.
The notification manager serves as the central nervous system for alert delivery within the OpenCTI-Platform/opencti threat intelligence platform. Operating as a singleton background process, this manager ensures that analysts receive timely updates about relevant intelligence changes without manually polling the system. By continuously evaluating the platform's event stream against sophisticated trigger rules, the notification manager bridges the gap between raw data ingestion and actionable security alerts.
Core Architecture of the Notification Manager
The notification manager implementation in src/manager/notificationManager.ts follows a three-layer architecture that separates scheduling concerns from stream processing and trigger evaluation logic.
Scheduler and Distributed Locking
To prevent duplicate processing across clustered API instances, the manager implements a Redis-based coordination mechanism. The initNotificationManager function spawns two independent processing intervals: a live loop executing every 10 seconds and a digest loop running every 60 seconds. Each iteration attempts to acquire a specific lock key—notification_manager:lock_live_key for live processing and notification_manager:lock_digest_key for digests—ensuring only one API instance acts as the notification manager at any time.
Stream Processing Layer
The stream processor subscribes to the platform's Server-Sent Events (SSE) stream through createStreamProcessor. When raw DataEvent objects arrive from the event bus, the notificationLiveStreamHandler iterates over all active live triggers, comparing event characteristics against trigger definitions. This handler serves as the primary entry point for real-time notification generation, filtering the high-volume event stream into discrete alert candidates before passing them to the evaluation engine.
Trigger Evaluation and Notification Creation
The evaluation engine processes candidate events through buildTargetEvents, which orchestrates several validation steps defined in notificationManager.ts:
- Trigger Loading: Retrieves active definitions via
getLiveNotificationsandgetDigestNotifications - User Resolution: Determines applicable recipients through
getNotifications, considering group and organization memberships - Access Validation: Verifies user permissions using
isUserCanAccessStreamUpdateEventandisStixMatchFilterGroupfromsrc/utils/access.ts - Event Translation: Converts raw operation types (create, update, delete) into notification categories via
eventTypeTranslater - Message Generation: Creates human-readable descriptions through
generateNotificationMessageForInstanceandgenerateNotificationMessageForFilteredSideEvents
Finally, storeNotificationEvent persists the constructed notification to the database, making it available for UI display, email dispatch, or webhook delivery.
Live vs. Digest Notification Processing
The notification manager supports two distinct operational modes, each optimized for different analyst workflows and implemented through separate handler functions.
Real-Time Live Notifications
Live notifications provide immediate alerting when knowledge graph changes match specific criteria. The notificationLiveStreamHandler processes events as they arrive from the SSE stream, constructing KnowledgeNotificationEvent payloads for each matching trigger-user pair. This mode suits critical security alerts requiring immediate attention, such as new malware indicators or high-confidence threat actor updates. The 10-second live loop ensures minimal latency between event occurrence and notification generation.
Scheduled Digest Notifications
Digest notifications aggregate multiple events over configurable time periods to reduce alert fatigue. The handleDigestNotifications function executes on the 60-second digest loop, querying the event store for notifications generated during the previous interval. It filters these by the digest's constituent trigger IDs, assembles compact message lists per user, and stores a consolidated DigestEvent. Analysts can configure digest periods as hourly, daily, weekly, or monthly, with specific trigger times for daily and weekly summaries.
Trigger Resolution and User Targeting
Before generating notifications, the manager must resolve which users should receive alerts for each trigger definition. The getNotifications function aggregates both native triggers—automatically created for platform events, assignee changes, and RFI request access—and user-defined triggers stored as ENTITY_TYPE_TRIGGER entities in the database.
For each resolved trigger, the system builds a ResolvedTrigger object coupling the trigger definition with its applicable user list. The buildTargetEvents function then deduplicates webhook notifiers across users, ensuring that a single webhook call occurs per notification regardless of how many users share that notifier configuration. This deduplication logic appears in lines 55-64 of notificationManager.ts, preventing redundant external API calls while maintaining individual user tracking for UI and email delivery.
Code Examples: Working with the Notification Manager
The following examples demonstrate how to interact with the notification system through GraphQL mutations and programmatic API usage.
Creating a Live Knowledge Trigger
Use the triggerKnowledgeLiveAdd mutation to create real-time alerts for specific entity types. This example creates a trigger that fires when new Malware objects are created:
mutation CreateLiveTrigger {
triggerKnowledgeLiveAdd(
input: {
name: "My Alert on New Malwares"
description: "Notify when a new Malware object is created"
event_types: ["create"]
notifiers: ["<notifier-id>"]
instance_trigger: false
filters: "{\"mode\":\"or\",\"filters\":[{\"key\":[\"entity_type\"],\"values\":[\"Malware\"],\"operator\":\"eq\"}]}"
recipients: []
}
) {
id
name
trigger_type
}
}
The trigger persists as an ENTITY_TYPE_TRIGGER entity and is picked up by the manager during the next live loop iteration.
Creating a Digest Trigger
Digest triggers aggregate events from multiple live triggers over specified intervals. This example configures a daily summary at 09:00 UTC:
mutation CreateDigest {
triggerKnowledgeDigestAdd(
input: {
name: "Daily Summary"
description: "Digest of all alerts"
trigger_ids: ["<trigger-id-1>", "<trigger-id-2>"]
period: day
trigger_time: "09:00:00.000Z"
notifiers: ["<notifier-id>"]
recipients: ["<user-id>"]
}
) {
id
name
trigger_type
}
}
The handleDigestNotifications function processes these configurations during the 60-second digest loop.
Starting the Manager Programmatically
For custom deployments or testing, you can manually start the notification manager using the internal API:
import notificationManager from './src/manager/notificationManager';
(async () => {
await notificationManager.start(); // spawns both live & digest intervals
})();
This initializes the Redis lock acquisition and begins processing the SSE event stream.
Key Source Files
The notification manager implementation spans several critical files in the OpenCTI-Platform/opencti repository:
src/manager/notificationManager.ts– Core manager implementation containinginitNotificationManager,notificationLiveStreamHandler, andhandleDigestNotifications.src/modules/notification/notification-types.ts– TypeScript definitions for triggers, notifications, and related GraphQL enums.src/modules/notification/notification.graphql– GraphQL schema exposingtriggerKnowledgeLiveAdd,triggerKnowledgeDigestAdd, and related queries.src/database/stream/stream-handler.ts– SSE stream processing utilities used by the notification manager.src/utils/access.ts– Access control utilities includingisUserCanAccessStreamUpdateEventandisStixMatchFilterGroup.docs/usage/notifications.md– User-facing documentation for trigger configuration and digest settings.
Summary
- The notification manager in OpenCTI is a singleton background service that monitors the platform's SSE event stream to deliver real-time and scheduled security alerts.
- It operates through two independent loops: a 10-second live loop for immediate notifications and a 60-second digest loop for aggregated summaries.
- Redis-based distributed locking (
notification_manager:lock_live_keyandnotification_manager:lock_digest_key) ensures only one API instance processes notifications in clustered deployments. - The manager evaluates triggers against incoming events using access control checks (
isUserCanAccessStreamUpdateEvent,isStixMatchFilterGroup) and generates human-readable messages viagenerateNotificationMessageForInstance. - Live notifications create immediate
KnowledgeNotificationEventobjects, while digest notifications aggregate events into scheduledDigestEventsummaries usinghandleDigestNotifications.
Frequently Asked Questions
What is the notification manager in OpenCTI?
The notification manager in OpenCTI is a background service implemented in src/manager/notificationManager.ts that continuously monitors the platform's event stream. It evaluates incoming security events against user-defined triggers and generates either immediate alerts or scheduled digest summaries for analysts, effectively automating the delivery of threat intelligence updates.
How does the notification manager handle high availability in clustered deployments?
The manager uses Redis-based distributed locking to prevent duplicate processing across multiple API instances. It attempts to acquire unique lock keys—notification_manager:lock_live_key for the 10-second live loop and notification_manager:lock_digest_key for the 60-second digest loop—ensuring only one instance acts as the active notification processor at any time while others remain in standby.
What types of triggers can I create in OpenCTI?
OpenCTI supports live triggers for real-time alerts and digest triggers for scheduled summaries. Live triggers can monitor knowledge changes (entity creation, updates, deletions) or activity events (authentication actions), with optional filters for specific entity types, markings, or individual instances. Digest triggers aggregate events from multiple live triggers over hourly, daily, weekly, or monthly periods, configurable through the triggerKnowledgeDigestAdd mutation.
How are notification messages generated from raw events?
The manager uses helper functions generateNotificationMessageForInstance and generateNotificationMessageForFilteredSideEvents to transform raw DataEvent objects into human-readable strings. These functions analyze the event type (create, update, delete), extract entity names and STIX IDs, and format concise descriptions like "[malware] WannaCry (attack-pattern--…)" that appear in the UI, emails, or webhook payloads delivered through storeNotificationEvent.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →