How to access the original data point timestamp in a Grafana alert notification?

Hello,

I’m using Grafana-managed alerting with AWS IoT SiteWise as the data source.

The SiteWise query returns a time, numeric value, and quality for each data point. I have an alert rule that monitors the numeric value and sends an email whenever the state changes.

The issue is with the timestamp in the alert email. Grafana’s .StartsAt represents when Grafana evaluated the rule and changed the alert to Firing. What I need instead is the original timestamp of the data point from AWS IoT SiteWise that caused the state change.

For example, if the source value changes at 12:22:51, but Grafana evaluates the rule later, I want the email to show 12:22:51 as the state-change time rather than the alert evaluation time.

I can see the correct timestamp in the raw SiteWise query response, but after the query goes through the alert expressions/reduction, the timestamp is not available in $values; only the reduced numeric values and labels remain.

What I’m trying to achieve is:

SiteWise data point → actual source timestamp → Grafana alert → alert email showing the exact state-change timestamp

Has anyone implemented something similar with AWS IoT SiteWise and Grafana-managed alerting? I’m looking for a way to retain or pass the original data-point timestamp through the alert evaluation so it can be displayed in the notification email.

I found an approach that worked in my Grafana setup.

The key point is that {{ .StartsAt }} is always the time Grafana changed the alert state to Firing. It isn’t the timestamp of the source data point.

Instead of relying on the original time field, I changed my query so the source timestamp is returned as a string column (for example, ts) alongside the numeric value and quality. Because ts is no longer a time field, it is preserved as a label during alert evaluation and becomes available in annotations and notification templates.

For example, my query returns something equivalent to →

SELECT
  CAST(event_timestamp AS VARCHAR) AS ts,
  value,
  quality
FROM ...
ORDER BY event_timestamp DESC
LIMIT 1

(The exact SQL syntax depends on the AWS IoT SiteWise query engine.)

Then I referenced the label in my annotation →

Value {{ $values.A }} crossed threshold at {{ $labels.ts }} (quality: {{ $labels.quality }})

and in my notification template:

{{ range .Alerts.Firing }}
Alert fired for value {{ index .Values "A" }} at source time {{ .Labels.ts }} (quality: {{ .Labels.quality }})
{{ end }}

In my case, the timestamp flowed all the way through the alert pipeline. The alert instance shows ts as a label, and the webhook payload includes it in commonLabels, so it can be used in the notification title, annotations, and email instead of relying on .StartsAt.


If your SiteWise datasource supports returning the timestamp as a string (or another non-time field that Grafana preserves as a label), this may be a workable approach for your use case.

Hey
I checked my setup, and I’m using the AWS IoT SiteWise – Get Property Value History query, not an SQL-based query.
The response contains time, the numeric property value, and quality, but I don’t have an option to CAST the time field to a string like in your example.
Is there another way to preserve the original time field as a label so I can use it in the alert notification?

Thanks!

Thanks for checking.
From your Query Inspector, the datasource returns three fields: time, the numeric value, and quality. During alert evaluation, quality is preserved as a label, but the time field remains Grafana’s special time field and isn’t propagated into $labels or $values.

The workaround I posted earlier depends on returning the source timestamp as a separate string field (for example, ts) so Grafana can preserve it as a label. Since the SiteWise query doesn’t appear to support returning the timestamp as a non time field, that approach isn’t applicable here.

Unless the SiteWise datasource exposes the source timestamp as a label (or an additional string field), the notification template can’t access the original data point timestamp directly and must rely on Grafana’s alert timestamps (such as .StartsAt) unless the datasource exposes it as a label.