# How to Set Up Alerts and Scheduled Reports in Apache Superset: Email, Slack, and Webhook Configuration

> Learn to configure Apache Superset alerts and scheduled reports for email, Slack, and webhooks. Automate data notifications and gain actionable insights efficiently.

- Repository: [The Apache Software Foundation/superset](https://github.com/apache/superset)
- Tags: how-to-guide
- Published: 2026-03-03

---

**Apache Superset enables automated alerts and scheduled reports through Celery workers that evaluate SQL thresholds or capture dashboard snapshots and dispatch notifications via the `EmailNotification`, `SlackNotification`, or `WebhookNotification` classes.**

Setting up alerts and scheduled reports in Apache Superset requires configuring the underlying notification infrastructure and defining `ReportSchedule` objects that specify when and where to send data. This guide covers the complete implementation path from feature flags to production deployment, referencing the actual source code in the `apache/superset` repository.

## Core Architecture and Data Models

All scheduling logic resides in [`superset/reports/models.py`](https://github.com/apache/superset/blob/main/superset/reports/models.py). The `ReportSchedule` ORM class stores the crontab expression, SQL query (for alerts), and references to charts or dashboards. Recipients are modeled separately through the `ReportRecipient` class, which uses the `ReportRecipientType` enumeration to distinguish channels:

```python
class ReportRecipientType(StrEnum):
    EMAIL = "Email"
    SLACK = "Slack"
    SLACKV2 = "SlackV2"
    WEBHOOK = "Webhook"

# source: superset/reports/models.py#L65-L70

```

Each recipient record stores a JSON `recipient_config_json` field containing the target address, channel name, or webhook URL.

## Alert Evaluation Logic

For threshold-based alerts, Superset executes the `AlertCommand` class defined in [`superset/commands/report/alert.py`](https://github.com/apache/superset/blob/main/superset/commands/report/alert.py). The `run()` method evaluates the SQL query and applies a validator—either `NOT_NULL` or `OPERATOR`—to determine if the alert triggers:

```python
if self._is_validator_not_null:
    self._report_schedule.last_value_row_json = str(self._result)
    is_null_or_nan = self._result is None or pd.isna(self._result)
    triggered = bool(self._result != 0 and not is_null_or_nan)
else:
    # operator validator

    triggered = OPERATOR_FUNCTIONS[operator](self._result, threshold)

# source: superset/commands/report/alert.py#L83-L95

```

When `triggered` is `True`, the execution pipeline proceeds to the notification phase.

## Notification Channel Configuration

Superset dispatches messages through three primary notification classes located in `superset/reports/notifications/`. Each requires specific backend configuration.

### Email Notifications

The `EmailNotification` class in [`superset/reports/notifications/email.py`](https://github.com/apache/superset/blob/main/superset/reports/notifications/email.py) constructs HTML emails with optional CSV or PDF attachments. It relies on the SMTP helper `send_email_smtp` from [`superset/utils/core.py`](https://github.com/apache/superset/blob/main/superset/utils/core.py).

Required configuration in [`superset_config.py`](https://github.com/apache/superset/blob/main/superset_config.py):

```python
SMTP_HOST = "smtp.example.com"
SMTP_PORT = 587
SMTP_USER = "superset@example.com"
SMTP_PASSWORD = "your_secure_password"
MAIL_DEFAULT_SENDER = "superset@example.com"
EMAIL_REPORTS_SUBJECT_PREFIX = "[Superset Report]"  # default defined in superset/config.py#L1976

```

The subject line is generated dynamically:

```python
def _get_subject(self) -> str:
    return __(
        "%(prefix)s %(title)s",
        prefix=current_app.config["EMAIL_REPORTS_SUBJECT_PREFIX"],
        title=self._name,
    )

# source: superset/reports/notifications/email.py#L204-L208

```

### Slack Notifications

The `SlackNotification` class in [`superset/reports/notifications/slack.py`](https://github.com/apache/superset/blob/main/superset/reports/notifications/slack.py) supports the legacy Slack Web API. It uploads files or posts messages using the Slack SDK client retrieved from [`superset/utils/slack.py`](https://github.com/apache/superset/blob/main/superset/utils/slack.py).

Configuration in [`superset_config.py`](https://github.com/apache/superset/blob/main/superset_config.py):

```python
SLACK_API_TOKEN = "xoxb-your-bot-token"

```

The token requires `chat:write` and `files:write` scopes. The notification logic handles file uploads versus simple messages:

```python
client = get_slack_client()
channel = self._get_channel()
if files:
    client.files_upload(..., filetype=file_type)
else:
    client.chat_postMessage(channel=channel, text=body)

# source: superset/reports/notifications/slack.py#L99-L113

```

Enable the `SLACK_V2_API` feature flag to use the newer SlackNotificationV2 implementation, which is recommended for new installations.

### Webhook Notifications

The `WebhookNotification` class in [`superset/reports/notifications/webhook.py`](https://github.com/apache/superset/blob/main/superset/reports/notifications/webhook.py) posts JSON payloads to external HTTP endpoints. This channel requires explicit feature flag activation.

Enable in [`superset_config.py`](https://github.com/apache/superset/blob/main/superset_config.py):

```python
FEATURE_FLAGS = {
    "ALERT_REPORT_WEBHOOK": True,
}

```

For security, enforce HTTPS-only endpoints:

```python
ALERT_REPORTS_WEBHOOK_HTTPS_ONLY = True  # default in superset/config.py

```

The implementation constructs a POST request:

```python
wh_url = self._get_webhook_url()
response = requests.post(wh_url, json=payload, timeout=60)

# source: superset/reports/notifications/webhook.py#L24-L27

```

If the feature flag is disabled, the system raises `NotificationUnprocessableException` when attempting to create webhook recipients.

## Step-by-Step Implementation Guide

### Enable Required Feature Flags

Add the following to your [`superset_config.py`](https://github.com/apache/superset/blob/main/superset_config.py) to unlock all notification channels:

```python
FEATURE_FLAGS = {
    "ALERT_REPORT_WEBHOOK": True,      # Enable webhook notifications

    "SLACK_V2_API": True,             # Use modern Slack API

    "ALERT_REPORTS": True,            # Enable the reporting feature itself

}

```

### Configure Backend Services

Ensure your Celery workers are running with the beat scheduler enabled, as the reporting engine relies on periodic tasks defined in [`superset/tasks/scheduler.py`](https://github.com/apache/superset/blob/main/superset/tasks/scheduler.py).

Configure SMTP and Slack tokens as shown in the previous sections, then restart the Superset workers to load the new configuration.

### Create Alerts and Reports via UI

1. Navigate to **Settings** → **Alerts & Reports**.
2. Click **+ Report** or **+ Alert**.
3. Configure the **Schedule** using a crontab expression (e.g., `0 9 * * 1-5` for 9 AM weekdays).
4. For **Alerts**, provide the SQL query and threshold logic.
5. Add **Recipients** by selecting the channel type (Email, Slack, or Webhook) and entering the target address or URL.

### Programmatic Creation via Python API

For infrastructure-as-code deployments, create schedules directly using the Superset ORM:

```python
from superset.models.core import Database
from superset.reports.models import ReportSchedule, ReportRecipient, ReportRecipientType
from superset import db

# Retrieve target database

db_obj = db.session.query(Database).filter_by(database_name="production").one()

# Create the schedule

schedule = ReportSchedule(
    type="Alert",
    name="Revenue Drop Alert",
    crontab="0 */6 * * *",  # Every 6 hours

    sql="SELECT SUM(revenue) FROM daily_metrics WHERE dt = CURRENT_DATE - 1",
    validator_type="operator",
    validator_config_json='{"op":"<","threshold":50000}',
    database=db_obj,
    active=True,
)
db.session.add(schedule)
db.session.commit()

# Attach email recipient

email_recipient = ReportRecipient(
    type=ReportRecipientType.EMAIL,
    recipient_config_json='{"target":"finance@example.com"}',
    report_schedule=schedule,
)
db.session.add(email_recipient)
db.session.commit()

```

## Execution Flow and Celery Integration

Understanding the backend execution helps debug delivery failures. When a schedule fires, the following occurs:

1. **Celery Beat** reads the `crontab` field from `ReportSchedule` and enqueues a task defined in [`superset/tasks/scheduler.py`](https://github.com/apache/superset/blob/main/superset/tasks/scheduler.py).
2. The worker executes `execute_report_schedule` (defined in [`superset/commands/report/execute.py`](https://github.com/apache/superset/blob/main/superset/commands/report/execute.py)), which loads the schedule and creates a `ReportExecutionContext`.
3. If `schedule.type == "Alert"`, the system instantiates `AlertCommand` from [`superset/commands/report/alert.py`](https://github.com/apache/superset/blob/main/superset/commands/report/alert.py) to evaluate the SQL query against the configured validator.
4. Upon successful execution, the system generates a `ReportExecutionResult` containing screenshots, CSV data, or PDF attachments.
5. The notification manager iterates over `schedule.recipients` and instantiates the appropriate notification class (`EmailNotification`, `SlackNotification`, or `WebhookNotification`) to dispatch the payload.

## Testing and Debugging Notifications

Before deploying to production, validate your configuration using Superset's Python shell:

### Test Email Delivery

```python
from superset.reports.notifications.email import EmailContent, EmailNotification
from superset.reports.models import ReportRecipient, ReportRecipientType

content = EmailContent(
    body="Test alert: Revenue threshold exceeded",
    name="Revenue Alert",
    url="https://superset.example.com/chart/123",
)

recipient = ReportRecipient(
    type=ReportRecipientType.EMAIL,
    recipient_config_json='{"target":"test@example.com"}',
)

notification = EmailNotification(content, recipient)
notification.send()

```

### Test Slack Integration

```python
from superset.reports.notifications.slack import SlackNotification
from superset.reports.models import ReportRecipient, ReportRecipientType

recipient = ReportRecipient(
    type=ReportRecipientType.SLACK,
    recipient_config_json='{"target":"#test-channel"}',
)

notification = SlackNotification(content, recipient)
notification.send()

```

### Verify Alert Logic

Test your SQL threshold logic without triggering notifications:

```python
from superset.commands.report.alert import AlertCommand
from superset.reports.models import ReportSchedule
import uuid

schedule = db.session.get(ReportSchedule, 42)  # Your alert ID

command = AlertCommand(schedule, uuid.uuid4())
triggered, message = command.run()
print(f"Triggered: {triggered}, Message: {message}")

```

## Summary

- **Alerts** execute SQL queries against thresholds using `AlertCommand` in [`superset/commands/report/alert.py`](https://github.com/apache/superset/blob/main/superset/commands/report/alert.py), while **scheduled reports** capture static snapshots of charts and dashboards.
- **Notification channels** are implemented as distinct classes in `superset/reports/notifications/`: `EmailNotification` requires SMTP configuration, `SlackNotification` requires a bot token, and `WebhookNotification` requires the `ALERT_REPORT_WEBHOOK` feature flag.
- **Configuration** happens in [`superset_config.py`](https://github.com/apache/superset/blob/main/superset_config.py) through standard SMTP variables (`SMTP_HOST`, `SMTP_USER`), `SLACK_API_TOKEN`, and feature flags like `ALERT_REPORT_WEBHOOK` and `SLACK_V2_API`.
- **Execution** relies on Celery Beat reading `ReportSchedule.crontab` and dispatching tasks via [`superset/commands/report/execute.py`](https://github.com/apache/superset/blob/main/superset/commands/report/execute.py), which instantiates the appropriate notification classes based on `ReportRecipientType`.
- **Programmatic access** is available through the Superset ORM by creating `ReportSchedule` and `ReportRecipient` objects directly in [`superset/reports/models.py`](https://github.com/apache/superset/blob/main/superset/reports/models.py).

## Frequently Asked Questions

### How do I enable webhook notifications in Apache Superset?

Enable the `ALERT_REPORT_WEBHOOK` feature flag in [`superset_config.py`](https://github.com/apache/superset/blob/main/superset_config.py) by setting `FEATURE_FLAGS = {"ALERT_REPORT_WEBHOOK": True}`. Additionally, set `ALERT_REPORTS_WEBHOOK_HTTPS_ONLY = True` to restrict webhooks to HTTPS endpoints only. Once enabled, you can add webhook recipients in the Alerts & Reports UI by selecting "Webhook" and providing the target URL.

### What SMTP settings are required for email alerts?

Configure the following variables in [`superset_config.py`](https://github.com/apache/superset/blob/main/superset_config.py): `SMTP_HOST`, `SMTP_PORT` (typically 587 for TLS), `SMTP_USER`, `SMTP_PASSWORD`, and `MAIL_DEFAULT_SENDER`. Optionally customize `EMAIL_REPORTS_SUBJECT_PREFIX` to tag outgoing messages. These settings are consumed by `EmailNotification` in [`superset/reports/notifications/email.py`](https://github.com/apache/superset/blob/main/superset/reports/notifications/email.py) when constructing messages via the `send_email_smtp` utility.

### How does Superset determine if an alert should trigger?

The `AlertCommand` class in [`superset/commands/report/alert.py`](https://github.com/apache/superset/blob/main/superset/commands/report/alert.py) evaluates the alert SQL query and applies the configured validator. For `NOT_NULL` validators, it checks if the result is non-zero and not NaN. For `OPERATOR` validators, it compares the query result against a threshold using Python comparison functions. The `run()` method returns a tuple `(triggered, message)` indicating whether the notification should proceed.

### Can I create alerts and reports programmatically instead of using the UI?

Yes, you can instantiate `ReportSchedule` and `ReportRecipient` objects directly from [`superset/reports/models.py`](https://github.com/apache/superset/blob/main/superset/reports/models.py). Create a schedule with `type="Alert"` or `type="Report"`, set the `crontab` string, SQL query (for alerts), and validator configuration. Then append `ReportRecipient` instances with `type=ReportRecipientType.EMAIL`, `SLACK`, or `WEBHOOK` and the appropriate JSON configuration in `recipient_config_json`. Commit these to the database using the Superset application context.