Trouble passing multiline templates through scripts

I need some help with this one.

I made a script to make it easier and more consistent to generate notifications. It exposes a bunch of the options through fields. Generally that works, but I’m having issues passing an action to the script. I can’t figure out how to format the action data so it’s passed correctly to the script.

This first notification is the goal, however the second is what I’m getting when I try to pass the same data through a script using fields.

Here’s a conventional notification that works.

action: notify.mobile_app_a
metadata: {}
data:
  title: >-
    Time to Go in {{
    states('sensor.countdown_to_next_departure_calendar') }}!
  message: >-
    Start Time: {{
    as_local(as_datetime(states('sensor.next_location_start'))).strftime('%H:%M')
    }}<br> Travel Time: {{
    states('sensor.travel_time_to_next_appointment') }} <br> Address:
    {{ states('sensor.next_location') }} <br> Appointment: {{
    states('sensor.next_location_summary') }}
  data:
    actions:
      - action: URI
        title: Open in Google Maps
        uri: >-
          https://www.google.com/maps/dir/?api=1&destination={{states('sensor.next_location')
          | replace('  ', '+') | replace(' ', '+') }}
enabled: true

This however doesn’t work (there is no “open map”) on the notification.

action: script.notification_script
metadata: {}
data:
  device_to_notify: a
  visibility: public
  sticky: false
  persistent: false
  importance: high
  priority: high
  alert_once: false
  include_time: false
  tag: leave_time
  channel: Leave Time
  color: yellow
  notification_icon: mdi:car-arrow-right
  message: >-
    Start Time: {{
    as_local(as_datetime(states('sensor.next_location_start'))).strftime('%H:%M')
    }}<br> Travel Time: {{
    states('sensor.travel_time_to_next_appointment') }} <br> Address:
    {{ states('sensor.next_location') }} <br> Appointment: {{
    states('sensor.next_location_summary') }}
  title: >-
    Time to Go in {{
    states('sensor._countdown_to_next_departure_calendar') }}!
  actions: |-
    - action: URI
      title: Open in Google Maps
      uri: https://www.google.com/maps/dir/?api=1&destination {{states('sensor.next_location')       | replace('  ', '+') | replace(' ', '+') }}
enabled: true

Here’s the script that handles the second notification:

sequence:
  - alias: Notification Template
    metadata: {}
    data:
      data:
        importance: "{{ importance }}"
        priority: "{{ priority }}"
        subject: "{{ subject }}"
        sticky: "{{ sticky }}"
        persistent: "{{ persistent }}"
        timeout: "{{ timeout }}"
        color: "{{ color }}"
        tag: "{{ tag }}"
        channel: "{{ channel }}"
        visibility: "{{ visibility }}"
        notification_icon: "{{ notification_icon }}"
        clickAction: "{{ clickAction }}"
        alert_once: "{{ alert_once }}"
        actions: "{{ actions }}"
        notification_id: "{{ notification_id }}"
      message: >-
        {{ message }}{% if include_time == "true" %} at {{ now().strftime
        ("%H:%M:%S") }}.{%else%}{% endif %}
      title: "{{ title }}"
    action: >-
      notify.{% if device_to_notify == "parents" or device_to_notify ==
      "persistent_notification"%}{{device_to_notify}}{%else%}mobile_app_{{device_to_notify}}{%
      endif %}
