> ## Content Index
> Fetch the complete content index at: https://blog.valentinvie.fr/llms.txt
> Use this file to discover other available public pages before exploring further.

# How to get Duplicati backup jobs notifications with nfty.sh or Discord ?
- URL: https://blog.valentinvie.fr/duplicati-integration-with-nfty-sh/
- Published: 2025-08-08T15:00:46.000Z
- Updated: 2026-02-25T11:06:48.000Z
- Description: When running automated backups, especially with a tool like Duplicati, it’s important to be notified about their status. Let's configure Duplicati to receive notification in ntfy.sh !
- Author: Valentin Vie
- Tags: Self-hosting

When running automated backups, especially with a tool like [Duplicati](https://www.duplicati.com/), it’s important to be notified about their status. Did the backup complete successfully? Was there a warning? Did it fail entirely?

In this post, I’ll walk you through how I integrated Duplicati with a self -hosted [ntfy.sh](https://ntfy.sh) instance to receive push notifications about your backup jobs.

#### Why ntfy.sh ? 

ntfy.sh is a simple publish-subscribe notification service that supports mobile push, desktop notifications, and webhooks. It's perfect for my use case and I find it easy to integrate. You may prefer gotify or pushbullet, I have not tried these I can't tell if they are as good.

#### The documentation

You will find all related documentation there:

[Scripts | Duplicati![](https://blog.valentinvie.fr/content/images/icon/image)Duplicati![](https://blog.valentinvie.fr/content/images/thumbnail/0FHyPEEwOX6FUsMff74e)](https://docs.duplicati.com/detailed-descriptions/scripts)

#### The script

Here's the script I created and configured in Duplicati (I was inspired by a blog post [here](https://forum.duplicati.com/t/http-notifications-and-ntfy-sh/20691/8)):

```Bash
#!/bin/bash

# Read Duplicati environment variables
EVENTNAME=$DUPLICATI__EVENTNAME
OPERATIONNAME=$DUPLICATI__OPERATIONNAME
REMOTEURL=$DUPLICATI__REMOTEURL
LOCALPATH=$DUPLICATI__LOCALPATH
BACKUPNAME=$DUPLICATI__backup_name

NTFY_URL="https://ntfy.example.com/duplicati"
NTFY_TOKEN="tk_abcd1234"

if [ "$EVENTNAME" == "BEFORE" ]
then
    # Send start notification
    curl -s -X POST "$NTFY_URL" \
        -H "Authorization: Bearer $NTFY_TOKEN" \
        -H "Title: Duplicati $OPERATIONNAME starting" \
        -H "Priority: low" \
        -d "A $OPERATIONNAME job on '$DUPLICATI__backup_name' is starting."
elif [ "$EVENTNAME" == "AFTER" ]
then
    if [ "$OPERATIONNAME" == "Backup" ]
    then
        if [ "$DUPLICATI__PARSED_RESULT" == "Success" ]
        then
        # Notify success
        curl -s -X POST "$NTFY_URL" \
            -H "Authorization: Bearer $NTFY_TOKEN" \
            -H "Title: Duplicati $OPERATIONNAME finished" \
            -H "Priority: low" \
            -H tags:white_check_mark,tada \
            -d "Backup '$DUPLICATI__backup_name' completed successfully"

        elif [ "$DUPLICATI__PARSED_RESULT" == "Warning" ]
        then
        # Notify warning
        curl -s -X POST "$NTFY_URL" \
            -H "Authorization: Bearer $NTFY_TOKEN" \
            -H "Title: Duplicati $OPERATIONNAME finished" \
            -H "Priority: default" \
            -H tags:warning \
            -d "Backup '$DUPLICATI__backup_name' completed with warnings"
        else
        # Notify failure
        curl -s -X POST "$NTFY_URL" \
            -H "Authorization: Bearer $NTFY_TOKEN" \
            -H "Title: Duplicati $OPERATIONNAME finished" \
            -H "Priority: high" \
            -H tags:x \
            -d "Backup '$DUPLICATI__backup_name' failed with status: $DUPLICATI__PARSED_RESULT"
        fi
    else
		# Send generic notification via ntfy
        curl -s -X POST "$NTFY_URL" \
            -H "Authorization: Bearer $NTFY_TOKEN" \
            -H "Title: Duplicati $OPERATIONNAME finished" \
            -H "Priority: low" \
            -d "A $OPERATIONNAME job on '$DUPLICATI__backup_name' has ended (no information on status)."
    fi
else
	# This should never happen, but there may be new operations
	# in new version of Duplicati
	# We write this to stderr, and it will show up as a warning in the logfile
	echo "Got unknown event \"$EVENTNAME\", ignoring" >&2
fi

exit 0

```

#### Integration steps

1. Save this script to your duplicati appdata folder location, e.g., `/mnt/user/appdata/duplicati/notification_script/notify.sh`
2. Make it executable with chmod : `chmod +x /usr/local/bin/duplicati-ntfy-notify.sh`
3. Check your docker container can access the `/mnt/user/appdata/duplicati` folder with path mapping to `/config`. This is my configuration but you can adapt it if you want.
4. Attach it to your Duplicati job under `Run script after (and/or before) backup`, using the proper script path.

![](https://blog.valentinvie.fr/content/images/2025/08/image-7.png)

⚠️

I ran into an issue by creating the script using a Windows machine. The docker container would not find the bash script eventhough the path mapping was correct. Creating the script using nano and pasting the content of the script worked. I thing Windows has a hard time with the `#!/bin/bash` script header but I'm not sure.

#### The result

Launch a backup or a file verification to test the script. You should receive some notification : 

![](https://blog.valentinvie.fr/content/images/2025/08/image-8.png)

Nice, It works ! 😄

💡

While ntfy.sh is great, this integration is hardcoded for a single notification service. What if you want to support multiple channels like Discord, Telegram, Email, or Slack without rewriting your script you can instead ping a Apprise-API server.

#### Discord webhooks

Here is a script using Discord webhooks (without Apprise):

```bash
#!/bin/bash

# Read Duplicati environment variables
EVENTNAME=$DUPLICATI__EVENTNAME
OPERATIONNAME=$DUPLICATI__OPERATIONNAME
REMOTEURL=$DUPLICATI__REMOTEURL
LOCALPATH=$DUPLICATI__LOCALPATH
BACKUPNAME=$DUPLICATI__backup_name

DISCORD_WEBHOOK_URL="https://discordapp.com/api/webhooks/<WEBHOOK_ID>/<SECRET>"

if [ "$EVENTNAME" == "BEFORE" ]
then
    # Send start notification
    curl -s -X POST "$DISCORD_WEBHOOK_URL" \
        -H "Content-Type: application/json" \
        -d "{
            \"embeds\": [
                {
                    \"title\": \"Duplicati $OPERATIONNAME starting\",
                    \"description\": \"A $OPERATIONNAME job on '$BACKUPNAME' is starting.\",
                    \"color\": 3066993
                }
            ]
        }"
elif [ "$EVENTNAME" == "AFTER" ]
then
    if [ "$OPERATIONNAME" == "Backup" ]
    then
        if [ "$DUPLICATI__PARSED_RESULT" == "Success" ]
        then
        # Notify success
        curl -s -X POST "$DISCORD_WEBHOOK_URL" \
            -H "Content-Type: application/json" \
            -d "{
                \"embeds\": [
                    {
                        \"title\": \"Duplicati $OPERATIONNAME finished\",
                        \"description\": \"Backup '$DUPLICATI__backup_name' completed successfully\",
                        \"color\": 3066993
                    }
                ]
            }"

        elif [ "$DUPLICATI__PARSED_RESULT" == "Warning" ]
        then
        # Notify warning
        curl -s -X POST "$DISCORD_WEBHOOK_URL" \
            -H "Content-Type: application/json" \
            -d "{
                \"embeds\": [
                    {
                        \"title\": \"Duplicati $OPERATIONNAME finished\",
                        \"description\": \"Backup '$DUPLICATI__backup_name' completed with warnings\",
                        \"color\": 15105570
                    }
                ]
            }"
        else
        # Notify failure
        curl -s -X POST "$DISCORD_WEBHOOK_URL" \
            -H "Content-Type: application/json" \
            -d "{
                \"embeds\": [
                    {
                        \"title\": \"Duplicati $OPERATIONNAME finished\",
                        \"description\": \"Backup '$DUPLICATI__backup_name' failed with status: $DUPLICATI__PARSED_RESULT\",
                        \"color\": 16711680
                    }
                ]
            }"
        fi
    else
		# Send generic notification via ntfy
        curl -s -X POST "$DISCORD_WEBHOOK_URL" \
            -H "Content-Type: application/json" \
            -d "{
                \"embeds\": [
                    {
                        \"title\": \"Duplicati $OPERATIONNAME finished\",
                        \"description\": \"A $OPERATIONNAME job on '$DUPLICATI__backup_name' has ended (no information on status).\",
                        \"color\": 16776960
                    }
                ]
            }"
    fi
else
	# This should never happen, but there may be new operations
	# in new version of Duplicati
	# We write this to stderr, and it will show up as a warning in the logfile
	echo "Got unknown event \"$EVENTNAME\", ignoring" >&2
fi

exit 0

```