How to Use Apprise: The Beginner's Guide to One Alert Wire for Everything

CodexFuse Team · 2026-11-01T10:22:04.719Z · 13 min read

How to use Apprise, the open-source Python notification library: install, send your first alert, keep secrets in a config file, and route alerts with tags.

What is Apprise, exactly?

Apprise is the open-source Python notification library that turns one command into alerts on Discord, Telegram, email, Slack, and 168 more services. If you want to learn how to use Apprise, this is the whole idea: you write one service URL per destination, and Apprise's command-line tool or Python API delivers the same message to all of them at once. (One quick note: "apprise" is also an English verb meaning "to inform" — this guide is about the software, the library maintained by Chris Caron on GitHub, not the grammar lesson.)

It lives at the sweet spot between a shell script and a notification platform. You do not run a server, you do not register for an API account, and you do not write a separate integration for every chat app. You keep a config file full of service URLs, and any script on the machine can send through it. Apprise belongs to a small notification family worth knowing: the ntfy beginner guide covers the self-hosted receiver many Apprise users wire their alerts into — Apprise sends, ntfy receives, and they pair beautifully. Think of this Apprise tutorial as one complete walkthrough — install, first alert, config, Python, tags, and real wiring — instead of five scattered docs pages.

How do you install Apprise?

You install Apprise with one command: pip install apprise. That is the canonical install line from the PyPI page, and it works anywhere Python 3.9 or newer runs — which is every current Linux distribution, macOS, and Windows. The package ships a console command named apprise, so after installing, apprise -V should print the version (2.1.0 is the current release as of this writing).

There are three honest ways to get it on your machine. Pick by habit, not by hype:

Install pathCommandBest for
pippip install appriseEverybody; the documented, canonical path
uvuv add appriseProjects already using uv for Python dependency management
Distro packageapt install apprise (Debian/Ubuntu)System-wide installs managed by your OS; may lag behind PyPI

If apprise is not found after a pip install, your user-scripts directory is not on your PATH — the classic fix is python3 -m pip install apprise or adding ~/.local/bin to PATH. The flag set below was verified against the current documentation at write time, because CLI flags do shift between releases.

How do you send your first Apprise alert?

Your first Apprise alert is one line: apprise -t "Backup Complete" -b "The server is safe" "discord://webhook_id/webhook_token". That is your first Apprise Discord alert in the making — the -t flag sets the title, -b sets the body, and the final argument is the service URL. That example comes straight from the official getting-started page; you replace the placeholder values with your real webhook ID and token.

Two behaviors are worth learning on day one. First, if you omit -b, Apprise reads the body from standard input, so echo "disk at 91%" | apprise -t "Warning" "tgram://bottoken/ChatID" works in pipelines — that one-liner is a complete Apprise Telegram alert. Second, the -d (dry-run) flag walks through your whole setup without sending anything — run it before you trust a new config. Verbose output with -vv shows you exactly which services fired and which failed, which is how you debug a silent alert.

What does an Apprise service URL look like?

An Apprise service URL looks like schema://credentials@host/path — one URL per service, with the schema naming the plugin. The canonical list of all 171 supported services now lives at appriseit.com/services/ (the old GitHub wiki is archived and redirects there, so do not bookmark the wiki). Three worked examples cover the shapes you will actually use:

# Discord webhook — schema names the plugin, path carries the credentials
discord://webhook_id/webhook_token

# Telegram bot — bot token, then one or more chat IDs
tgram://bottoken/ChatID
tgram://bottoken/ChatID1/ChatID2

# Plain email — Apprise email alerts use the familiar user:password@host shape
mailto://user:[email protected]

The URL is doing real work here: Apprise parses the schema to pick the plugin, then hands each plugin its own slice of the URL. Some services need query-string parameters for extra options, and those always override values parsed from the URL path. If a service URL ever confuses you, the site also ships a URL builder at appriseit.com/tools/url-builder/ that assembles the syntax for you.

How do you keep your secrets out of the command line?

You keep secrets out of the command line by putting your service URLs in a config file — full stop. The docs say it plainly: configuration keeps your notification services, tags, and groups in one file, and it keeps credentials out of your shell history. This is the one rule of Apprise: never paste a URL with a token into a terminal command once you have more than a one-off alert to send.

Apprise finds your config automatically. If you do not pass --config, it scans a fixed list and loads the first match: ~/.apprise, ~/.apprise.conf, ~/.apprise.yml, ~/.apprise.yaml, then the ~/.config/apprise* variants, then the global /etc/apprise* paths. (Windows users get %APPDATA%/Apprise/apprise.conf.) You can also load any file explicitly, multiple times, even from a URL: apprise --config=/etc/apprise/config.yml --body="test".

The TEXT format is line-based and reads like a shopping list — blank lines ignored, # comments, one URL per line, optional tag prefixes:

# Email notifications
mailto://user:[email protected]

# Discord notifications — tagged so scripts can target it
ops=discord://webhook_id/webhook_token

