Skip to content
Templates

Templates

Overview

You can customize the message posted by setting a notification template.

Notification Template

Sets the Go template used for formatting notification messages.

            Argument: --notification-template
Environment Variable: WATCHTOWER_NOTIFICATION_TEMPLATE
                Type: String
             Default: See default templates below

Notification Template File

Sets the path to a file containing the Go template used for formatting notification messages.

            Argument: --notification-template-file
Environment Variable: WATCHTOWER_NOTIFICATION_TEMPLATE_FILE
                Type: String
             Default: (empty)

When both the notification-template and notification-template-file configuration options are specified, the file-based template takes precedence over the inline template.

Examples

Create a template file named custom-template.txt with your desired template content, then mount it into the container and specify the path:

services:
    watchtower:
        image: nickfedor/watchtower:latest
        environment:
            WATCHTOWER_NOTIFICATION_TEMPLATE_FILE: "/custom-template.txt"
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
            - /path/to/custom-template.txt:/custom-template.txt

Notification Report

Enables the session report as the notification template data, including container statuses and logs.

            Argument: --notification-report
Environment Variable: WATCHTOWER_NOTIFICATION_REPORT
                Type: Boolean
             Default: false

The template is a Go template that processes either a list of log entries (Message, Data, Level, Time) captured from zerolog events or a notifications.Data struct, depending on the notification-report configuration option.

Named Templates

Pass one of these names to notification-template instead of an inline template string:

NamePurpose
defaultHuman-readable session summary
default-legacyPer-log-entry formatting
json.v1Full notification data as JSON (ToJSON)
porcelain.v1.summary-no-logOne container per line
porcelain.jsonStable JSON report (ToPorcelainJSON)

porcelain.json is the template selected by --porcelain json. It renders .Report through ToPorcelainJSON and omits log entries. The JSON shape is documented under Programmatic Output (Porcelain).

Available template functions: ToUpper, ToLower, ToJSON, ToPorcelainJSON, Title, RFC1123, HasKey, and FormatDiskSpace.

Simple Templates

Simple templates are used when the notification-report configuration option is not set, formatting individual log entries as they occur.

{{- range $i, $e := . -}}
{{- if $i}}{{- println -}}{{- end -}}
{{- $msg := $e.Message -}}
{{- if eq $msg "Found new image" -}}
    Found new image: {{$e.Data.image}} ({{with $e.Data.new_id}}{{.}}{{else}}unknown{{end}})
{{- else if eq $msg "Stopping container" -}}
    Stopped stale container: {{$e.Data.container}} ({{with $e.Data.id}}{{.}}{{else}}unknown{{end}})
{{- else if eq $msg "Started new container" -}}
    Started new container: {{$e.Data.container}} ({{with $e.Data.new_id}}{{.}}{{else}}unknown{{end}})
{{- else if eq $msg "Removing image" -}}
    Removed stale image: {{with $e.Data.image_id}}{{.}}{{else}}unknown{{end}}
{{- else if eq $msg "Failed to list containers for image usage check, skipping removal" -}}
    Skipped image cleanup: {{with $e.Data.image_name}}{{.}}{{else}}unknown{{end}} ({{with $e.Data.image_id}}{{.}}{{else}}unknown{{end}}){{with $e.Data.error}}: {{.}}{{end}}
{{- else if eq $msg "Detected multiple Watchtower instances - initiating cleanup" -}}
    Detected {{$e.Data.count}} Watchtower instances - initiating cleanup
{{- else if eq $msg "Docker image usage exceeds configured maximum" -}}
    Docker image usage exceeds configured maximum: {{if HasKey $e.Data "usage"}}{{FormatDiskSpace (index $e.Data "usage")}}{{else}}unknown{{end}} of {{if HasKey $e.Data "max"}}{{FormatDiskSpace (index $e.Data "max")}}{{else}}unknown{{end}} used ({{if HasKey $e.Data "reclaimable"}}{{FormatDiskSpace (index $e.Data "reclaimable")}}{{else}}unknown{{end}} reclaimable, {{if HasKey $e.Data "image_count"}}{{index $e.Data "image_count"}}{{else}}unknown{{end}} images)
{{- else if eq $msg "Docker image usage exceeds configured warning threshold" -}}
    Docker image usage exceeds configured warning threshold: {{if HasKey $e.Data "usage"}}{{FormatDiskSpace (index $e.Data "usage")}}{{else}}unknown{{end}} of {{if HasKey $e.Data "warn"}}{{FormatDiskSpace (index $e.Data "warn")}}{{else}}unknown{{end}} used ({{if HasKey $e.Data "reclaimable"}}{{FormatDiskSpace (index $e.Data "reclaimable")}}{{else}}unknown{{end}} reclaimable, {{if HasKey $e.Data "image_count"}}{{index $e.Data "image_count"}}{{else}}unknown{{end}} images)
{{- else if eq $msg "Failed to query Docker image disk usage" -}}
    Failed to query Docker image disk usage{{with $e.Data.error}}: {{.}}{{end}}
{{- else if eq $msg "Docker image usage budget enabled" -}}
    Docker image usage budget enabled: maximum {{with $e.Data.disk_space_max}}{{FormatDiskSpace .}}{{else}}0 B{{end}}, warning at {{with $e.Data.disk_space_warn}}{{FormatDiskSpace .}}{{else}}0 B{{end}}
{{- else if $e.Data -}}
    {{$msg}} | {{range $k, $v := $e.Data -}}{{$k}}={{$v}} {{- end}}
{{- else -}}
    {{$msg}}
{{- end -}}
{{- end -}}
  • This template processes info-level log entries in real-time, formatting key update events in past tense with container and image details from structured log fields.
  • It sends each event immediately in legacy mode, mimicking a step-by-step log.

