Reusable notification scripts
I use scripts to share notification behavior between automations and to return the WhatsApp send response to the caller. The examples use fictional recipients.
Send a notification and return its response
Add this definition to scripts.yaml. In the script editor, use the contents
beneath whatsapp_notify:.
whatsapp_notify:
alias: WhatsApp notify
mode: queued
max: 10
fields:
message:
required: true
selector:
text:
multiline: true
to:
required: true
selector:
text:
client_id:
default: default
selector:
text:
quoted_message:
required: false
selector:
object:
sequence:
- action: whatsapp.send_message
data:
clientId: "{{ client_id | default('default') }}"
to: "{{ to }}"
body: '{{ {"text": message | string} }}'
options: >-
{{ {'quoted': quoted_message}
if quoted_message is defined and quoted_message is mapping
else {} }}
response_variable: whatsapp_result
- stop: Return the send response
response_variable: whatsapp_result
Call the script directly to receive its response. I can then send a later notification as a reply to the first:
- action: script.whatsapp_notify
data:
to: 120363000000000000@g.us
message: "The task has started."
response_variable: task_start
- delay: "00:00:05"
- action: script.whatsapp_notify
data:
to: "{{ task_start.sent_message.key.remoteJid }}"
message: "The task is complete."
quoted_message: "{{ task_start.sent_message }}"
response_variable: task_end
Replace the delay with the actual work or a wait for completion. task_start
and task_end have the same response shape as whatsapp.send_message.
Calling script.turn_on starts a script in the background and does not return
this response to the caller. See Home Assistant script responses.
Save a message key for another run
I store only the message key when a later automation needs to add a completion reaction. A quoted reply needs the full message object and should keep that object in a variable or suitable storage instead.
Create a Text helper named input_text.whatsapp_task_key with a maximum length
of 255. The equivalent configuration.yaml entry is:
input_text:
whatsapp_task_key:
name: WhatsApp task key
max: 255
These actions clear any previous key, send a new notification, and save its key as JSON only if it fits:
- action: input_text.set_value
target:
entity_id: input_text.whatsapp_task_key
data:
value: ""
- action: whatsapp.send_message
data:
clientId: default
to: 120363000000000000@g.us
body:
text: "The task has started."
response_variable: task_start
- variables:
key_json: "{{ task_start.sent_message.key | to_json }}"
- if:
- condition: template
value_template: "{{ key_json | length <= 255 }}"
then:
- action: input_text.set_value
target:
entity_id: input_text.whatsapp_task_key
data:
value: "{{ key_json }}"
else:
- stop: The message key is too long for the text helper
error: true
In the completion automation, read the JSON and reuse the full key:
- variables:
message_key: >-
{{ states('input_text.whatsapp_task_key') | from_json(default={}) }}
- condition: template
value_template: >-
{{ message_key is mapping and message_key.get('id')
and message_key.get('remoteJid')
and message_key.get('fromMe') == true }}
- action: whatsapp.send_message
data:
clientId: default
to: "{{ message_key.remoteJid }}"
body:
react:
text: "\u2705"
key: "{{ message_key }}"
- action: input_text.set_value
target:
entity_id: input_text.whatsapp_task_key
data:
value: ""
Use the same client session for both runs and a separate helper for each independent task. Do not let overlapping runs overwrite each other's key. Home Assistant text helpers have a 255-character limit; never truncate JSON to fit. Keys contain private chat and message identifiers.
Send media returned by a helper
I also use scripts that prepare a file and return a URL, then pass that URL to
WhatsApp. For example, the following sequence assumes your own
script.prepare_sticker already exists and returns a mapping containing url:
- action: script.prepare_sticker
data:
description: "A small green check mark"
response_variable: sticker_result
- action: whatsapp.send_message
data:
clientId: default
to: 120363000000000000@g.us
body:
sticker:
url: "{{ sticker_result.url }}"
The helper is a prerequisite, not an action provided by this integration. The same pattern applies to exported PDFs, generated images, and converted videos: wait for the helper to finish and return a downloadable URL before sending the file.