alias: Notification Script
description: ""
icon: mdi:bell-alert
fields:
  title:
    description: The Title of the notification.
    selector:
      text: null
    name: Title
    required: true
  message:
    description: The message you'd like to send to the device.
    selector:
      text: null
    name: Message
    required: true
  tag:
    description: >-
      Replace an existing notification by using a tag for the notification. All
      subsequent notifications will take the place of a notification with the
      same tag.
    selector:
      select:
        options:
          - washer
          - garage_doors
        custom_value: true
    required: false
    name: Tag
  notification_id:
    description: >-
      Like Tag, but for Persistant Notificaitons - If notification_id is given,
      it will overwrite the notification if there already was a notification
      with that ID.
    selector:
      text: null
    required: false
    name: notification_id
  channel:
    description: >-
      https://companion.home-assistant.io/docs/notifications/notifications-basic/#creating-a-channel
    selector:
      select:
        options:
          - house_quiet_alerts
          - house_alerts
          - a_control_alerts
          - frigate
          - network_quiet_alerts
          - access_quiet_alerts
        custom_value: true
    required: false
  device_to_notify:
    description: Device to send notification to.
    selector:
      select:
        options:
          - a
          - b
          - c
          - d
          - persistent_notification
          - parents
          - "3219"
          - "3205"
          - whole_family
    default: a
    required: true
  color:
    description: >-
      In Android you can set the color of the notification, you can use either
      the color name or the hex code.
    selector:
      select:
        options:
          - red
          - green
          - yellow
          - purple
          - orange
          - blue
        multiple: false
        custom_value: true
    required: false
  visibility:
    description: >-
      You can change how much of a notification is visible on the lock screen by
      using the visibility option. Possible values for this property are:
      public: always show all notification content private (default): visibility
      depends on your setting in the system Settings app > Notifications; if the
      option to show sensitive notifications when locked is enabled all
      notification content will be shown, otherwise only basic information such
      as the icon and app name are visible secret: always hide notification from
      lock screen
    selector:
      select:
        options:
          - public
          - private
          - secret
        multiple: false
    name: Visibility
    required: true
    default: private
  notification_icon:
    description: >-
      On Android you also have the option of changing the notification status
      bar icon to any icon on Material Design. By default the Home Assistant
      icon will appear. The expected format is the same in Home Assistant
      mdi:cellphone. If you provide an invalid icon name then no icon will be
      shown. Requires Android 6+.
    selector:
      icon: null
    name: Status Bar Icon
    required: false
  clickAction:
    description: Android URL - e.g. "https://google.com" or "/lovelace/cameras"
    selector:
      text:
        type: url
        autocomplete: url
    name: URL
    required: false
  subject:
    description: >-
      A subject may take the place of longer content (more than 6 lines),
      depending on your device.
    selector:
      text:
        type: text
    name: Subject
    required: false
  sticky:
    description: >-
      You can set whether to dismiss the notification upon selecting it or not.
      Setting sticky to 'true' will keep the notification from being dismissed
      when the user selects it. Setting it to 'false' (default) will dismiss the
      notification upon selecting it.
    name: Sticky Notification
    selector:
      select:
        options:
          - "true"
          - "false"
        multiple: false
    required: true
    default: false
  persistent:
    description: >-
      Persistent notifications are notifications that cannot be dismissed by
      swiping away. These are useful if you have something important like an
      alarm being triggered. In order to use this property you must set the tag
      property as well.
    selector:
      select:
        options:
          - "true"
          - "false"
        multiple: false
    name: Persistant
    required: true
    default: false
  timeout:
    description: >-
      You can set how long a notification will be shown on a users device before
      being removed/dismissed automatically. You may use the timeout property
      along with the value in seconds to achieve this.
    name: Timeout
    selector:
      text:
        type: number
    required: false
  importance:
    description: >-
      When you are setting the channel for your notification you also have the
      option to set the importance for the channel per notification. Possible
      values for this property are high, low, max, min and default. To learn
      more about what each value does see the FCM docs.
    name: Channel Importance
    default: high
    selector:
      select:
        options:
          - high
          - low
          - max
          - min
          - default
        multiple: false
    required: true
  priority:
    description: Like Importance, but for < Android 8.0
    default: high
    name: Priority
    selector:
      select:
        options:
          - high
          - low
          - max
          - min
          - default
        multiple: false
    required: true
  alert_once:
    description: >-
      On Android you have the option for making a notification only alert once
      on the device. This means it will only make a sound, vibrate and/or flash
      the LED once. Although it is not an Android requirement this feature will
      not appear to function if you do not have a tag set.
    selector:
      select:
        options:
          - "true"
          - "false"
        multiple: false
    default: false
    name: Alert Once
    required: true
  include_time:
    description: Whether to apphend at {{ now().strftime ("%H:%M:%S") to the message
    selector:
      select:
        options:
          - "true"
          - "false"
        multiple: false
    name: Include Time
    required: true
    default: false
  actions:
    selector:
      text: null
    name: Actions
mode: queued
max: 20

Here’s the trace info from the second notification:

Executed: January 20, 2026 at 08:38:00
Result:
params:
  domain: notify
  service: mobile_app_a
  service_data:
    data:
      importance: high
      priority: high
      subject: ''
      sticky: false
      persistent: false
      timeout: ''
      color: yellow
      tag: leave_time
      channel: Leave Time
      visibility: public
      notification_icon: mdi:car-arrow-right
      clickAction: ''
      alert_once: false
      actions: |-
        - action: URI
          title: Open in Google Maps
          uri: https://www.google.com/maps/dir/?api=1&destination 131+288th
      notification_id: ''
    message: >-
      Start Time: 09:00<br> Travel Time: 12 minutes <br> Address: 131 <br> Appointment: *TS- Job
      for A
    title: Time to Go in 10 min!
  target: {}
running_script: false

I did try using a few variations both on the script configuration and call side.

>- for example, and the editor seemed to tweak how it’s saved.

That’s not valid… actions should contain a list of action objects, not a list-shaped string.

1 Like

Thanks for taking a look. That was the hint I needed.

The GUI was putting that into the YAML and I didn’t notice it when I pasted it on here. Not the first time the GUI has stumbled me with templates.

I changed the YAML to this and it works now.

action: script.notification_script
metadata: {}
data:
  device_to_notify: a
  visibility: public
  sticky: false
  persistent: false
  importance: high
  priority: high
  alert_once: false
  include_time: false
  tag: leave_time
  channel: Leave Time
  color: yellow
  notification_icon: mdi:car-arrow-right
  message: >-
    Start Time: {{
    as_local(as_datetime(states('sensor.next_location_start'))).strftime('%H:%M')
    }}<br> Travel Time: {{
    states('sensor.travel_time_to_next_appointment') }} <br> Address:
    {{ states('sensor.next_location') }} <br> Appointment: {{
    states('sensor.next_location_summary') }}
  title: >-
    Time to Go in {{
    states('sensor.countdown_to_next_departure_calendar') }}!
  actions:
    - action: URI
      title: Open in Google Maps
      uri: >-
        https://www.google.com/maps/dir/?api=1&destination
        {{states('sensor.next_location')       | replace('  ', '+') |
        replace(' ', '+') }}
enabled: true