Using Simple Templates in the Preview Tool

The Template Preview Tool uses the same template root as Watchtower:

  • Report toggle off (legacy mode): the root is the log entry slice. Range over ., the same as the default simple template above.
  • Report toggle on (report mode): the root is a notifications.Data value. Range over .Entries (and use .Report for session results).
The example below is for report mode. With the report toggle off, use range . instead of range .Entries.
{{- range $i, $e := .Entries -}}
{{- if $i}}{{- println -}}{{- end -}}
{{- $msg := $e.Message -}}
{{- if eq $msg "Found new image" -}}
    Found new image: {{$e.Data.image}} ({{with $e.Data.new_id}}{{.}}{{else}}unknown{{end}})
{{- else if eq $msg "Stopping container" -}}
    Stopped stale container: {{$e.Data.container}} ({{with $e.Data.id}}{{.}}{{else}}unknown{{end}})
{{- else if eq $msg "Started new container" -}}
    Started new container: {{$e.Data.container}} ({{with $e.Data.new_id}}{{.}}{{else}}unknown{{end}})
{{- else if eq $msg "Removing image" -}}
    Removed stale image: {{with $e.Data.image_id}}{{.}}{{else}}unknown{{end}}
{{- else if eq $msg "Failed to list containers for image usage check, skipping removal" -}}
    Skipped image cleanup: {{with $e.Data.image_name}}{{.}}{{else}}unknown{{end}} ({{with $e.Data.image_id}}{{.}}{{else}}unknown{{end}}){{with $e.Data.error}}: {{.}}{{end}}
{{- else if eq $msg "Detected multiple Watchtower instances - initiating cleanup" -}}
    Detected {{$e.Data.count}} Watchtower instances - initiating cleanup
{{- else if eq $msg "Docker image usage exceeds configured maximum" -}}
    Docker image usage exceeds configured maximum: {{if HasKey $e.Data "usage"}}{{FormatDiskSpace (index $e.Data "usage")}}{{else}}unknown{{end}} of {{if HasKey $e.Data "max"}}{{FormatDiskSpace (index $e.Data "max")}}{{else}}unknown{{end}} used ({{if HasKey $e.Data "reclaimable"}}{{FormatDiskSpace (index $e.Data "reclaimable")}}{{else}}unknown{{end}} reclaimable, {{if HasKey $e.Data "image_count"}}{{index $e.Data "image_count"}}{{else}}unknown{{end}} images)
{{- else if eq $msg "Docker image usage exceeds configured warning threshold" -}}
    Docker image usage exceeds configured warning threshold: {{if HasKey $e.Data "usage"}}{{FormatDiskSpace (index $e.Data "usage")}}{{else}}unknown{{end}} of {{if HasKey $e.Data "warn"}}{{FormatDiskSpace (index $e.Data "warn")}}{{else}}unknown{{end}} used ({{if HasKey $e.Data "reclaimable"}}{{FormatDiskSpace (index $e.Data "reclaimable")}}{{else}}unknown{{end}} reclaimable, {{if HasKey $e.Data "image_count"}}{{index $e.Data "image_count"}}{{else}}unknown{{end}} images)
{{- else if eq $msg "Failed to query Docker image disk usage" -}}
    Failed to query Docker image disk usage{{with $e.Data.error}}: {{.}}{{end}}
{{- else if eq $msg "Docker image usage budget enabled" -}}
    Docker image usage budget enabled: maximum {{with $e.Data.disk_space_max}}{{FormatDiskSpace .}}{{else}}0 B{{end}}, warning at {{with $e.Data.disk_space_warn}}{{FormatDiskSpace .}}{{else}}0 B{{end}}
{{- else if $e.Data -}}
    {{$msg}} | {{range $k, $v := $e.Data -}}{{$k}}={{$v}} {{- end}}
{{- else -}}
    {{$msg}}
{{- end -}}
{{- end -}}