Two more features make configs scale. The include keyword imports another file, so you can keep secrets in one place and share the rest: include /etc/apprise/secrets.conf. And YAML configs support ${NAME} template variables filled from --template-var or APPRISE_TEMPLATE_<NAME> environment variables, so secrets stay out of version control as well as out of shell history.

Should your Apprise config be YAML or TEXT?

Use TEXT unless you have a reason not to. Both formats describe the same information — the same file even works unchanged across the CLI, the API server, and the Python library — but the docs are explicit that an Apprise YAML config earns its keep through structure for larger setups and automation. Decide with this table:

SituationFormatWhy
A few services, hand-editedTEXTSimplest syntax; one URL per line, optional tag= prefixes
Per-service settings per URLYAMLSettings written under a URL take priority over the URL itself
Config generated by toolingYAMLStandardised structure that automation can parse and write
Secrets in a separate fileEitherBoth support include; put the include in the shared file

How do you send notifications from Python with Apprise?

You send notifications from Python with three calls: create the object, add a URL, notify. The pattern is Apprise() then add() then notify(), verified against the current developer docs at write time:

import apprise

apobj = apprise.Apprise()
apobj.add('tgram://bottoken/ChatID')
apobj.notify(
    body='What a great notification service!',
    title='My Notification Title',
)

The same three calls answer the "send notifications python one library" search for good: one library, one URL per service, no per-platform SDKs. The Apprise Python pattern stays identical whether you add one service or twenty — add() once per destination, then a single notify() fans out to all of them. For scripts that need config files, apprise.AppriseConfig() loads them, and apobj.add(config) attaches the loaded config to your object. Notifications also accept attach= with a local path or remote URL, and the library adapts the attachment to each service's capabilities.

How do Apprise tags route your alerts?

Apprise tags route your alerts by labeling each service in the config, then filtering at send time. In a TEXT config you prefix the URL: tv,kitchen=kodi://user:[email protected] tags that service with both tv and kitchen, and you can even define groups like friends = user1, user2 so one name notifies several people. The CLI's -g/--tag flag then picks the audience:

# Notify services tagged ops
apprise --tag="ops" --body="Deploy finished"

# Notify services tagged ops AND critical
apprise --tag="ops,critical" --body="Database is down"

# Notify services tagged ops OR critical
apprise --tag="ops" --tag="critical" --body="Heads up"

# Notify every service in the config, ignoring filters
apprise --tag="all" --body="Fire drill"

Two special tags complete the system. Tag a URL with always and it fires no matter what filter you pass — perfect for the one channel that must never be filtered out. Pass --tag=all and Apprise notifies every service defined in the configuration. Advanced setups can add priority and retry prefixes to tags for escalation chains, but tags plus groups cover nearly every beginner's routing need.

Can Apprise send attachments?

Yes — Apprise supports attachments on the CLI and in Python, adapting them to each service's capabilities. On the command line you add --attach with a path: apprise -vv -t "School Assignment" -b "See attached" --attach=Documents/FinalReport.docx. In Python you pass attach= with a local path or a remote URL, and you can hand it a list, set, or tuple for several files at once. A service that cannot take attachments simply gets the message without one, so the same call works everywhere.

How do you run Apprise in Docker?

You run Apprise in Docker with the official caronc/apprise image — but know what it is first. The image packages Apprise API, the web-gateway micro-service, not just the CLI: docker pull caronc/apprise:latest gets you a container that listens on port 8000 and accepts notification requests over HTTP, backed by /config, /plugin, and /attach volumes. This is the right shape when your alerts need to come from services that cannot run Python — a webhook from anywhere on your network becomes a POST to the gateway.

If Docker itself is new to you, read the Docker beginner guide first; the volume flags and port mapping are standard Docker, nothing Apprise-specific. The gateway reads the same config file formats, so the TEXT or YAML file you built for the CLI works here unchanged.

How do you expose Apprise's API safely?

You do not expose Apprise's API to the open internet bare — you put it behind a VPN or a reverse proxy with authentication. The gateway is designed to sit on your private network and accept POSTs from your own scripts, containers, and webhooks. If you need to reach it from outside your LAN, the safest pattern beginners actually use is a mesh VPN, which gives the API a private address without opening any inbound port; the Tailscale beginner guide walks through that exact setup.

Where do real Apprise alerts come from?

Real Apprise alerts come from the boring infrastructure you already run: cron jobs that report success or failure, backup scripts that confirm the night's copy, and monitors that watch your servers. The pattern is always the same — the job runs, and on the interesting outcome it calls apprise with a body describing what happened. A typical cron line looks like this:

# Every night at 2 AM: back up, then report through Apprise
0 2 * * * /usr/local/bin/nightly-backup.sh && apprise -t "Backup OK" -b "Nightly backup completed" || apprise -t "Backup FAILED" -b "Check the logs now"

This is also where Apprise's whole design pays off. That backup runs on a VPS somewhere — if the question of which server still confuses you, the plain-English what is VPS hosting guide sorts it out — and the alert lands on your phone through whatever service your config names. Monitors feed the same wire: a Netdata beginner guide dashboard can watch your disks and memory in real time, and Apprise carries its "disk at 91%" warnings to Discord, Telegram, or email without a second integration to maintain.

