Here’s the first version of what I had proposed. I chose to use the term “message” instead of “notification” to avoid confusion with Home Assistant’s native persistent_notification.
template:
- trigger:
- platform: event
event_type:
- message_create
- message_delete
- message_delete_all
sensor:
- name: Messages
state: "{{ now().timestamp() | timestamp_custom() }}"
attributes:
messages: >
{% set msgs = this.attributes.get('messages', []) %}
{% if trigger.event.event_type == 'message_create' %}
{% set new = [{
"id": trigger.event.data.id | default('TS' ~ now().timestamp()),
"title": trigger.event.data.title | default(''),
"message": trigger.event.data.message | default(''),
"time": now().isoformat() }] %}
{{ (msgs + new) }}
{% elif trigger.event.event_type == 'message_delete' %}
{% if trigger.event.data.id is defined %}
{% set msgs = msgs | rejectattr('id', 'eq', trigger.event.data.id) | list %}
{% elif trigger.event.data.index is defined and trigger.event.data.index | is_number %}
{% set t = trigger.event.data.index | int(0) - 1 %}
{% if 0 <= t < msgs|count %}
{% set msgs = msgs | rejectattr('id', 'eq', msgs[t].id) | list %}
{% endif %}
{% endif %}
{{ msgs }}
{% else %}
{{ [] }}
{% endif %}
Here are the three custom events for managing messages:
1. message_create
Create a new message.
Example
- event: message_create
event_data:
id: abc123
title: Hello world
message: The quick brown fox jumped over etc
- If you do not supply a value for
idthen a unique value is automatically generated. - If you do not supply a value for
titleormessagethen an empty string is automatically supplied.
2. message_delete
Delete a message by either its id or index value (i.e. its index position in the list of all messages). Index values start with 1 (not 0).
Example by id
- event: message_delete
event_data:
id: abc123
Example by index
- event: message_delete
event_data:
index: 1
3. message_delete_all
Deletes all messages in the list.
Example
- event: message_delete_all
To make it easier to test this Trigger-based Template Sensor, I suggest using Developer Tools > Events.

Here’s a simple template to list all messages:
{% for m in state_attr('sensor.messages', 'messages') %}
ID: {{ m.id }}
Title: {{ m.title }}
Message: {{ m.message }}
Time: {{ m.time | as_timestamp | timestamp_custom() }}
{% endfor %}
EDIT
Replaced use of trigger.id in favor of trigger.event.event_type.