Send IRC notifications to external services like Pushover when you're highlighted in IRC.
- Get notifications on your phone or other devices when highlighted/mentioned in IRC
- Supports multiple notification services:
- Pushover - Popular push notification service
- Prowl - iOS push notifications (Growl compatible)
- ntfy.sh - Open-source, self-hostable notification service
- Generic Webhook - Send to any webhook endpoint (Discord, Slack, Mattermost, etc.)
- Smart filtering to avoid notification spam
- Only notify when away (optional)
- Deduplication to prevent spam
- Easy command-based configuration
- Service-agnostic architecture for easy expansion
- TheLounge 4.0.0 or higher
- Node.js 14.0.0 or higher
- A Pushover account (free tier works great)
-
Navigate to your TheLounge home directory:
cd ~/.thelounge
-
Install the plugin:
npm install thelounge-plugin-external-notify
-
Restart TheLounge:
thelounge restart
- Sign up for a free account at pushover.net
- Note your User Key from the dashboard
- Create an application at pushover.net/apps/build
- Note your API Token for the application
- Download Prowl from the App Store
- Create an account or sign in to the Prowl app
- Get your API key from prowlapp.com/api_settings.php
- Note your 40-character API Key
- Choose a unique topic name (e.g.,
thelounge-yourname) - Optional: Set up your own ntfy server at docs.ntfy.sh/install
- Install the ntfy app on your device:
- Android: Google Play
- iOS: App Store
- Web: ntfy.sh/app
- Subscribe to your topic in the ntfy app
Works with any service that accepts webhooks:
- Discord: Create a webhook in Server Settings → Integrations → Webhooks
- Slack: Create an incoming webhook app
- Mattermost: Create an incoming webhook
- Custom: Any HTTP endpoint that accepts POST requests
The easiest way to configure the plugin is directly from IRC. Choose your preferred service:
/notify config pushover userKey YOUR_30_CHARACTER_USER_KEY
/notify config pushover apiToken YOUR_30_CHARACTER_API_TOKEN
/notify enable
/notify test
/notify config prowl apiKey YOUR_40_CHARACTER_API_KEY
/notify enable
/notify test
/notify config ntfy topic thelounge-yourname
/notify enable
/notify test
/notify config webhook url https://your-webhook-url
/notify enable
/notify test
For Discord webhooks:
/notify config webhook url https://discord.com/api/webhooks/YOUR_WEBHOOK
/notify config webhook bodyTemplate '{"content": "**{{title}}**\n{{message}}"}'
/notify enable
The configuration is automatically saved to your user config file.
If you prefer to edit the config file directly, you can also manually add the configuration to your network object in ~/.thelounge/users/<username>/<network>.json:
{
"externalNotify": {
"enabled": true,
"services": {
"pushover": {
"enabled": true,
"userKey": "your-30-character-user-key-here",
"apiToken": "your-30-character-api-token-here",
"priority": 0,
"sound": "pushover"
}
},
"filters": {
"onlyWhenAway": true,
"highlights": true
}
}
}You can configure all settings from within IRC using the /notify config command:
/notify config pushover userKey YOUR_USER_KEY
/notify config pushover apiToken YOUR_API_TOKEN
/notify config pushover priority 0 # -2 to 2
/notify config pushover sound cosmic # Any Pushover sound
/notify config filter onlyWhenAway true # true or false
/notify config filter highlights true # true or false
All changes are automatically saved to your user configuration file.
- userKey: Your 30-character Pushover user key (required)
- apiToken: Your 30-character Pushover API token (required)
- priority: Notification priority (-2 to 2, default: 0)
-2: No notification, just badge update-1: Quiet notification0: Normal priority (default)1: High priority, bypasses quiet hours2: Emergency priority, requires acknowledgment
- sound: Notification sound (default: "pushover", see Pushover sounds)
- apiKey: Your 40-character Prowl API key (required)
- priority: Notification priority (-2 to 2, default: 0)
-2: Very Low-1: Moderate0: Normal (default)1: High2: Emergency
- application: Application name shown in notification (default: "TheLounge", max 256 chars)
- topic: Your unique topic name (required)
- server: ntfy server URL (default: "https://ntfy.sh")
- priority: Notification priority (1-5, default: 3)
1: Min priority3: Default priority5: Max priority
- tags: Comma-separated tags (default: "", example: "irc,thelounge")
- url: Webhook URL to POST notifications to (required)
- method: HTTP method (default: "POST", options: GET, POST, PUT, PATCH)
- contentType: Content-Type header (default: "application/json")
- headers: Custom headers as JSON string (default: "{}", example: '{"Authorization": "Bearer TOKEN"}')
- bodyTemplate: JSON template for request body (default: '{"title": "{{title}}", "message": "{{message}}", "timestamp": "{{timestamp}}"}')
- Use
{{title}},{{message}},{{timestamp}}as placeholders
- Use
Common Webhook Templates:
- Discord:
'{"content": "**{{title}}**\n{{message}}"}' - Slack:
'{"text": "{{title}}", "blocks": [{"type": "section", "text": {"type": "mrkdwn", "text": "{{message}}"}}]}' - Mattermost:
'{"text": "**{{title}}**\n{{message}}"}'
- onlyWhenAway: Only send notifications when marked as away (default:
true) - highlights: Notify when your nickname is mentioned (default:
true)
Note: TheLounge has built-in highlight configuration in Settings > Highlights. This plugin respects those settings when determining what triggers a notification.
All commands are used with /notify in any channel or private message.
/notify status Show current configuration and status
/notify enable Enable notifications
/notify disable Disable notifications
/notify config Configure settings interactively
/notify test Send a test notification
/notify help Show help message
/notify setup pushover Show Pushover setup instructions
/notify setup prowl Show Prowl setup instructions
/notify setup ntfy Show ntfy.sh setup instructions
/notify setup webhook Show generic webhook setup instructions
You can customize how notifications are formatted using template variables. This allows you to control exactly what information is displayed in the notification title and message.
{{network}}- IRC network name (e.g., "freenode"){{channel}}- Channel name or "PM" for private messages (e.g., "#lounge"){{nick}}or{{user}}- Sender's nickname (e.g., "john"){{message}}or{{text}}- Message content{{date}}- Formatted date/time (e.g., "Jan 15, 14:30"){{time}}- Time only (e.g., "14:30"){{timestamp}}- ISO timestamp (e.g., "2025-01-15T14:30:00.000Z"){{type}}- Message type ("message", "action", "notice")
/notify config format title "{{network}}"
/notify config format message "<{{nick}}> {{message}}"
/notify config format actionMessage "* {{nick}} {{message}}"
/notify config format reset
Default Format (channel messages):
- Title:
freenode - #lounge - Message:
<john> Hello everyone
Default Format (private messages):
- Title:
freenode - Message:
<john> Hi there
With timestamps:
/notify config format message "{{time}} <{{nick}}> {{message}}"
Result: 14:30 <john> Hello everyone
Minimal format:
/notify config format title "{{network}}"
/notify config format message "{{nick}}: {{message}}"
Result:
- Title:
freenode - Message:
john: Hello everyone
Detailed format:
/notify config format title "{{network}} / {{channel}} @ {{time}}"
/notify config format message "[{{type}}] {{nick}}: {{message}}"
Result:
- Title:
freenode / #lounge @ 14:30 - Message:
[message] john: Hello everyone
{
"enabled": true,
"services": {
"pushover": {
"enabled": true,
"userKey": "your-user-key",
"apiToken": "your-api-token",
"priority": 0,
"sound": "pushover"
}
},
"filters": {
"onlyWhenAway": true,
"highlights": true
}
}{
"enabled": true,
"services": {
"pushover": {
"enabled": true,
"userKey": "your-user-key",
"apiToken": "your-api-token",
"priority": 1,
"sound": "cosmic"
}
},
"filters": {
"onlyWhenAway": false,
"highlights": true
}
}{
"enabled": true,
"services": {
"pushover": {
"enabled": true,
"userKey": "your-user-key",
"apiToken": "your-api-token",
"priority": -1,
"sound": "none"
}
},
"filters": {
"onlyWhenAway": true,
"highlights": true
}
}{
"enabled": true,
"services": {
"prowl": {
"enabled": true,
"apiKey": "your-40-character-api-key",
"priority": 0,
"application": "TheLounge"
}
},
"filters": {
"onlyWhenAway": true,
"highlights": true
}
}{
"enabled": true,
"services": {
"ntfy": {
"enabled": true,
"server": "https://ntfy.sh",
"topic": "thelounge-yourname",
"priority": 3,
"tags": "irc,thelounge"
}
},
"filters": {
"onlyWhenAway": true,
"highlights": true
}
}{
"enabled": true,
"services": {
"ntfy": {
"enabled": true,
"server": "https://ntfy.example.com",
"topic": "irc-notifications",
"priority": 4,
"tags": ""
}
},
"filters": {
"onlyWhenAway": false,
"highlights": true
}
}{
"enabled": true,
"services": {
"webhook": {
"enabled": true,
"url": "https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN",
"method": "POST",
"contentType": "application/json",
"headers": "{}",
"bodyTemplate": "{\"content\": \"**{{title}}**\\n{{message}}\"}"
}
},
"filters": {
"onlyWhenAway": true,
"highlights": true
}
}{
"enabled": true,
"services": {
"webhook": {
"enabled": true,
"url": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL",
"method": "POST",
"contentType": "application/json",
"headers": "{}",
"bodyTemplate": "{\"text\": \"{{title}}\", \"blocks\": [{\"type\": \"section\", \"text\": {\"type\": \"mrkdwn\", \"text\": \"{{message}}\"}}]}"
}
},
"filters": {
"onlyWhenAway": false,
"highlights": true
}
}You can use multiple services simultaneously:
{
"enabled": true,
"services": {
"pushover": {
"enabled": true,
"userKey": "your-user-key",
"apiToken": "your-api-token",
"priority": 0,
"sound": "pushover"
},
"prowl": {
"enabled": true,
"apiKey": "your-40-character-api-key",
"priority": 0,
"application": "TheLounge"
},
"ntfy": {
"enabled": true,
"server": "https://ntfy.sh",
"topic": "thelounge-backup",
"priority": 3,
"tags": "irc"
}
},
"filters": {
"onlyWhenAway": true,
"highlights": true
}
}Customize how notifications are displayed with template variables:
{
"enabled": true,
"services": {
"pushover": {
"enabled": true,
"userKey": "your-user-key",
"apiToken": "your-api-token",
"priority": 0,
"sound": "pushover"
}
},
"filters": {
"onlyWhenAway": true,
"highlights": true
},
"format": {
"title": "{{network}}",
"titleWithChannel": "{{network}} / {{channel}}",
"message": "{{time}} <{{nick}}> {{message}}",
"actionMessage": "{{time}} * {{nick}} {{message}}"
}
}This will display notifications like:
- Title:
freenode / #lounge(for channel messages) orfreenode(for PMs) - Message:
14:30 <john> Hello everyone
-
Check plugin is loaded:
/notify status -
Verify configuration file exists and has valid JSON
-
Check TheLounge logs for errors:
thelounge logs
-
Send a test notification:
/notify test
The configuration is stored in your TheLounge user config file:
~/.thelounge/users/<username>/<network>.json
Look for the externalNotify property. Replace <username> and <network> with your TheLounge username and network name.
- Verify your User Key is exactly 30 characters
- Verify your API Token is exactly 30 characters
- Make sure there are no extra spaces or quotes
- Test your credentials at pushover.net
Adjust your filters:
- Set
onlyWhenAway: trueto only notify when away - Disable notifications when you're actively using IRC
This plugin uses TheLounge's built-in highlight detection. To customize what triggers highlights:
- Go to Settings (gear icon in TheLounge)
- Navigate to "Highlights"
- Add custom highlight words/patterns
The plugin will send notifications for any message that TheLounge marks as a highlight.
thelounge-plugin-external-notify/
├── index.js # Main plugin entry point
├── package.json # Plugin metadata
├── lib/
│ ├── commands.js # Command implementations
│ ├── config-manager.js # Configuration handling
│ ├── notification-manager.js # Notification routing logic
│ ├── format.js # Message formatting utilities
│ ├── message.js # Message sending utility
│ └── notifiers/
│ ├── base.js # Abstract notifier interface
│ ├── pushover.js # Pushover implementation
│ └── example.js # Example notifier template
└── test/
├── config-manager.test.js
├── notification-manager.test.js
├── pushover.test.js
├── integration.test.js
└── simple.test.js
To add support for a new service:
- Create
lib/notifiers/yourservice.jsextendingBaseNotifier - Implement required methods:
constructor()- Set up registerVariables with required/optional fields- Define defaults for optional fields
- Let BaseNotifier handle validation
- The plugin will automatically:
- Load your notifier when configured
- Validate configuration using your registerVariables
- Apply defaults for optional fields
See lib/notifiers/pushover.js for a complete example.
Service-Agnostic Architecture:
- Core infrastructure (
config-manager.js,notification-manager.js) knows nothing about specific services - Each notifier (
lib/notifiers/*.js) manages its own:- Configuration schema (via
registerVariables) - Validation logic (via
validate()) - Default values for optional fields
- API integration
- Configuration schema (via
Benefits:
- Easy to add new notification services
- No service-specific code in core files
- Each service is self-contained and maintainable
Run the test suite:
npm testSee TESTING.md for detailed testing instructions.
MIT
- Report bugs at: GitHub Issues
- TheLounge documentation: thelounge.chat
- Pushover API docs: pushover.net/api
- Prowl API docs: prowlapp.com/api/api
- Ntfy docs: https://docs.ntfy.sh