Apprise vs ntfy: which one do you need?

Apprise and ntfy answer different halves of the notification problem, and most setups that have one eventually add the other. This table draws the line once:

Apprisentfy
What it isA client library that sends to 100+ servicesA self-hosted service that receives pushes
You run a server?No (except the optional API gateway)Yes — or use the public ntfy.sh
DestinationsDiscord, Telegram, email, Slack, 171 totalntfy apps and subscribed clients
Best wiringApprise sends to an ntfy topic URL like any other servicentfy receives; Apprise fans out to everything else
Start here ifYou need one alert wire for many platformsYou need a private push inbox on your own server

They are complements, not competitors: point an Apprise service URL at your ntfy topic and your "send everywhere" setup gains a self-hosted inbox for free.

What mistakes do Apprise beginners keep making?

MistakeWhat happensThe fix
Credentials on the command lineTokens land in shell history and process listsMove URLs into a config file; use template variables for secrets
-T for tags-T is the theme flag in current releasesTag filtering is -g/--tag, always
Forgetting the config loads automaticallyAn old ~/.apprise silently changes behaviorRun apprise -d -vv to see what is actually loaded
Assuming one service URL = one message copyConfusion when a service swallows attachmentsAttachments adapt per service; test each destination once
Bookmarking the GitHub wikiThe wiki is archived and redirectsUse appriseit.com/services/ as the canonical service list

Your first 10 steps: from install to your first routed alert

  1. Install: pip install apprise, then confirm with apprise -V.
  2. Dry-run your first alert to a test service: apprise -d -t "Hello" -b "Testing" "discord://webhook_id/webhook_token".
  3. Send it for real by dropping the -d flag.
  4. Create ~/.apprise and move the service URL into it, one per line.
  5. Tag your destinations: ops=discord://webhook_id/webhook_token and personal=tgram://bottoken/ChatID.
  6. Test the tag filter: apprise --tag="ops" -b "Ops-only test".
  7. Add an always tag to the one channel that must never be filtered out.
  8. Move any secrets into a separate file and pull it in with include.
  9. Wire one cron job to report through Apprise on failure.
  10. Add a second service — email or ntfy — and watch one alert land in two places at once.

Sources

  • Apprise on PyPI (current release 2.1.0, install docs, CLI usage, Python API, 171-service table) — pypi.org/project/apprise/
  • Apprise official docs: getting started (install, first alert, CLI/Python/API tracks) — appriseit.com/getting-started/
  • Apprise official docs: configuration (TEXT/YAML formats, tagging, groups, includes, default paths, special tags) — appriseit.com/config/
  • Apprise official docs: developer reference (Python API: Apprise, add, notify, AppriseConfig) — appriseit.com/dev/
  • Apprise official docs: services index and URL builder — appriseit.com/services/
  • Apprise CLI man page, Ubuntu noble — manpages.ubuntu.com/manpages/noble/man1/apprise.1.html
  • Apprise CLI man page, Debian testing (April 2026) — manpages.debian.org/testing/apprise/apprise.1.en.html
  • Apprise GitHub repository (stars, forks, BSD 2-Clause license, wiki archive notice) — github.com/caronc/apprise
  • Apprise repository metadata via GitHub API — api.github.com/repos/caronc/apprise
  • Official caronc/apprise Docker image (Apprise API gateway, port 8000, volumes) — hub.docker.com/r/caronc/apprise
  • Home Assistant Apprise integration docs (notify platform, config-file and direct-URL setup, tags) — home-assistant.io/integrations/apprise/

Frequently asked questions

Is Apprise free to use?

Yes. Apprise is open source under the BSD 2-Clause license, so the library itself costs nothing and has no paid tier or hosted upsell. You only pay for whatever services you send to — and most of those, like a Discord webhook or a Telegram bot, are free too.

What is the difference between the Apprise CLI and the Apprise API?

The CLI (apprise) runs on the machine and sends notifications directly — it is what cron jobs and scripts call. Apprise API is the optional web gateway packaged in the caronc/apprise Docker image: it listens on port 8000 and accepts notification requests over HTTP, so devices and services that cannot run Python can still send through your Apprise config.

How many notification services does Apprise support?

171, according to the current official documentation. The maintained list lives at appriseit.com/services/ — the old GitHub wiki is archived and redirects there, so any guide still linking the wiki is out of date.

Can Apprise send to multiple services at once?

Yes — that is its entire point. Put several service URLs in your config (or pass several on the command line) and one notify() or one CLI call delivers to all of them. Tags let you choose a subset, like --tag="ops", without editing the config.

Is it safe to put tokens in the Apprise config file?

Safer than the command line, which is the documented reason config files exist — credentials stay out of shell history. Keep the file's permissions tight, split secrets into an included file if you share configs, and use template variables or environment variables for the most sensitive values.

Featured on Twelve Tools Launch Llama Tools Launch your MCP