Log Simrix Monitor alerts to a Google Sheet
Simrix Monitor does not write to Google Sheets directly. A webhook pointed at a relay can append a row for every alert, which gives you the delivery history the product does not keep. This page covers the setup and which fields to map.
There is no native integration for this yet. Alerts get there through a webhook pointed at a relay you control. The steps below set that up.
Steps
- Create a sheet with a header row. A good starting set is timestamp, event, monitor, site URL, status, failure summary and check id.
- Create a relay that can receive a webhook and append a row: Zapier and Make both have a Google Sheets step.
- In Simrix Monitor, open Account → Webhooks, choose Add webhook, and paste the relay's URL.
- Pick the events and save, copying the signing secret before you leave the page.
- In the relay, verify the signature, then map the body's fields onto your columns.
Why a sheet is more useful here than it sounds
Simrix Monitor keeps the record of every check, but it does not keep a log of alerts that were sent, and webhook deliveries are not recorded at all. A sheet gives you that history on your own side.
It also makes the pattern visible. One failure is an incident; the same monitor failing every Tuesday afternoon is a cause, and that is far easier to notice in rows than in an inbox.
Which fields are worth a column?
timestamp and event give you when and what. monitor.name and monitor.url say which check and where. run.status and run.failureSummary say what happened. run.id lets you find the check in the app later.
One caveat on screenshots: run.screenshotUrl is a path rather than a full address, and opening it needs a signed-in session, so a link in a shared sheet will not open for someone outside your workspace.
What does Simrix Monitor send?
A single JSON POST per event. Here is a real body for a failed check.
{
"event": "monitor_failed",
"timestamp": "2026-09-14T14:03:11.482Z",
"workspaceId": "clz9a1b2c3d4e5f6g7h8i9j0",
"monitor": {
"id": "clz8m0n1o2p3q4r5s6t7u8v9",
"name": "Checkout smoke test",
"type": "page_check",
"url": "https://shop.example.com/checkout"
},
"run": {
"id": "clz7r0u1n2i3d4e5f6g7h8i9",
"status": "failed",
"changeDetected": false,
"aiSummary": "We could not find “#place-order” on the page at step 3 of 6. It may have been renamed or moved, or the page may not have got that far.",
"failureSummary": "We could not find “#place-order” on the page at step 3 of 6. It may have been renamed or moved, or the page may not have got that far.",
"failureReasonCode": "element_not_found",
"durationMs": 31204,
"httpStatus": 200,
"screenshotUrl": "/api/artifacts/clz7r0u1n2i3d4e5f6g7h8i9/screenshot.png",
"diffScreenshotUrl": null,
"shareUrl": "https://simrixmonitor.com/r/Zq8nT2xK9pLm4vR7wYbC1dF3hJ5kN6sQ8tU0xW2yA4E"
}
}
Which events can fire?
| Event | When it fires |
|---|---|
monitor_failed |
A scheduled check on a workflow monitor failed. |
monitor_recovered |
A workflow monitor passed again after a failure. |
change_detected |
A change monitor found a meaningful difference from its baseline. |
What is in the body?
| Field | Type | Notes |
|---|---|---|
event |
string | One of the three event names. |
timestamp |
string | ISO 8601, set when the request is sent, not when the check ran. |
workspaceId |
string | Your workspace. |
monitor.id |
string | Use this to correlate with your own records. |
monitor.name |
string | The monitor's name as you set it. |
monitor.type |
string | The monitor's kind, for example page_check or change_monitor. |
monitor.url |
string | The URL the check started from. Empty string if none was set. |
run.id |
string | The check's id. |
run.status |
string | For example passed or failed. |
run.changeDetected |
boolean | True only on change_detected. |
run.aiSummary |
string or null | The plain-English summary, when one was produced. |
run.failureSummary |
string or null | Why the check failed. Null on success events. |
run.durationMs |
number or null | How long the check took. |
run.httpStatus |
number or null | The response code of the final page. |
run.screenshotUrl |
string or null | A path, not a full URL. Prefix it with your Simrix Monitor address, and note it needs a signed-in session to open. |
run.diffScreenshotUrl |
string or null | The highlighted difference image. Only on change_detected. |
run.shareUrl |
string or null | A public link to this check's evidence, when the monitor has shareable reports switched on. Opens with no sign-in, so this is the link to forward. Null when sharing is off for that monitor. |
Which headers arrive?
| Header | Value | Notes |
|---|---|---|
Content-Type |
application/json |
The body is always JSON. |
X-Simrix-Signature |
sha256=<hex digest> |
HMAC-SHA256 of the raw request body, keyed with your signing secret. |
X-Simrix-Event |
monitor_failed |
The same value as the body's event field, so you can route before parsing. |
User-Agent |
Simrix-Monitor-Webhook/1.0 |
Fixed. Useful for filtering your own logs. |
How do you verify the signature?
The signature is an HMAC-SHA256 of the raw request body, keyed with your signing secret and written as lowercase hex behind a sha256= prefix.
import crypto from "node:crypto";
// Sign the RAW body. Re-serialising parsed JSON will not match.
function isFromSimrixMonitor(rawBody, header, secret) {
const expected =
"sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(header ?? "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
What should your receiver expect?
- Delivery is attempted once. A non-2xx response, a connection error or a timeout is logged and dropped. There is no retry, no backoff and no dead-letter queue, so treat a missed delivery as possible and reconcile from the app when it matters.
- The timeout is 10 seconds for the whole request. Acknowledge quickly and do your own work afterwards, rather than processing before you respond.
- The signature covers the raw body only. No timestamp is included, so there is no replay protection built in. If that matters, record
run.idand ignore ids you have already handled. - Change monitors only fire
change_detected. A change monitor that errors does not sendmonitor_failed, and change monitors never sendmonitor_recovered. Subscribing tomonitor_failedwill not tell you a change monitor is broken. - Failure and recovery webhooks follow the email toggles. Turning off Failure alerts or Recovery alerts on the notifications page turns off the matching webhook as well.
- Only scheduled checks send anything. Running a check by hand to try something out fires no webhook and sends no email.
14 days, no card required.
Frequently asked questions
Can Simrix Monitor write to a sheet without a relay?
No. There is no Google Sheets integration. Webhooks and email are the only delivery channels, so a relay does the writing.
Will the sheet capture every alert?
Almost, but not guaranteed. Deliveries are attempted once with no retry, so an outage at the relay loses that row rather than replaying it later.
Can I export check history instead?
Not today. There is no CSV or PDF export of check history in the app, which is part of why a sheet fed by webhooks is useful.
Last updated