Notifio is a desktop app that watches rental search pages and tells you the moment something new appears. Its website is 38 pages: a homepage, a pricing page, fifteen per-site alert pages, five comparison pages, eight long-form articles, and the usual legal furniture.
Two numbers govern every one of those pages. A meta title has to come in under 60 characters and a meta description under 160, because past roughly that point a search result gets truncated and the last clause of a sentence you wrote carefully becomes an ellipsis. Thirty-eight pages is more than I will hand-count reliably, so a node:test suite reads the page sources and counts for me. I wrote that suite up in Your title template spends ten of your sixty characters, and nobody counts them, and the short version is that it parses string literals out of page.tsx files and out of the catalogues the generated pages are built from, appends the root layout's %s | Notifio suffix, and asserts.
It passes. The whole suite is 140 tests and none of them fail:
ℹ tests 140 ℹ suites 34 ℹ pass 140 ℹ fail 0 This week I measured the other end of the pipe. Not the strings in the repository, the bytes on the wire. Thirty-eight curl calls, a regex for <title> and one for <meta name="description">, and a character count on whatever came back.
Three pages failed.
The three
page title description /compare 63 153 /alerts/idealista 54 161 /alerts/spareroom 55 161 A 63-character title and two 161-character descriptions, on a site whose test suite insists that nothing is over 60 or 160. Here is /compare, straight out of the served HTML:
<title>Rental Alert Tools Compared – Prices & Trade-offs | Notifio</title> The string in the repository is Rental Alert Tools Compared – Prices & Trade-offs. With the layout suffix that is 59 characters, which is what the test counted and why it passed. What went down the wire is 63, because one ampersand arrived as &.
And /alerts/spareroom:
<meta name="description" content="SpareRoom's instant alerts are a bulk send, and new free ads are reserved for Early Bird users for 7 days. Here is how to use Notifio around both, honestly."> 156 characters of English. 161 bytes of HTML. The possessive apostrophe in "SpareRoom's" is serialised as ', which is six characters doing the work of one.
The arithmetic of the inflation
Across all 38 pages there are exactly 13 character references in the title and description, and only two distinct ones:
' 9 apostrophes, all of them in descriptions & 4 ampersands, all of them in titles ' costs five bytes more than the character it encodes. & costs four. So the entire site carries 61 bytes of escaping inside numbers that are supposed to be budgets of 60 and 160, concentrated in twelve pages, and one page (/alerts/spareroom, which has an apostrophe in the description and an ampersand in the title) carries both.
The four ampersands are worth listing, because they are all the same editorial habit:
Rental Alert Tools Compared – Prices & Trade-offs /compare Download Notifio – Mac & Windows /download Help & Support /help SpareRoom Alerts & the Early Bird Problem /alerts/spareroom Four places where a human wrote "and" as "&" to save three characters in a 60-character budget, and each one spent five getting there. You can read all four with:
for p in compare download help alerts/spareroom; do curl -s "https://notifio.app/$p" | grep -o '<title>[^<]*</title>' done The escaping is not a choice anyone made
Nothing in the codebase escapes these. Every page exports a plain Metadata object with ordinary TypeScript strings in it:
export const metadata: Metadata = { title: "Help & Support", description: "Get help with Notifio: setup guide, monitoring tips, ...", }; React's serialiser escapes text and attribute values on the way out, which is the behaviour you want everywhere else on the page and which is the entire reason an apostrophe in a description cannot close the content="..." attribute early. It escapes &, <, >, " and ', and it leaves everything else alone.
That last part is visible in the same titles. The dash in Rental Alert Tools Compared – Prices is an en dash, U+2013, and it is served as a raw three-byte UTF-8 character rather than as –:
Compared \xe2\x80\x93 Prices & Trade-offs So in one attribute you get an apostrophe inflated to six characters and a dash left at one, because the rule is about HTML syntax, not about how exotic a character looks.
Which number is the real one
The entity count is the wrong unit, and the test is right to ignore it.
A crawler parses the HTML before it does anything with the text. By the time Google is deciding whether your title fits, ' has been one apostrophe for several layers already, and the string it is measuring is the 156-character one, not the 161-byte one. Measuring the served bytes tells you about your transport, not about your snippet.
Which means my audit found nothing to fix, and that is a useful result: it is the difference between "the test is lying to me" and "the test and I disagree about units". If I had pointed this at a build that was genuinely over budget, the entities would have been noise on top of a real failure, and chasing them first would have been the wrong afternoon.
There is a caveat in the other direction, though, and it is bigger than 61 bytes. Google does not truncate on a character count at all, it truncates on pixel width, somewhere around 600px for a title. "WWW" and "iii" are both three characters. The 60 that the test enforces is a proxy that happens to be checkable in CI, and the two descriptions sitting at 156 decoded characters have four characters of headroom against a limit that was never the real limit.
So the honest summary of the audit is: every page passes the budget we can test, the HTML carries 61 bytes that the budget deliberately does not count, and the budget itself is an approximation of a rule written in pixels. The pages are at notifio.app/compare, notifio.app/alerts/idealista and notifio.app/alerts/spareroom if you want to count them yourself.
One line will do it:
curl -s https://notifio.app/alerts/spareroom \ | grep -o 'name="description" content="[^"]*"' | wc -c