llms.txt
Search Documentation
Search through all documentation pages
v4.x

v4.1.8 Changelog

See what's new in Kener v4.1.8, including hidden monitors for your team, SSL certificate details, image uploads through the API, and v4 API writes that match the dashboard

Release date: October 22, 2026

Important

Two changes can surprise you after the upgrade:

  • Signed-in users whose role has monitors.read now see hidden monitors on the status site. All three built-in roles have it. See Hidden monitors for your team.
  • Some /api/v4 writes now return 400 for input that they stored before, and some writes now do more, for example send subscriber emails. See API changes.

New features

Hidden monitors for your team

A signed-in user whose role has monitors.read now sees hidden monitors on the status site. Before, a monitor set to Hidden in Status Page was hidden from everyone, your team too. Now you can keep private monitors in the same Kener install. All three built-in roles (admin, editor, member) have monitors.read. A user whose custom role does not have it sees what an anonymous visitor sees.

For these users, hidden monitors show on:

  • / and /{page_path}, when the monitor is on the page.
  • /monitors/{tag}, with its status bars, latency chart, and day details.
  • The affected monitors on /incidents/{id} and /maintenances/{id}.

Badges, embeds, RSS feeds, sitemap.xml, events pages, inline events, the notifications list, and subscriber emails still hide hidden monitors for every viewer.

If you added hidden monitors to a public page, your signed-in members now see them there. Anonymous visitors still do not.

Kener now sends Cache-Control: private on each response to a signed-in request, unless the route sets its own header.

Warning

A CDN rule that ignores the origin's Cache-Control header can cache a signed-in page and serve its hidden monitors to anonymous visitors. Do not cache HTML or /dashboard-apis/* responses for requests that carry the kener-user cookie.

See Signed-in viewers.

SSL certificate details on the status page

SSL monitors now show the certificate state on the home page bars and on /monitors/{tag}:

State Meaning
SECURED The certificate is valid and has not expired
INSECURE The certificate expired or failed verification, for example self-signed, unknown CA, or wrong host name
UNKNOWN The latest check read no certificate, for example after a connection error or a timeout

The page also shows the time remaining, the expiry date, and the issuer. If the page stays open past the expiry, the label changes to INSECURE by itself.

The SSL monitor also gets three optional fields:

  • timeout (Timeout (ms)) sets the TLS handshake timeout. The default is 10000. Before, a host that did not answer kept the worker waiting with no limit.
  • tlsServername (TLS Server Name (SNI)) sets the SNI name for a monitor whose host is an IP address. Kener sends no SNI for a bare IP.
  • allowSelfSignedCert (Allow Self-Signed / Untrusted Certificates) judges an untrusted certificate by its expiry only. The monitor can be UP, but the page still shows INSECURE, because a browser rejects that certificate.

A DOWN threshold of 0 hours is now allowed. latency is still the TLS handshake time, so latency alerts, badges, embeds, and API data do not change. See SSL Monitor. Thanks to @phatlet.

Upload images through the API

POST /api/v4/images takes an API key and a base64 image, and returns an /assets/images/<id> URL. Put that URL in page_logo, the site logo, the favicon, a monitor image, or any other image field. Before, only the dashboard could upload an image, so a tool that copies config between two Kener instances could not copy logos.

curl -X POST https://your-kener.com/api/v4/images \
  -H "Authorization: Bearer $KENER_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"base64\":\"$(base64 < logo.png | tr -d '\n')\",\"mime_type\":\"image/png\"}"
  • The image ID comes from the image content: the first 16 hex characters of its SHA-256, plus .png or .jpg. When you upload the same image again, Kener stores nothing new and returns the same ID. Old image IDs keep working.
  • When you leave out max_width and max_height, Kener keeps the original size. The dashboard still fits images inside 256×256.
  • On MySQL, a migration changes images.data from text to longtext. Before, MySQL rejected an image over about 49 KB with "Data too long", in the dashboard too. The migration does nothing on PostgreSQL and SQLite.

See the API Reference.

Inline events and the event list together

Before, Display Events Inline controlled two things. On showed inline event cards and a side column with the event list, and it removed the top bar button. Off showed the button only. Now a separate Event List setting picks where the list of current and past events shows:

eventListPlacement Status pages (/ and /{page_path}) Monitor pages
button (Top bar button, default) Top bar button Top bar button
aside (Side column) Column on the right Top bar button
hidden (Hidden) No list No list

So you can now show the inline cards and the top bar button together. An install that has no eventListPlacement yet keeps its home page look: Kener uses aside when inline events are on, and button when they are off. No migration runs.

If you have inline events on, two pages change:

  • Custom status pages (/{page_path}) now show the side column. Before, they showed no event list.
  • Monitor pages now show the top bar button. Before, they showed no event list.

