HTML changelogs as pages, written for the customer

A changelog written from commit messages is a list of things nobody outside the team can act on. Write each entry from the reader's side, mark what needs action, give every entry an anchor, and keep it at one address that never changes.

An HTML changelog as a page has one reader: someone checking whether the thing they wanted has happened, or whether the bug that affected them is fixed.

An HTML changelog written from the customer side: three categories, newest first, one page.
An HTML changelog written from the customer side: three categories, newest first, one page.

Almost every changelog is written for a different reader, the team, from the commit messages, and the customer learns nothing they can act on.

This guide covers writing from the customer's side, the three categories, newest first on one page, marking what needs action, why an empty month is information, and the four steps to set the changelog up at one address.

A changelog has one reader: someone checking whether the thing they wanted has happened, or whether the bug that affected them is fixed. Almost every changelog is written for a different reader — the team.

The HTML changelog: write from the customer's side

<!-- from the commit log -->
<li>Refactored share token resolution and added Firestore index</li>

<!-- from the reader's side -->
<li>Shared links now open in under a second, including on the first visit.</li>

The first tells a customer nothing they can act on. The second tells them whether to try again.

The test for every entry: could a reader tell whether this affects them? If not, it belongs in release notes for the team, not here.

The three categories

<h3>New</h3>       <!-- they can now do something they could not -->
<h3>Better</h3>    <!-- something they already did now works better -->
<h3>Fixed</h3>     <!-- something that was broken -->

Three headings, in that order. Drop any that is empty rather than writing filler under it.

"Fixed" is the section customers read most closely, and the one most often thinned out because a long list of fixes feels like an admission. It is the opposite — it is evidence that reports get acted on.

Structure

<article id="2026-09-12">
  <h2><a href="#2026-09-12">12 September 2026</a></h2>

  <h3>New</h3>
  <ul>
    <li>Pages can be duplicated, which makes a weekly report a two-click job.</li>
  </ul>

  <h3>Fixed</h3>
  <ul>
    <li>A pasted table with merged cells no longer loses its header row.</li>
  </ul>
</article>

Each entry has an id and a self-link. That is what lets support reply "fixed on the 12th — see [link]", which is the most common thing a changelog is actually used for. Without anchors, the answer is "it is in the changelog somewhere".

Newest first, one page

/changelog
One page at one address. Link it from the app footer and it is always current.
One page at one address. Link it from the app footer and it is always current.

One address, never changing, newest at the top. Readers are asking "what changed since I last looked", which is a reverse-chronological question.

Do not split by version unless your customers think in versions. Most do not; they think in dates.

Say when something needs action

<li>
  <strong>Action needed:</strong> API keys created before August stop working on 1 November.
  Regenerate yours in Settings.
</li>
Say when something needs action. The red tag is the only one a reader must not miss.
Say when something needs action. The red tag is the only one a reader must not miss.

Mark these clearly and put them at the top of the entry. A breaking change buried among improvements will be missed, and then it is your support queue.

An empty month is information

<article id="2026-08">
  <h2>August 2026</h2>
  <p>Nothing customer-visible. We spent the month on the storage migration
     that makes the faster shared links above possible.</p>
</article>

Better than a gap. A gap reads as abandonment; a one-line explanation reads as a team that was busy. And it is honest, which is the whole currency of a changelog.

What to leave out

Internal refactoring, unless it produced something the reader notices. Then describe the thing they notice.

Dependency updates. Nobody outside the team is checking.

Marketing language. "We are thrilled to announce" in a changelog is out of register — this is a document people scan for facts.

Version numbers as headings, unless customers use them.

Linking the changelog from where the question is asked

The customer asking "is this fixed" is in a support thread, a help page, or the app. Put the changelog address in all three, and answer the question with the entry's anchor rather than a sentence.

When the same fix is asked about ten times, ten replies contain the same link, and the changelog becomes the place people check before asking.

Revise the text click and type save Same document new version stored unchanged Same address nothing to resend
Each release is an edit at the top of the same page. The address in the footer, the help page and every support reply stays the same.

Why one page at one address

A changelog is linked from support replies, release emails, and documentation, and those links have to keep working for years. One address, appended to, is the only shape that supports that.

In NOS the changelog is a document at a fixed address whose text is clickable text — adding this week's entry is typing at the top, and every anchored link ever sent still resolves to the right entry.

Entry quality test

Entry Passes Why
"Refactored the share token resolver" No Nothing a reader can act on
"Shared links now open in under a second" Yes States the change they will notice
"Fixed a bug in the table parser" No Which bug, affecting what
"A pasted table with merged cells keeps its header row" Yes Specific and recognisable
"Various improvements and fixes" No Says nothing at all
"Nothing customer-visible this month" Yes Honest, and better than a gap

The test is always the same: could a reader tell whether this affects them.

Where it sits with your other updates

A changelog is the customer-facing record. A weekly update is the internal one, and a roadmap is the forward-looking one. Keeping them separate matters — a changelog that includes plans will be read as commitments, and a roadmap that includes shipped work stops being a plan.

One address each, appended to. Every link ever sent into a support reply keeps resolving.

Versions, dates, or both

Customers think in dates; developers think in versions. Head each entry with the date, put the version number in small type beside it if you have one, and never make the reader translate.

A customer who asks "was that fixed before my renewal on the 10th" needs the date; the version is for the support engineer checking which build they are on.

Setting up the changelog: 4 steps

  1. Write each entry as what changed for the reader. Not the commit. "Revoke a share link: open Share, choose Revoke" tells the reader what they can now do.
  2. Use three categories and mark action needed. New, improved, fixed, and a red action needed tag with a date for anything the reader must do themselves.
  3. Give every dated entry an anchor. A heading id per date, so support can send a customer straight to the fix that concerns them.
  4. Paste it into a NOS document and keep the address forever. Share, then Share link, then Create link. Newest first, added to in place, and the address in the app footer never changes. Turning HTML into a link is this step.

Questions people ask

What makes a changelog readable?

Entries written from the customer's side — what they can now do, or what stopped being broken — rather than what was implemented.

Newest first or oldest first?

Newest first. Readers are checking what changed since they last looked.

Should each entry have its own link?

Yes. An anchored entry can be linked from a support reply, which is the single most common use a changelog gets.

How often should it be updated?

Whenever something changes for a user. An empty month is information; a changelog that skips six months and then posts everything is not read.

Keep reading