---
name: sending-notifications-d90d7e9e4a0b
description: 'How to send real-time in-app notifications from PostHog backend code. Use when integrating notifications into a new feature, wiring up a notification source (alerts, comments, approvals, pipelines, issues), or choosing the right target type and priority for a notification.'
---

# Sending real-time notifications

## When to use this

You're adding notification support to a PostHog feature — for example, notifying a user when they're mentioned in a comment, when an alert fires, or when an approval is requested.

## The facade API

All notification creation goes through a single function. Import from the facade, not from internal modules:

```python
from products.notifications.backend.facade.api import (
    create_notification,
    NotificationData,
    NotificationType,
    Priority,
    TargetType,
)
```

Build a `NotificationData` and call `create_notification`:

```python
event = create_notification(
    NotificationData(
        team_id=team.id,
        notification_type=NotificationType.ALERT_FIRING,
        priority=Priority.CRITICAL,
        title="Event ingestion latency > 30s",
        body="Events are queuing up. Ingestion pipeline is degraded.",
        target_type=TargetType.USER,
        target_id=str(user.id),
        resource_type="dashboard",
        resource_id="42",
        source_url="/dashboard/42",
    )
)
```

Returns a `NotificationEvent` on success, or `None` if the feature flag is disabled, no recipients were resolved, or the team doesn't exist. Safe to call in any context.

## NotificationData fields

**Required:**

| Field               | Type               | Description                                                                |
| ------------------- | ------------------ | -------------------------------------------------------------------------- |
| `team_id`           | `int`              | Team context — used to look up the organization and check the feature flag |
| `notification_type` | `NotificationType` | Determines the icon in the UI                                              |
| `title`             | `str`              | Notification headline (~100 chars recommended)                             |
| `body`              | `str`              | Longer description shown on expand. Can be empty string                    |
| `target_type`       | `TargetType`       | Who receives this: `user`, `team`, `organization`, or `role`               |
| `target_id`         | `str`              | ID of the target (user ID, team ID, org UUID, or role UUID as string)      |

**Optional:**

| Field           | Type                               | Default  | Description                                                                                                                                                                                   |
| --------------- | ---------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `resource_type` | `NotificationResourceType \| None` | `None`   | Access-controlled types (e.g. `"dashboard"`) auto-filter recipients without viewer access                                                                                                     |
| `resource_id`   | `str`                              | `""`     | ID of the resource for linking                                                                                                                                                                |
| `source_url`    | `str`                              | `""`     | Relative URL path (e.g. `/dashboard/42`), shown as link icon in UI                                                                                                                            |
| `priority`      | `Priority`                         | `NORMAL` | `normal` = popover only; `critical` = popover + persistent toast                                                                                                                              |
| `archivable`    | `bool`                             | `False`  | Opt in to a per-recipient "archive" (dismiss) action that moves the notification to the recipient's Archived tab. When `False`, recipients can only mark it read/unread (the default pattern) |
| `resolver`      | `RecipientsResolver \| None`       | `None`   | Custom recipient resolver. Default handles user/team/org/role targeting                                                                                                                       |

## Choosing parameters

### Notification type

| Type                 | When to use                                      |
| -------------------- | ------------------------------------------------ |
| `comment_mention`    | User was @mentioned in a comment or discussion   |
| `alert_firing`       | A monitoring alert threshold was breached        |
| `approval_requested` | A change requires the user's approval            |
| `approval_resolved`  | An approval the user requested has been resolved |
| `pipeline_failure`   | A data pipeline or batch export failed           |
| `issue_assigned`     | An error tracking issue was assigned to the user |

### Priority

**Be very careful with `critical`.** It triggers a persistent toast popup that overlays the user's screen and must be manually dismissed. This is intentionally intrusive — reserve it for genuine emergencies like outages, security alerts, or SLA breaches. Overusing `critical` will train users to ignore notifications entirely. When in doubt, use `normal`.

### Target type

| Target         | `target_id` value | Recipients                             |
| -------------- | ----------------- | -------------------------------------- |
| `user`         | User ID           | Just that user                         |
| `team`         | Team ID           | All members of the team's organization |
| `organization` | Organization ID   | All organization members               |
| `role`         | Role ID           | All users with that RBAC role          |

### Resource type and access control

When `resource_type` matches an access-controlled resource (dashboard, feature_flag, experiment, etc.), recipients without `viewer` access are automatically excluded. For notification-only types (`pipeline`, `approval`, `comment`), no AC filtering is applied.

## Delivery pipeline

```text
Django (create_notification)
  → Postgres (NotificationEvent row)
  → Kafka (notification_events topic, on transaction commit)
  → Go livestream service (Kafka consumer)
  → Redis SPUBLISH (sharded pub/sub, keyed by org ID)
  → SSE (/notifications endpoint)
  → Browser (popover + optional toast)
```

Kafka publish happens on `transaction.on_commit` — won't fire if the transaction rolls back.

## Adding a new notification type

1. Add enum value in `products/notifications/backend/facade/enums.py`
2. Add icon mapping in `frontend/src/lib/components/NotificationsMenu/notificationToasts.tsx` (`NOTIFICATION_TYPE_ICONS`) — the single icon source, read by `getNotificationIcon`, which only `NotificationRow` calls; the side panel gets the icon by rendering that row
3. Add a label + description entry in `frontend/src/lib/components/NotificationsMenu/NotificationRow.tsx` (`REALTIME_NOTIFICATION_TYPE_META`) — drives the per-type notification preferences UI
4. Run `python manage.py makemigrations notifications`

## Testing

Mock the feature flag in tests:

```python
from unittest.mock import patch

with patch("posthoganalytics.feature_enabled", side_effect=lambda flag, *a, **kw: flag == "real-time-notifications"):
    event = create_notification(data)
```


---
Source attribution: PostHog
Original project: https://github.com/PostHog/posthog
License: MIT
License information: https://opensource.org/license/mit
Original upstream instructions; downloaded from Dave AI.

## Upstream license notice

MIT License

Copyright (c) 2026 Gabriel Moreira

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



# Dave AI resource metadata

Creator / publisher: PostHog
Original project: https://github.com/PostHog/posthog
Attribution basis: Upstream repository explicitly recorded in package mirror path

Fields of work: Development & Engineering, Product Management
Roles: Backend Developer, Growth Product Manager, Product Manager
Specialties: Backend
Tools: Posthog
Country applicability: Country not specified
Classification basis: Source catalog labels
Instruction SHA-256: 944b9f1e72d93a541f44f56f3cea1a8b372a402d56a83c24754890f2630dfc66