The side column and the button badge now load the events of the current page when you switch between custom pages. Before, they kept the events of the first page. See Event display settings.

Set your own heartbeat secret

The heartbeat secret is the last part of the heartbeat URL, /ext/heartbeat/{tag}/{secret}. Before, the admin UI could only make a random one. Now you can type a known value in Heartbeat secret, or set type_data.secretString through the API. Then you can give a sender, such as a Prometheus Alertmanager rule, its URL before the monitor exists.

  • The rule is at least 12 characters, using only A-Z a-z 0-9 . _ ~ -. The admin form keeps the save button off while the value breaks the rule.
  • POST /api/v4/monitors and PATCH /api/v4/monitors/{tag} return 400 with code BAD_REQUEST for a new or changed secret that breaks the rule. Before, the API stored any value, for example a/b?c.
  • A heartbeat monitor saved with no secret gets a generated one, and the response includes it. Before, a heartbeat monitor created through the API with no secret could never receive a heartbeat.
  • A cloned heartbeat monitor gets a new secret. Before, the clone kept the secret of its source.
  • A stored secret that a save sends back unchanged keeps working, even when it breaks the rule.

See Heartbeat secret.

Default Docker connection from `DOCKER_HOST`

A new Docker monitor now starts on the connection in DOCKER_HOST. Before, it always started on /var/run/docker.sock, so behind a socket proxy you typed the proxy address into each new monitor.

Environment A new Docker monitor starts on
DOCKER_HOST not set socket, /var/run/docker.sock
DOCKER_HOST=unix:///run/proxy/docker.sock socket, /run/proxy/docker.sock
DOCKER_HOST=tcp://docker-socket-proxy:2375 tcp, docker-socket-proxy:2375
The same, with DOCKER_TLS_VERIFY or DOCKER_TLS set tls, docker-socket-proxy:2375
Any other value, for example ssh:// socket, /var/run/docker.sock, and the server logs one warning

A saved Docker monitor keeps its stored connection. A monitor that you create through /api/v4/monitors does not use this default, so send connectionType and daemon. See Default connection and DOCKER_HOST.

State and impact flags in subscriber emails

A subscription_update email template can now change with the state and impact of an incident, for example a red banner when an incident starts and a green one when it is resolved. Mustache cannot compare strings, so most of the new variables are flags:

Variable Value
update_state The state of the update, for example INVESTIGATING
is_investigating, is_identified, is_monitoring, is_resolved true for the state of the update
incident_impact The worst impact among the visible monitors of the incident: DOWN, DEGRADED, or empty
is_down, is_degraded true for that worst impact
is_maintenance true in maintenance emails

Existing templates render as before. See subscription_update. Thanks to @codekuu.

API changes

Every v4 API write now runs the same code as the same dashboard write. Before, 11 route files wrote to the database themselves, so an API write could skip a step that the dashboard does.

Incidents:

  • POST /api/v4/incidents/{incident_id}/comments now emails subscribers. An update that reopens a resolved incident now clears its end time. Thanks to @andrewmitchell-automations.
  • PATCH /api/v4/incidents/{incident_id}/comments/{comment_id} now changes the incident state and end time, the same as the dashboard.
  • A RESOLVED update dated before the incident start returns 400 with "A RESOLVED comment cannot be dated before the incident start". This applies to POST and PATCH.
  • DELETE /api/v4/incidents/{incident_id}/comments/{comment_id} stores the update as INACTIVE, not DELETED. Every v4 comment route returns 404 for an update that is not ACTIVE.
  • DELETE /api/v4/incidents/{incident_id} deletes the updates of the incident. Before, they stayed with status DELETED.
  • POST /api/v4/incidents keeps an end_date_time that you send. A monitor impact other than DOWN, DEGRADED, or MAINTENANCE returns 400. The same monitor twice returns 201. Before, it returned 500 and left a half-saved incident.
  • An incident end before its start returns 400, for a new end and a new start alike. A start_date_time of 0 returns 400. A PATCH with title: "" keeps the old title.

Maintenances:

  • PATCH /api/v4/maintenances/{maintenance_id} with a new start keeps the COMPLETED and CANCELLED events. A new start in the same minute no longer sends a second "Maintenance Created" email.
  • PATCH /api/v4/maintenances/{maintenance_id}/events/{event_id} returns 400 for a window shorter than one minute.

Monitors, pages, and site data:

  • POST /api/v4/monitors and PATCH /api/v4/monitors/{tag} return 400 with code BAD_REQUEST for a proxy that is not an http:// or https:// URL, for example socks5://proxy.internal:1080. A PATCH that sends back the stored proxy unchanged still succeeds.
  • The same two routes now check the heartbeat secret. See Set your own heartbeat secret.
  • POST /api/v4/pages and PATCH /api/v4/pages/{page_path} return 400 for a monitor tag listed twice, before they save anything. Before, POST saved the page and PATCH removed all its monitors, and then both returned 500.
  • PATCH /api/v4/site/oidcSettings now clears the OIDC config cache, the same as the dashboard.

