Notifio has two things to sell. The lifetime licence, which monitors rental search pages and alerts you, and the auto-reply upgrade, which messages the landlord for you. Both are one-time payments, the same price, and the second one sits on top of the first rather than replacing it:

// server/src/lib/pricing/constants.ts export const LICENSE_PRICE_PENCE = 2000; export const UPGRADE_PRICE_PENCE = 2000; 

Two products, one catalogue. Go and look at /pricing and you will find two cards, two prices in 72px type, and one button.

What the button census says

I pulled the markup of all 38 live pages and counted. The entire site has two <form> elements and, on the pricing page, exactly one <button>:

<button type="submit" ...>Buy now · €24.99</button> 

That is the licence. The auto-reply card next to it has the headline price, a paragraph explaining what it does, a line about VAT, and then no control of any kind. Instead it has a sentence:

Auto-reply needs a lifetime licence first. Once you have activated Notifio, open the Auto-reply tab and unlock it there.

So the website advertises a product it cannot sell you. That looks like an oversight and it is not. The reason is in the route's own doc comment.

The reason is that the site cannot ask who you are

// server/src/app/api/checkout/upgrade/route.ts /** * Starts a Stripe Checkout session for the one-time auto-reply upgrade. * * Requires an existing, active licence: the upgrade extends the lifetime * licence rather than replacing it, so we authenticate with the same * email + token pair the desktop app already holds. That is also why this is * driven from inside the app rather than from the public pricing page. */ 

The upgrade is a purchase that only makes sense for somebody who already owns something, so the first thing the route does after rate limiting is prove ownership:

const license = await resolveLicense(email, token); if (!license) { return NextResponse.json( { error: "No active licence found for this email and token." }, { status: 403 } ); } // The upgrade is permanent, so there is never a reason to buy it twice. if (license.autoReply) { /* ... refused ... */ } 

And there is the whole story, because Notifio has no accounts. There is no session, no cookie, no logged-in state anywhere on the marketing site. The only client in the world that can satisfy that resolveLicense call without asking a human to type a secret into a web page is the desktop app, because the app already holds the email and token on disk from activation.

A website with accounts would put a button there without thinking about it. Ours would have to grow a form that takes an activation token, which means a public endpoint that accepts a 60-bit secret typed by hand, for a purchase the app can start with one click and no typing at all. The in-app flow then hands the checkout URL to the system browser rather than rendering it in a window we control, which I wrote about in our in-app purchase leaves the app.

I am happy with that trade. What I am not happy with is what the census found next.

Where the words are

I stripped scripts and tags from all 38 pages and counted mentions of auto-reply in the visible text:

Page Mentions
/terms 25
/privacy 11
/pricing 5
/ 4
23 other pages 1 to 3 each
/help 0

Twenty-seven of 38 pages mention it, 88 times in total, and 36 of those 88 are in the two legal documents. The two pages nobody reads for fun carry 41 per cent of everything the site says about half the catalogue.

The legal weight is correct, for what it is worth. The terms of service has to describe software that composes and submits a message to a stranger on your behalf: who the sender is, what happens if a site's form changes, what we do not promise, and the fact that it is beta. Those are real paragraphs that have to exist and they have to be specific. Auto-reply is the part of this product with consequences in somebody else's inbox, so it is the part that needs the most careful writing, and the legal pages are where careful writing goes.

The zero is the problem.

/help is the support page. Its FAQ answers six questions: whether you need to keep the app on screen, how often it checks, what sites it works with, whether you can monitor several at once, what to do if you lose your activation token, and whether it runs on Windows and Mac. Not one of them mentions auto-reply. A customer who has paid for the upgrade, shown it how to reply on a site, and then hit a site where it does not behave arrives at the help page and finds a page written for a product that only sends emails.

That gap has a shape I recognise. The help page was written when there was one product. Every page added since then was generated from typed content files, and the typed files all carry a required field about auto-reply, which is why 23 other pages mention it at all. The one page whose FAQ is a small hand-maintained array, untouched by any of that, is the one that is out of date, and it is the one a confused customer goes to first.

What I am changing

Two edits, in the order that a buyer encounters them.

The pricing card gets one line more than a price. Not a button, because the button cannot exist, but the sentence that is currently buried under the card moves up next to the figure, so the price and the way to buy it are read together rather than 200 pixels apart.

The help FAQ gets three new answers: what the upgrade costs and where you buy it, what happens on a site where it does not work, and what the app does if a reply fails to send. That array also feeds the page's FAQPage structured data, so those three answers are the ones most likely to be quoted back at somebody searching for the problem rather than browsing our site.

Neither of these is code. Both of them are the half of a product that nobody counts until they count it: 88 sentences about a feature, allocated by which file happened to be easiest to edit at the time.

You can see the two cards on /pricing, the animated version of what the upgrade does on the homepage, and the app itself on /download.