Getting Started
Installation
Install dread with a single command. The script downloads the correct binary for your platform and sets up a background service for desktop notifications.
curl -sSL dread.sh/install | sh
This will:
- Download the
dreadbinary to~/.local/bin - Automatically add
~/.local/binto your PATH (no sudo required) - Set up a background service (
launchdon macOS,systemdon Linux, Task Scheduler on Windows) for desktop notifications - Start listening for webhook events immediately
Supported platforms: macOS, Linux, and Windows (amd64 and arm64). Re-run the same command to update to the latest version.
Your First Channel
A channel is a webhook endpoint. Create one for each service you want to receive events from.
$ dread new "Stripe Prod"
Created channel: Stripe Prod (ch_stripe-prod_a1b2c3)
Webhook URL: https://dread.sh/wh/ch_stripe-prod_a1b2c3
The command prints the channel ID and a webhook URL you can paste into any service's webhook settings.
Wire Up a Webhook
Copy the webhook URL from the previous step and paste it into your service's webhook configuration (Stripe dashboard, GitHub repo settings, Slack app config, etc.).
Once the service starts sending events, you'll see them immediately:
# paste the URL into Stripe, GitHub, Slack, Linear...
# notifications start automatically
$ dread # open the TUI to see events live
Desktop notifications fire automatically from the background service. Open the TUI anytime to browse events with full payload inspection.
TUI Features
Header & Logo
When you launch dread, the TUI displays a 3-column header inside a rounded box:
- Left column — ASCII art DREAD logo in the brand brown colour, with the version number below
- Centre column — time-of-day greeting, connected channel count, session uptime, channel health dots, and success/failure/neutral event counts
- Right column — total event count, events-per-minute rate, a sparkline showing event volume over the last hour, and rotating command tips that cycle every 5 seconds
The header is always visible and updates in real time as events arrive.
Status Indicators
Each event in the TUI list (and in the web dashboard) is classified and shown with a coloured dot:
- ● Green — success events (keywords: succeeded, completed, paid, captured, created, active, resolved, delivered, merged, approved, ready)
- ● Red — failure events (keywords: fail, error, denied, declined, expired, canceled, refused, rejected, dispute, alert, incident, critical, warning, overdue)
- ● Gray — neutral events that don't match either category
Classification is based on keyword matching against the event type and summary fields. This works automatically with any webhook source.
Sparkline & Health
The header's right column includes a Unicode sparkline (using block characters ▁▂▃▄▅▆▇█) that visualises event volume over the last 60 minutes in twelve 5-minute buckets.
Channel health dots appear in the centre column. Each channel shows a dot that is green if it received an event within the last 30 minutes, or gray if it's stale. This gives a quick at-a-glance view of which integrations are actively sending.
The TUI also checks /api/version on startup and displays a notification in the header if a newer version of dread is available.
Split Pane
Press s to toggle a master-detail split view. The screen divides into two halves: the event list on the left and the payload detail on the right. Selecting an event in the list instantly updates the right pane without leaving the list.
This is ideal for debugging — you can navigate through events with j/k while continuously seeing the full payload beside it.
Tabs & Stats
The TUI has three tabs, switched with number keys:
1Live — the full event stream (default)2Errors — auto-filtered to show only failure events (errors, denials, alerts, etc.)3Stats — bar charts showing events by source, success/failure/neutral breakdown with percentages, and a 7-day × 24-hour activity heatmap
The Errors tab directly serves the core use case: quickly seeing what failed. The Stats tab gives a bird's-eye view of webhook traffic patterns.
Pause & Toasts
Press p or Space to pause the live event feed. While paused, new events are buffered in the background and a counter shows how many are waiting. Press p again to unpause and flush all buffered events.
When a failure event arrives (regardless of pause state), a red toast notification appears above the footer showing the source and summary. Toasts auto-dismiss after 5 seconds. Up to 3 toasts can be visible at once.
Advanced Filters
Press / to open the filter prompt. The filter supports several modes:
- Substring match — type any text to match against source, type, summary, channel, and the raw JSON payload
- Exclusion — prefix with
!to exclude matching events (e.g.,!test) - Field-specific — use
source:stripe,type:checkout, orchannel:prodto filter by a specific field - Filter history — press
↑/↓in the filter prompt to browse previous filters
Deep payload search is also supported — filtering searches inside the raw JSON body, so you can find events by a customer ID or charge amount buried in the payload.
Bookmarks
Press f to star/bookmark any event. Bookmarked events show a ★ indicator in the event list and the header shows a total bookmark count.
Press F to toggle bookmark-only view, filtering the list to show only bookmarked events. Press F again to return to the full list.
Auto-Diff
Press d in the detail view to see a line-by-line diff of the current event's payload compared to the previous event from the same source. Added lines are shown in green, removed lines in red. Press d again to return to the normal payload view.
Event Grouping
Press g to toggle event grouping. When enabled, consecutive events with the same source and type within 60 seconds are collapsed into a single row with a ×N badge showing the burst count. This reduces noise from high-volume event sources.
Command Palette
Press Ctrl+P to open a command palette overlay with fuzzy search. Type to filter commands, use ↑↓ to navigate, and Enter to execute. All major TUI actions are available through the palette.
Mouse Support
The TUI supports mouse interaction. Click on an event in the list to select it. Scroll to navigate. In split pane mode, clicking an event also updates the detail pane.
HTML Export
Press x to export the current session as a styled HTML report. The export includes all filtered events with timestamps, sources, types, summaries, status classification, and collapsible JSON payloads. The file is saved to the current directory.
Forward Response Capture
When using --forward, each forwarded event now shows a status badge in the event list (e.g. →200 for success, →err for failures). In the detail view, the full forward response is shown including HTTP status code, response headers, response body, and round-trip duration.
Swimlane Timeline
The Stats tab (press 3) now includes a swimlane timeline visualization showing per-source event activity over the last 60 minutes. Each source gets its own horizontal lane with filled blocks indicating minutes with activity.
CLI Reference
dread
Launch the interactive terminal UI. Shows a live feed of webhook events across all your channels with full payload inspection.
$ dread [flags]
| Flag | Default | Description |
|---|---|---|
--server | dread.sh | Server URL to connect to |
--filter | Filter events by substring (source, type, summary, channel) | |
--forward | Forward incoming events to a URL |
Keybindings:
| Key | Action |
|---|---|
q | Quit |
j / k | Navigate up / down |
enter | View event detail & payload |
/ | Filter events |
r | Replay event |
c | Copy webhook URL (list) or payload (detail) |
p / Space | Pause / resume live feed |
s | Toggle split pane (list + detail side-by-side) |
? | Show help overlay with all keybindings |
1 | Live tab (all events) |
2 | Errors tab (failures only) |
3 | Stats tab (charts, heatmap & swimlane) |
f | Bookmark / unbookmark event |
F | Toggle bookmarks-only view |
d | Diff with previous same-source event |
g | Toggle event grouping |
x | Export session as HTML |
Ctrl+P | Command palette |
esc | Back / clear filter |
dread new
Create a new webhook channel. Returns the channel ID and the webhook URL to paste into your service.
$ dread new <name>
Example:
$ dread new "GitHub Deploys"
Created channel: GitHub Deploys (ch_github-deploys_d4e5f6)
Webhook URL: https://dread.sh/wh/ch_github-deploys_d4e5f6
dread list
Show all channels with their IDs and webhook URLs.
$ dread list
Stripe Prod ch_stripe-prod_a1b2c3 https://dread.sh/wh/ch_stripe-prod_a1b2c3
GitHub Deploys ch_github-deploys_d4e5f6 https://dread.sh/wh/ch_github-deploys_d4e5f6
Sentry Alerts ch_sentry-alerts_g7h8i9 https://dread.sh/wh/ch_sentry-alerts_g7h8i9
dread logs
Print recent webhook events to stdout. Useful for scripting or quick checks without opening the TUI.
$ dread logs [--limit N]
| Flag | Default | Description |
|---|---|---|
--limit | 20 | Number of events to show |
Example:
$ dread logs --limit 5
2m ago stripe invoice.paid $249.00
5m ago github PR merged #139 → main
12m ago sentry TypeError: Cannot read prop…
18m ago linear Issue ENG-481 moved to Done
25m ago slack #deploys: Production deploy v2.4.1
dread status
Show channel overview, last event timestamps, and background service info.
$ dread status
Channels: 3
Stripe Prod last event 2m ago
GitHub Deploys last event 5m ago
Sentry Alerts last event 12m ago
Service: running (launchd)
Server: dread.sh (connected)
dread test
Send a test webhook event to a channel. Useful for verifying your setup end-to-end.
$ dread test <channel-id>
Example:
$ dread test ch_stripe-prod_a1b2c3
Sent test event to Stripe Prod (ch_stripe-prod_a1b2c3)
dread add / remove
Manually subscribe to or unsubscribe from individual channels by ID.
$ dread add <channel-id> "Display Name"
$ dread remove <channel-id>
Example:
$ dread add ch_stripe-prod_a1b2c3 "Stripe Prod"
Added channel: Stripe Prod
$ dread remove ch_stripe-prod_a1b2c3
Removed channel: ch_stripe-prod_a1b2c3
dread watch
Run in headless notification mode. No TUI — just desktop notifications. The background service uses this internally, but you can run it manually too.
$ dread watch [flags]
| Flag | Default | Description |
|---|---|---|
--server | dread.sh | Server URL to connect to |
--filter | Only notify on matching events |
Auto-reconnects after 3 seconds if the connection drops.
dread service
Install or remove a background service so dread watch runs automatically — even after the terminal is closed or the machine restarts.
$ dread service install
Background service installed and started.
Plist: ~/Library/LaunchAgents/dev.dread.watch.plist
Logs: ~/Library/Logs/dread.log
Notifications will now appear even when the terminal is closed.
| Subcommand | Description |
|---|---|
install | Install and start the background service (launchd on macOS, systemd on Linux, Task Scheduler on Windows) |
uninstall | Stop and remove the background service |
On macOS, this creates a launchd agent that starts at login and auto-restarts on failure. On Linux, it creates a systemd user service. On Windows, it creates a Task Scheduler task that runs at logon. Logs are written to ~/Library/Logs/dread.log (macOS) or available via journalctl --user -u dread-watch (Linux).
Use dread status to check whether the background service is running.
dread replay
Re-forward a past event to a URL. Fetches the full event payload from the server and POSTs it to the target.
$ dread replay <event-id> --forward <url>
Example:
$ dread replay evt_abc123 --forward http://localhost:3000/webhook
Replayed evt_abc123 → http://localhost:3000/webhook (200 OK)
Webhooks
How It Works
When a service sends a POST request to your channel's webhook URL:
- The server receives the payload at
POST /wh/{channel-id} - It auto-detects the source (Stripe, GitHub, etc.) from request headers
- It extracts the event type and a human-readable summary
- The event is stored server-side and broadcast to all connected clients via WebSocket
- Your desktop notification fires, and the TUI updates in real time
Supported Sources
dread auto-detects 60+ webhook sources from HTTP headers. Any unrecognised source is labelled "webhook" — add ?source=name to your webhook URL to label it yourself.
| Category | Sources |
|---|---|
| Payment & Finance | Stripe, PayPal, Square, Razorpay, Paddle, Recurly, Coinbase, Plaid, Xero, QuickBooks |
| Dev & Code | GitHub, GitLab, Bitbucket, CircleCI, Travis CI, Buildkite |
| Infrastructure | Vercel, Heroku, AWS SNS, Cloudflare |
| Communication | Slack, Discord, Twilio, SendGrid, Mailchimp, Zendesk, Telegram, LINE |
| Project Management | Linear, Jira, Notion, Trello, Airtable |
| Monitoring | Sentry, PagerDuty, Grafana, Pingdom |
| CMS & Commerce | Shopify, WooCommerce, Contentful, Sanity, BigCommerce |
| Auth & Identity | Auth0, WorkOS, Svix (Clerk, Resend) |
| Database | Supabase, PlanetScale |
| SaaS | HubSpot, Typeform, Calendly, DocuSign, Zoom, Figma, Knock, Novu, LaunchDarkly, Customer.io, Pusher, Ably, Twitch, Zapier |
Custom Webhooks
You can send webhooks from your own services. Just POST JSON to your channel URL:
$ curl -X POST https://dread.sh/wh/ch_my-channel_abc123 \
-H "Content-Type: application/json" \
-d '{"event": "deploy.success", "env": "production"}'
To set a custom source name, add ?source=name to your webhook URL:
https://dread.sh/wh/ch_my-channel_abc123?source=trigger.dev
This works with any service — just append ?source= when pasting the URL into your webhook settings. You can also use the X-Dread-Source header for programmatic control:
$ curl -X POST https://dread.sh/wh/ch_my-channel_abc123 \
-H "Content-Type: application/json" \
-H "X-Dread-Source: my-app" \
-d '{"event": "deploy.success", "env": "production"}'
Team Workspaces
Sharing a Workspace
A workspace is your collection of channels. Share it with your team so everyone gets the same webhook feeds.
$ dread share
Share this with your team:
dread follow ws_a1b2c3d4e5f6
They'll get all your channels (and any you add later).
The workspace ID is generated from your local config. Running dread share publishes your current channel list to the server.
Following a Workspace
Teammates run a single command to subscribe to all channels in a workspace:
$ dread follow ws_a1b2c3d4e5f6
Following workspace ws_a1b2... (3 channels):
Stripe Prod ch_stripe-prod_a1b2c3
GitHub Deploys ch_github-deploys_d4e5f6
Sentry Alerts ch_sentry-alerts_g7h8i9
New channels will sync automatically.
To stop following:
$ dread unfollow ws_a1b2c3d4e5f6
Unfollowed workspace ws_a1b2c3d4e5f6
Auto-Sync
When the workspace owner adds new channels, followers pick them up automatically on their next reconnect. No action needed — the background service handles it.
The sync happens every time the WebSocket connection is established (on startup, after a network drop, etc.). Any new channels in the workspace are added to the follower's local config automatically.
Notifications
Desktop Notifications
dread sends native desktop notifications for every webhook event. Run dread service install to set up a background service that starts at login and keeps running even after the terminal is closed.
$ dread service install
- macOS — uses a native notifier with sound. Notifications appear in Notification Centre.
- Linux — uses
notify-send. Works with any desktop environment that supports freedesktop notifications. - Windows — uses Windows toast notifications via PowerShell. Works on Windows 10 and later.
This installs a launchd agent (macOS), systemd user service (Linux), or Task Scheduler task (Windows) that auto-restarts on failure. To remove it, run dread service uninstall.
Custom notification sound
Set the "sound" field in your config to change the notification sound (default: Sosumi):
{
"token": "dk_...",
"channels": [...],
"sound": "Hero"
}
macOS built-in sounds: Basso, Blow, Bottle, Frog, Funk, Glass, Hero, Morse, Ping, Pop, Purr, Sosumi, Submarine, Tink
You can also use custom sounds on macOS by placing a .aiff file in ~/Library/Sounds/ and referencing it by name (without extension).
Linux: uses freedesktop sound names (e.g. message-new-instant). Support varies by desktop environment.
You can also change the sound from the web dashboard — open the sidebar and use the Notification Sound dropdown. Changes are saved to the workspace and synced to team members.
Watch Mode
Run the notification daemon manually without the TUI:
$ dread watch
Watch mode is headless — it connects to the server, listens for events, and fires desktop notifications. If the connection drops, it auto-reconnects after 3 seconds.
This is the same process the background service runs. You can use it directly for debugging or if you prefer to manage the process yourself.
Filtering Events
Use the --filter flag to only see events matching a pattern. The filter is a case-insensitive substring match against source, type, summary, and channel name.
# only show Stripe events in the TUI
$ dread --filter stripe
# only get notifications for payment events
$ dread watch --filter payment
# filter for a specific channel
$ dread --filter "GitHub Deploys"
In the TUI, press / to open the filter prompt interactively.
Forwarding & Replay
Forward to Localhost
Forward webhook events to a local development server in real time:
$ dread --forward http://localhost:3000/webhook
Every event that arrives is POSTed to the target URL with the original payload. dread adds the following headers for context:
| Header | Description |
|---|---|
X-Dread-Source | Detected source (stripe, github, etc.) |
X-Dread-Event-Type | Event type (invoice.paid, push, etc.) |
X-Dread-Channel | Channel ID |
X-Dread-Event-Id | Unique event ID |
Forwarding uses a 10-second timeout per request. The TUI continues to work normally while forwarding.
Replay Past Events
Re-forward any past event to a URL. Useful for debugging webhook handlers without waiting for the real event to happen again.
$ dread replay <event-id> --forward <url>
Example:
$ dread replay evt_abc123 --forward http://localhost:3000/webhook
Replayed evt_abc123 → http://localhost:3000/webhook (200 OK)
The event is fetched from the server and POSTed to the target with the same X-Dread-* headers. You can find event IDs in the TUI detail view or from dread logs.
Web Dashboard
Overview
The web dashboard at /dashboard lets you view your live event feed in the browser without installing the CLI. It uses the same APIs as the CLI — no extra backend required.
The workspace ID in the URL is the access key, same as the rest of the app. Anyone with the workspace ID can view the dashboard.
Connecting
Visit /dashboard and enter your workspace ID (e.g. ws_230a2bc06cb0). Find your workspace ID by running:
$ dread share
The dashboard remembers your last workspace ID in localStorage. You can also share direct links:
https://dread.sh/dashboard?ws=ws_230a2bc06cb0
Features
- Channel sidebar — lists all channels with their webhook URLs and copy buttons
- Live event feed — events stream in real-time via WebSocket, with channel name, source, type, and summary
- JSON payload viewer — click any event row to expand and see the full payload with syntax highlighting
- Filter — search events by source, type, channel, or summary text
- Pause/resume — pause the live stream to inspect events; buffered events flush on resume
- Load more — scroll to the bottom and load older events with pagination
- Tab notifications — unread event count appears in the browser tab title when the tab is in the background
- Theme toggle — dark/light theme, same as the rest of the site
- Mobile responsive — sidebar collapses to a hamburger menu on small screens
- Mute toggle — per-channel mute via localStorage, suppresses browser notifications
- Export — download events as JSON or CSV from the toolbar, or export as styled HTML
- Replay — re-send any event to a URL from the event detail view
- Bookmarks — star/bookmark events with ★, toggle bookmark-only view to filter to important events
- Advanced filtering —
source:stripe,type:checkout,!errorexclusion, and free-text search - Stats panel — toggle source breakdown bars, success/failure/neutral status chart, and per-source swimlane timeline
- Diff view — compare any event with the previous event from the same source, showing added/removed lines
- Keyboard shortcuts —
j/knavigate,/filter,fbookmark,ddiff,sstats,?help overlay - HTML export — download the current session as a styled HTML report with collapsible payloads
Muting Channels
Temporarily silence a noisy channel without unsubscribing:
dread mute ch_noisy_abc123
dread unmute ch_noisy_abc123
Muted channels continue receiving events server-side but won't trigger desktop notifications in watch mode or the TUI. The dashboard also offers a per-channel mute toggle saved in localStorage.
Alert Rules
Set threshold alerts to fire when a pattern matches too many events in a time window:
# Alert when 5+ sentry events in 10 minutes
dread alert add sentry 5 10
# List configured rules
dread alert list
# Remove a rule by index
dread alert remove 0
When the threshold is reached, you'll get a desktop notification. If Slack/Discord forwarding is configured, the alert is forwarded there too. Counters are in-memory and reset on restart.
Slack / Discord Forwarding
Forward webhook events to Slack or Discord in real time via dread watch:
dread watch --slack https://hooks.slack.com/services/T.../B.../xxx
dread watch --discord https://discord.com/api/webhooks/123/abc
Or set the URLs in ~/.config/dread/config.json:
{
"slack_url": "https://hooks.slack.com/services/...",
"discord_url": "https://discord.com/api/webhooks/..."
}
Forwarding runs client-side in your dread watch process. Events are sent as rich messages — Slack uses blocks, Discord uses embeds.
Export Events
Download events as JSON or CSV via the API (capped at 1000 per request):
curl "https://dread.sh/api/export?channels=ch_xxx&format=csv" -o events.csv
curl "https://dread.sh/api/export?channels=ch_xxx&format=json" -o events.json
The dashboard also includes an Export button in the toolbar.
Daily Digest
Get a summary of recent event activity:
dread digest # last 24 hours
dread digest --hours 8 # last 8 hours
Shows total event count, breakdown by source, and the 10 most recent events. Also available via API: GET /api/digest?channels=ch_xxx&hours=24
Status Page
Every workspace gets a public status page showing channel freshness:
https://dread.sh/status/ws_abc123def456
Channels are colour-coded by time since last event: green (<5min), yellow (<30min), red (>30min), grey (no events). The page auto-refreshes every 30 seconds.