Changelog
Reaching readers
Publishing an entry is half the job; the other half is making sure people see it. A changelog can show new entries inside your own app with a widget, email them to subscribers, post them to Slack and your own webhooks, and offer feeds for readers and AI tools. This page covers each channel.
Most channels use the changelog's own domain, so connect one first. See Changelog settings.
The "What's new" widget
The widget adds a button to your website or app that opens the changelog's 10 newest entries in a panel, with a count of entries the visitor has not seen yet.
Add it to your site
Check the settings
In Settings, Widget, keep Show the widget on, and set the Button label (1 to 30 characters; "What's new" by default) and the Position: Bottom right, Bottom left, or No button (I'll attach it to my own element). Choose Save widget.
Optional attributes on the script tag:
| Attribute | What it does |
|---|---|
data-position |
bottom-right, bottom-left or none, overriding the setting. |
data-selector |
A CSS selector of your own link or button to attach the unread badge to, for example #whats-new. |
data-theme |
light, dark or auto. |
data-label |
The button text, overriding the setting. |
Embed the list in a page
Where you cannot add scripts, or to show the list inside a page, use the iframe:
<iframe src="https://changelog.example.com/embed" title="What's new" loading="lazy" style="border:0;width:100%;height:480px"></iframe>
Under Allowed sites, list the origins allowed to show the iframe, such as https://app.example.com. Leave it empty to allow any site.
Content Security Policy
If your site sets a Content Security Policy, allow your changelog's domain in script-src and connect-src. Add it to style-src for older browsers, and to frame-src if you use the iframe.
The widget sets no cookies. It remembers the latest entries for a minute in the browser's local storage, so page views within a minute do not fetch them again.
Feeds
Every published changelog has three feeds on its domain:
| Feed | Address |
|---|---|
| RSS 2.0 | /feed.xml |
| Atom 1.0 | /atom.xml |
| JSON Feed 1.1 | /feed.json |
Add ?category=<slug> to follow one category, for example https://changelog.example.com/feed.xml?category=fixed.
Email subscribers
Readers subscribe with the Subscribe button on your changelog. They enter their email address, can pick only some categories, and agree to receive emails. Nothing is sent until they confirm through the link in a confirmation email (valid for 7 days).
Choose when to email
In Settings, Subscribers, under When to email subscribers:
- Instant — email each new entry when it is published.
- Weekly digest — one email a week with that week's new entries, on the day and hour (UTC) you choose. A week with nothing new sends nothing.
- Off — no subscribe form and no emails.
Only the first publish of an entry is emailed, never an edit, and only when Notify subscribers and integrations was on. Subscribers who follow some categories only get entries in those categories.
Set a Reply-to address if subscribers should be able to reply. The card also shows how many emails were sent today; past the daily limit, emails wait for the next day.
Every email carries an unsubscribe link, and mail clients get a one-click unsubscribe. Emails are sent from EvoHub on the changelog's behalf, with your changelog's name and brand colour, and contain no tracking pixels.
Note
The subscribe form and every link in the emails open on the changelog's own domain, so nobody can subscribe until the changelog has an active custom domain.
Manage subscribers
The Subscribers list shows every address with its status — Confirmed, Waiting to confirm or Unsubscribed — and the categories it follows. Search by email or filter by status. Export CSV downloads the list with each address's consent record. Deleting a subscriber erases the address and its consent record.
Reactions and feedback
In Settings, Widget, under Reactions and feedback:
- Reactions lets readers react to an entry with an emoji: thumbs up, heart, celebrate, eyes or rocket.
- Feedback adds a Send feedback link under each entry. Readers send a short private comment (up to 1,000 characters), with an email address if they want a reply.
Read comments on the Feedback page, mark them resolved, or delete them.
Slack and webhooks
In Settings, Integrations (for people who manage the changelog), you can announce each newly published entry to up to 10 destinations. Like email, only an entry's first publish with Notify subscribers and integrations on is sent.
Slack
Create an incoming webhook in Slack, then add it under Slack with a name and the webhook address (it starts with https://hooks.slack.com/services/). Each new entry is posted with its title, summary and a Read the update button.
Webhooks
Add your endpoint under Webhooks with a name and an https address. EvoHub shows a signing secret once; copy it then. Each new entry is sent as a POST with a JSON body:
{
"id": "cdel_...",
"type": "entry.published",
"created_at": "2026-10-01T09:00:00Z",
"site": { "slug": "acme", "name": "Acme Updates", "url": "https://changelog.example.com" },
"entry": {
"slug": "faster-dashboards",
"title": "Faster dashboards",
"summary": "Dashboards load twice as fast.",
"version": "v2.4.0",
"date": "2026-10-01T09:00:00Z",
"categories": [{ "slug": "improved", "name": "Improved" }],
"tags": ["dashboards"],
"url": "https://changelog.example.com/faster-dashboards",
"body_md": "..."
}
}
Requests carry the headers X-EvoHub-Event, X-EvoHub-Delivery and X-EvoHub-Signature: t=<unix time>,v1=<hex>. The signature is an HMAC-SHA256 of t + "." + raw body with your signing secret. Verify it on the raw body and reject requests more than 5 minutes old:
import crypto from "node:crypto";
// rawBody: the request body exactly as received, not re-serialised JSON.
export function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(t + "." + rawBody)
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1 ?? "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
A failed delivery is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours. For each destination you can switch it Active on or off, Send test (a ping event), look at the last 50 Deliveries, Rotate secret (the old secret stops working at once) and Delete it.
AI tools
Every published changelog is readable by AI assistants on its domain:
/llms.txtand/llms-full.txt— an index and the full text, following llmstxt.org./<entry>.md— any entry as Markdown (or request the entry withAccept: text/markdown)./mcp— an MCP server with the toolslist_entries,get_entryandsearch.
Let AI crawlers read the changelog in Settings, General controls what robots.txt says to AI crawlers such as GPTBot and ClaudeBot; llms.txt stays available either way.
Related
Was this page helpful?