The same work changes three things in the dashboard:

  • A manual edit of monitoring data now updates the latest status and queues an alert evaluation, the same as the API. So a manual DOWN edit can fire an alert.
  • A RESOLVED update dated before the incident start fails before Kener saves anything. Before, the dashboard saved the update, returned a server error, and left the incident open. Alerts get the same check.
  • An incident edit whose new start is after the stored end is now rejected.

Security

Three production dependencies move past critical advisories. Thanks to @codekuu.

Package Before Now Advisory
protobufjs 7.5.4 7.6.6 GHSA-xq3m-2v4x-88gg (critical), GHSA-75px-5xx7-5xc7 (high)
proxy-addr 2.0.7 2.0.8 GHSA-jqcg-44mw-7w3h (critical)
shell-quote 1.8.3 1.12.0 GHSA-w7jw-789q-3m8p (critical)

The fixes for hidden monitors that leaked to the public are in Bug fixes.

Improvements

Warning when a secret goes over plain HTTP

The API and Prometheus monitor editors now show a warning when the monitor uses a $SECRET variable and its URL or proxy uses plain http://. Kener sends that secret in clear text. HTTP targets still work. Thanks to @lokiee0.

Release images publish when one image fails

The release workflow builds four Docker images. Before, when one build failed, GitHub cancelled the other three. So the v4.1.6 and v4.1.7 images did not publish at release, and latest stayed on v4.1.5. Now each image builds on its own. The v4.1.7 images were published again on October 8, 2026.

Bug fixes

  • Inline incidents no longer show hidden monitors. With inline events on, an ongoing incident on /, /{page_path}, or /monitors/{tag} showed the name and image of a hidden monitor to anonymous visitors. Inline incidents now leave hidden monitors out for every viewer.
  • Event lists no longer match events through hidden monitors. Inline events and /dashboard-apis/notifications?tags=… matched an event through any linked monitor, hidden or not. So anyone who knew the tag of a hidden monitor could read the titles of the events that affect only that monitor. Now an event shows only when it is global or links a monitor that is not hidden. On the page of a hidden monitor, signed-in users see only global events inline. They still see the events of that monitor in its day details.
  • Maintenance emails and /maintenances/{id} no longer name hidden monitors. Maintenance emails listed hidden monitors, for example Billing DB(MAINTENANCE). The page data of /maintenances/{id} (__data.json) held the tag of a hidden monitor for anonymous visitors, but the page did not show it.
  • Subscribers get emails only for events that a status page shows. A non-global event whose linked monitors are all hidden no longer emails its title to subscribers. A non-global event with no linked monitors sends no email either. {{incident_impact}} now counts only visible monitors, so a hidden DOWN monitor no longer makes the email say DOWN.
  • A masked secret no longer becomes the stored secret. Since v4.1.7, Kener masks the OIDC client_secret and the captcha Secret Key in responses. On an instance with no stored secret, a save that sent the masked value stored the mask as the real secret. This happened, for example, when you copied oidcSettings from one instance to another. Kener now stores an empty string, and the PATCH response shows "". A copied captcha config with isEnabled: true shows as misconfigured until you enter the Secret Key.
  • Latency and uptime alerts close their incidents. With incident creation on, a LATENCY or UPTIME alert opened an incident with no monitor and no link to the alert, so the incident never closed. These incidents now get the monitor with the DEGRADED impact, and they close with the alert. The opening email of an alert incident now also carries the impact.
  • Status bars no longer return 500 for bad numbers. On PostgreSQL, /dashboard-apis/monitor-bars and /dashboard-apis/monitor-bar returned 500 for days=abc or endOfDayTodayAtTz=NaN. A bad value now gets the same default as a missing one. A timezone that Kener cannot read now falls back to UTC, so the browser no longer sends NaN. Thanks to @anandghegde.
  • Embeds use the defaults for a bad days or height. /embed/monitor-{tag} and /embed/latency-{tag} sent days=NaN to the API, and drew the latency chart at height: NaNpx. A bad value now gets the default: 90 days and 128 px. Only whole numbers count, so ?height=300px and ?days=30abc now also get the defaults.
  • The duration label stays under the navbar. On incident and maintenance cards, the duration between the start and end dates drew on top of the navbar when you scrolled.

Documentation

  • Every v4 monitor API example now sends monitor_type. Before, the examples sent type, which the API ignores, so a copied example created an API monitor.
  • Monitors Overview now lists the Prometheus monitor.
  • User Subscriptions now says that each incident update emails subscribers, from any source, and which events send no email.