I sell a $19 PDF. Today I had my Claude Code setup do something I had never done in the three and a half months the thing has been on sale: read the sales page line by line, and check every single claim against the file that buyers actually download.
It came back with 21 edits — claims that were wrong, links that were missing, and dates that had quietly rotted.
The worst one was this sentence, which appeared twice on the page:
Free preview (Chapter 2 sample, no signup): The Five Migration Triggers (free Gist, measurable thresholds)
That preview did not exist. I had never written it. And neither of the two mentions was even a hyperlink — just plain text, sitting there, telling people to go try something free before buying, with nowhere to go.
I want to write down how that survived three and a half months, because the mechanism is boring and I suspect it is not just me.
The audit was mechanical, and that is the point
The instruction I gave was narrow: download the actual delivered file, count what is in it, then go through the page claim by claim. Not "improve the copy." Just: does the page say things the file does not do.
The counting part is easy and immediately useful:
# the file buyers actually get, not the file in your build directory
python3 - <<'PY'
import pypdf
r = pypdf.PdfReader("delivered.pdf")
txt = "\n".join((p.extract_text() or "") for p in r.pages)
print(len(r.pages), "pages,", len(txt), "chars")
PY
251 pages. The page said 251 pages. Good.
Eleven triggers, the page said. The chapter headings ran 1–5 and 11–16, which looks wrong until you count them: eleven. (6–10 were candidates that never got promoted, so the numbering has a hole in it. Fine.) Good.
Then this, in a paragraph about running production workloads on an API key:
the Playbook's Trigger 14 chapter is the operator-side mapping of that recommendation
Trigger 14 in the actual book is the irreversible-operation cluster. The chapter about programmatic billing is Trigger 15. And two paragraphs further down, the same page says "Trigger 15 (programmatic credit pool separation)" — correctly.
So the page contradicted itself, in writing, and I had read that page dozens of times.
Claims live in fields, not pages
Here is the part that actually changed how I work.
Three days earlier I had found the same problem on a different product — a ¥500/month membership whose page promised "a new edition on the 1st of each month." I checked the delivery record: six editions shipped, none of them on the 1st. I rewrote the promise, published the real dates, and considered it handled.
It was not handled. When I went back today to copy the corrected wording, the old promise was still sitting in three other places on the same product:
| Where | What it still said | Reality |
|---|---|---|
| Your terms (the field buyers are held to) | "arrives on the 1st of each month at 09:00 JST" | 0 of 6 editions |
| Same field | "distributed as PDF and Markdown" | they are post bodies, no attachments |
| Same field | refund policy built on "arrives within the first five days" | the premise is false, so the policy is incoherent |
| Same field | "messages are checked at least once per business day" | no mechanism behind it at all |
| Tier description | "745 hooks" | 911, counted today |
| Tier description | "[June edition, shipping 2026-06-01] current material…" | June was never delivered to members |
| Welcome message (first thing a new member reads) | "delivered between the 1st and 5th" | same broken promise |
Seven surfaces in this one product, on top of the page I had already fixed three days earlier. I had fixed the page and told myself I had fixed the promise.
A page is one text field out of many. Storefronts scatter your claims across a description, a short summary, a terms box, a welcome email, a receipt, a tier blurb. You edit the one you look at. Nobody edits the terms box, because nobody reads the terms box — except the person who paid.
Rule I now follow: when you correct a claim, grep the whole product for the claim, not the page for the sentence. And fix the terms field and the post-purchase message first, because those two are the ones a paying customer is actually entitled to rely on.
The link check that checked nothing
The page linked to four browser tools hosted through htmlpreview.github.io, which renders a raw Gist as HTML. All four returned HTTP 200. Great.
Then, out of habit, I ran the same check against a Gist ID I made up:
$ curl -s -o /dev/null -w "%{http_code} %{size_download}\n" -L \
"https://htmlpreview.github.io/?https://gist.githubusercontent.com/me/0000000000000000000000000000dead/raw/nope.html"
200 1269
- Of course it does — htmlpreview is a client-side shim. It always loads; the fetch that can fail happens in the browser afterwards. My "are the links alive" check could not distinguish a live tool from a deleted one.
The check with discriminating power is the raw URL underneath:
$ curl -s -o /dev/null -w "%{http_code} %{size_download}\n" -L \
"https://gist.githubusercontent.com/me/0000000000000000000000000000dead/raw/nope.html"
404 14
Before you trust a check, run it against something you know is broken. If it passes, the check is decoration. This costs thirty seconds and it is the single habit that has saved me the most embarrassment.
(The four real tools were fine, by the way. I just could not have honestly said so before.)
What to do with a promise you did not keep
The obvious fix for the missing preview was to delete the sentence. Twice. Two minutes of work, and the page becomes true.
I did not do that, and I want to be clear that this was not nobility — it was arithmetic. That sentence is the only thing on the page inviting a stranger to check my work before paying me. Deleting it makes the page honest and slightly worse at its job.
So instead the agent pulled Chapter 2 out of the delivered PDF — the five triggers, the measurable threshold on each — and I published it as the free preview the page had been promising. Now the sentence is true and it is a link.
One detail from that, since it is the same lesson wearing a different hat: the chapter tells you to run /usage --json to get your cache numbers. I checked whether that still works on my current version before publishing a document telling strangers to run it. The literal string does not appear anywhere in the shipped binary anymore. So the preview says so, plainly, and gives a command I actually ran instead — reading cache_creation_input_tokens and cache_read_input_tokens out of the session transcripts. My own seven-day ratio came out at 0.017, well under the threshold the chapter warns about.
I would rather ship a preview that admits one of its instructions has aged than one that quietly wastes a reader's afternoon.
Four things you can run on your own product today
- Download the artifact your customers get — from the customer-facing URL, not your build folder — and count it. Pages, chapters, files, whatever number your page brags about.
- Grep the page for every proper noun and number it uses about the product. Chapter names, feature counts, version numbers. Every one is a claim.
- List every editable text field the storefront has, not just the description. Terms, summary, welcome message, receipt, tier blurbs. Read all of them.
- Take every "try it free" reference and confirm the thing exists. Not that the link returns 200 — that the artifact it names is real. Mine failed this one twice on the same page.
The free preview that started all this is here, if you want to see what four months of not checking looks like after it gets checked. It ends by telling you not to buy the book if none of the five thresholds trip on your own numbers, which is the honest outcome of running the measurements, and the reason the measurements are the free part.
I run Claude Code autonomously and write up what breaks. The scanning and counting above was the agent's work; the four months of not looking were mine.
Correction (2026-08-12, hours after publishing): this post originally said "Seven surfaces, counting the two I had already fixed." I went back to count instead of remembering, and only one surface had been fixed earlier — the short description — and it is not one of the seven. Getting the size of my own error wrong, in a post about claims that were never checked against reality, is the same failure one level up. The seven in the table are unchanged; they were counted from the live fields.
Top comments (0)