Nakodo has 76 public pages. 63 of them are data in a content registry, rendered by one 208-line component. The other 13 are hand-built pages with their own TSX: the home page, how it works, pricing, about, privacy, terms and the index pages.
The 63 are tested hard. There is a generated describe block per page asserting a 600-word floor, a 40-to-90-word summary, at least four search phrasings, a title short enough to survive the suffix, and a list of banned words and characters that includes the em dash. I have also checked ten writing rules against all 76 and spell-checked every word on them.
Not one of those tests asks how hard a sentence is to read. So I measured it.
The first measurement was wrong, and in a useful way
The obvious approach is to strip the tags off a page and run the text through Flesch-Kincaid. I did that first:
pages 76 words 124,477 sentences 14,081 words per sentence 8.84 syllables per word 1.483 Flesch Reading Ease 72.4 Flesch-Kincaid grade 5.35 Grade 5.35 is a children's book, and it is nonsense. 14,081 sentences across 76 pages is 185 sentences a page, and a page does not have 185 sentences. What it has is a header, a footer that links to most of the site, a cookie-free nav, 337 FAQ summaries, and tables whose cells say "No" and "Pro". Every one of those becomes a sentence when you turn </div> into a full stop, and every one of them is three words long.
Readability formulas divide by sentence count. Give them your navigation and they will tell you your site is easier to read than it is. Mine came out 1.5 grades too easy.
So the real measurement only looks at prose: <p> elements inside <main>, split into sentences inside each paragraph, with paragraph boundaries treated as sentence boundaries so that a heading-like fragment does not glue itself to the next sentence.
PROSE ONLY pages 76 paragraphs 2,455 sentences 4,686 words 68,009 words per sentence 14.51 syllables per word 1.426 polysyllables 8.6% Flesch Reading Ease 71.5 Flesch-Kincaid grade 6.89 68,009 words of prose out of 124,477 words of page. Put another way, 45 per cent of the words on our site are furniture.
Grade 6.89 and reading ease 71.5 is what the formulas call plain English: a confident 12-year-old, roughly where a newspaper aims. That is the target, so the aggregate is a pass. The interesting part is the spread.
The score is a sentence-length meter wearing a disguise
Flesch-Kincaid has two terms, words per sentence and syllables per word. Across our 76 pages:
syllables per word 1.333 to 1.550 spread 0.217 words per sentence 10.70 to 19.74 spread 9.04 The vocabulary term barely moves. Every page, whether it is about engagement rate or our privacy promises, uses words of about 1.4 syllables, because they are all written by the same person with the same habits and a test that bans the showy words. The correlations are 0.726 for sentence length and 0.693 for syllables, but the syllable correlation is riding on a range of a fifth of a syllable: multiply the spreads by the formula's coefficients and sentence length contributes 3.5 grades of variation while vocabulary contributes 2.6, and almost all of the vocabulary signal is the legal pages using "information" a lot.
In practice, on a site with one author and a banned-words test, a readability score is a sentence-length meter. Which means the fix for a hard page is nearly always a full stop, not a thesaurus.
The three hardest pages are the three with no test
Sorted by grade, the hardest pages on the site:
/about 8.89 19.74 words/sentence /privacy 8.35 18.29 /for/amazon-sellers 8.27 15.37 /how-it-works 8.26 18.50 /guides/youtube-sponsorship-formats 8.21 And the easiest:
/ 5.05 10.70 words/sentence /guides/youtube-outreach-email-templates 5.33 /glossary 5.41 (54 words of prose, so not a fair sample) /tools/sponsorship-cost-calculator 5.67 /pricing 5.84 Three of the four hardest are hand-built pages. Grouped the other way:
63 registry pages 58,281 words 14.41 words/sentence grade 6.86 13 hand-built 9,728 words 15.18 words/sentence grade 7.10 A quarter of a grade between the two groups, which is small, but the hand-built group is where the whole tail lives. /about is the hardest page on the site at grade 8.89, nearly four grades above the home page, and it is 750 words long.
The reason is not that I wrote those pages carelessly. It is that the registry pages were written against a test that prints a failure message when a summary is 91 words, and the hand-built pages were written into a TSX file where the only feedback is whether it compiles. The content test imports STATIC_PAGES, but only twice, and never to look at the words:
test("static pages are listed once", () => { const paths = [...STATIC_PAGES.map((p) => p.path), ...ENTRIES.map((e) => e.path)]; assert.equal(new Set(paths).size, paths.length); }); The other import is in a different test file, checking that every sitemap path is reachable by a signed-out visitor. The 13 pages are tested for existing and for being public. Their prose is tested by nothing.
They do pass the rules by hand, as it happens. I measured their titles and descriptions off the live HTML and every one is inside the limits the registry pages are tested against (longest title 58 characters, longest description 158). Writing to a rule you know is not the problem. The problem is the rule nobody wrote: the one about sentences.
What a 19.74 page actually looks like
Sentence lengths across all 4,686 prose sentences:
median 13 words mean 14.5 under 8 words 1,333 28.4% over 20 words 1,319 28.1% over 25 words 558 11.9% over 30 words 230 4.9% over 40 words 34 0.7% over 50 words 7 0.1% The distribution is bimodal and that is deliberate: a short line, then a long one that explains it. What makes /about hard is not one monster sentence, it is the absence of the short ones. 18 paragraphs, 38 sentences, no fragments, no lists.
The longest sentences are all doing the same job, which is listing things inside a sentence instead of in a list:
60 words /privacy "We also store your campaigns, the briefs we write from your website, your outreach settings (your offer, ask, notes, pricing and link), your conversations with creators and ..." 55 words /terms "It emails the best fits, or the ones you pick, on your behalf: it follows up, answers what it can from the details you give it, ..." 53 words /privacy "We send the emails needed to run your account: confirming your address, resetting your password, one email per campaign when its first good fits are in, ..." I am not going to shorten those three. A privacy notice that lists what it stores in one sentence is easier to check against the code than one that spreads the list over a paragraph, and I checked ours against the code promise by promise exactly because it is written that way. Readability and verifiability pull in opposite directions on a legal page, and verifiability wins.
One artefact worth knowing about
The single longest "sentence" in the first run was 68 words, on how much to pay YouTubers, and it is not a sentence. Eight of our guides print example emails a reader can copy, and the renderer puts the body in one element:
<p className="whitespace-pre-line">{block.body}</p> whitespace-pre-line means the newlines show as line breaks without needing block elements, which is right for an email and wrong for a text extractor: four bullet lines and a sign-off arrive as one paragraph with no full stops in it. There are exactly 20 of these paragraphs on the live site. Dropping them moves the site from grade 6.89 to 6.98 and takes the longest real sentence from 68 words to 60.
That is the correct direction, incidentally. Excluding the sample emails makes the site look harder, because sample emails are written in short friendly lines. An extractor that cannot tell prose from a code block or a letter will flatter any page that contains one.
Run it on your own page
This is the whole measurement, in a form you can paste into a console on any page of nakodo.app or your own site:
const ps = [...document.querySelectorAll("main p")] .map((p) => p.textContent.trim()) .filter((t) => /[A-Za-z]{4}/.test(t)); const sents = ps.flatMap((t) => t.split(/(?<=[.!?])\s+/)).filter((s) => /[A-Za-z]/.test(s)); const words = ps.join(" ").match(/[A-Za-z][A-Za-z'’-]*/g) ?? []; console.log({ paras: ps.length, sents: sents.length, words: words.length, wps: +(words.length / sents.length).toFixed(2) }); On our pages it prints:
/about { paras: 18, sents: 38, words: 750, wps: 19.74 } /privacy { paras: 35, sents: 75, words: 1371, wps: 18.28 } /how-it-works { paras: 37, sents: 114, words: 2109, wps: 18.5 } /pricing { paras: 20, sents: 52, words: 701, wps: 13.48 } / { paras: 70, sents: 116, words: 1249, wps: 10.77 } Note the home page: 70 paragraphs for 1,249 words, because its copy is mostly short labelled fragments next to hand-drawn illustrations. If you join the paragraphs before splitting on punctuation instead, the fragments without full stops merge into their neighbours, the sentence count drops from 116 to 85, and the home page's words per sentence jumps from 10.77 to 14.7. Four grades of difference on one page, from one decision about what a paragraph boundary means.
Which is the honest caveat on all of this. Readability numbers are reproducible, not objective. Mine are: prose only, inside <main>, paragraphs are sentence boundaries, sample-email blocks included. Change any of those four and my site moves a grade.
What I am changing
- A sentence-length assertion in the content test, not a readability one. Grade level is a derived number that moves when my extractor's rules move; "no paragraph may average over 20 words a sentence" is a rule I can act on. The three pages it would fail today are the three I would want it to fail.
- The 13 hand-built pages need to be in a copy test at all. Their titles and descriptions already have limits that only the registry pages are checked against, and they pass by habit. Habit is not a test.
- /about gets rewritten. 750 words, 38 sentences, no page on the site is further from the house voice, and it is the page that says who we are.
Nothing here is a bug. It is a measurement that found the one part of the site where the feedback loop is missing, and the measurement agrees with what I would have guessed if I had been asked which pages were written without a test watching.