Example output for a log entry with msg="Found new image":

Found new image: repo/image:latest (abcdef123456)

Report Templates

When the notification-report configuration option is set, the template processes a notifications.Data struct containing a session report and log entries.

{{- if .Report -}}
  {{- with .Report -}}
    {{len .Scanned}} Scanned, {{len .Updated}} Updated, {{len .Restarted}} Restarted, {{len .Failed}} Failed
    {{- if ( or .Updated .Restarted .Failed ) -}}
      {{- range .Updated}}
- {{.Name}} ({{.ImageName}}): {{.CurrentImageID.ShortID}} updated to {{.LatestImageID.ShortID}}
      {{- end -}}
      {{- range .Fresh}}
- {{.Name}} ({{.ImageName}}): {{.State}}
      {{- end -}}
      {{- range .Restarted}}
- {{.Name}} ({{.ImageName}}): {{.State}}
      {{- end -}}
      {{- range .Skipped}}
- {{.Name}} ({{.ImageName}}): {{.State}}: {{.Error}}
      {{- end -}}
      {{- range .Failed}}
- {{.Name}} ({{.ImageName}}): {{.State}}: {{.Error}}
      {{- end -}}
    {{- end -}}
  {{- end -}}
{{- if .Entries -}}

Logs:
{{- end -}}
{{range .Entries -}}{{.Time.Format "2006-01-02T15:04:05Z07:00"}} [{{.Level}}] {{.Message}}{{"\n"}}{{- end -}}
{{- end -}}
  • This template generates a summary of container statuses (scanned, updated, failed, etc.) followed by logs, used for notifications like email or Slack messages.

Example Usage

services:
    watchtower:
        image: nickfedor/watchtower:latest
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
        environment:
            WATCHTOWER_NOTIFICATION_REPORT: "true"
            WATCHTOWER_NOTIFICATION_URL: >
                discord://token@channel
                slack://watchtower@token-a/token-b/token-c
            WATCHTOWER_NOTIFICATION_TEMPLATE: |
                {{- if .Report -}}
                {{- with .Report -}}
                {{len .Scanned}} Scanned, {{len .Updated}} Updated, {{len .Restarted}} Restarted, {{len .Failed}} Failed
                {{- if ( or .Updated .Restarted .Failed ) -}}
                    {{- range .Updated -}}
                - {{.Name}} ({{.ImageName}}): {{.CurrentImageID.ShortID}} updated to {{.LatestImageID.ShortID}}
                    {{- end -}}
                    {{- range .Fresh -}}
                - {{.Name}} ({{.ImageName}}): {{.State}}
                    {{- end -}}
                    {{- range .Restarted -}}
                - {{.Name}} ({{.ImageName}}): {{.State}}
                    {{- end -}}
                    {{- range .Skipped -}}
                - {{.Name}} ({{.ImageName}}): {{.State}}: {{.Error}}
                    {{- end -}}
                    {{- range .Failed -}}
                - {{.Name}} ({{.ImageName}}): {{.State}}: {{.Error}}
                    {{- end -}}
                {{- end -}}
                {{- end -}}
                {{- if .Entries -}}

                Logs:
                {{- end -}}
                {{- range .Entries -}}{{.Time.Format "2006-01-02T15:04:05Z07:00"}} [{{.Level}}] {{.Message}}{{"\n"}}{{- end -}}
                {{- end -}}

Example output for a session with one updated container, one restarted container, and one error log:

5 Scanned, 1 Updated, 1 Restarted, 0 Failed
- /container (repo/image:latest): abcdef12 updated to 34567890
- /restarted-container (repo/image:latest): Restarted

Logs:
2025-08-20T06:00:13-07:00 [error] Operation failed. Try again later.

Customizing Templates

You can create custom templates to format notifications differently.

Use the Template Preview Tool to test your templates interactively.

When the preview report toggle is off, simple templates can range over . just as they do in Watchtower. When the report toggle is on, range over .Entries.

Additional Resources

  • For detailed template syntax, refer to the Go Template documentation.
  • For log entry fields, each entry exposes Message, Data (map of structured fields), Level, and Time (see pkg/notifications notification entries and zerolog).
Last updated on