I Built an App and Forgot to Make It Findable
Session one of building GoPuppy's website in public: the stack decision, the content architecture, and how long this will really take.
I spent months building an iOS app and roughly twenty minutes thinking about how anyone would ever find it.
That’s the honest summary. GoPuppy is live on the App Store. It has a real curriculum, a working subscription, analytics, crash reporting, seven languages. What it did not have, until today, was a single page on the internet that explains what it is to someone who has never heard of it.
This is session one of fixing that in public.
The stack decision took ten minutes and I want to explain why
Astro. Static output. Deployed to Cloudflare Pages. No Next.js, no CMS, no React.
The reasoning is boring and I think that’s the point: nothing on this website is dynamic. It’s text, images and links. Every piece of technology that adds a runtime to that is a cost with no matching benefit: slower first paint, more JavaScript, more things to keep updated, and a worse Core Web Vitals profile on exactly the mobile connections my audience is using.
Astro ships zero JavaScript by default. The pages that need a little (a consent banner, an analytics listener) get a little. Everything else is HTML that a CDN can hand over in one round trip.
The temptation was real, though. I know Next. I’d have been productive faster. Picking the simpler tool when you’re already fluent in the complicated one is a decision you have to make deliberately, because nothing in the moment pushes you toward it.
The architectural decision that actually matters
Here’s the one I expect to matter most in six months, and it has nothing to do with frameworks.
The site has two content sections and they are deliberately separate:
/blog/: dog training. Potty training, biting, crate training, leash work./build/: this one. Notes about building and marketing the app.
The obvious thing would be one blog with categories. I didn’t do that, because search engines assess topical authority per section, and a feed that alternates between “how to stop puppy biting” and “why I ditched Next.js” is convincingly about neither.
I want the dog-training section of this domain to look, to a crawler, like it is about exactly one thing. The build log is for a different audience, you, and it gets its own home, its own lower sitemap priority, and no claim on the topical signal.
The content model
Five pillar guides, each surrounded by narrower articles that link back to it, and which the pillar links out to. Hub and spoke.
What makes this version different from most content marketing is that the topics aren’t chosen from a keyword tool in isolation. They’re chosen where high-intent search queries overlap with lessons the app already teaches. The potty training guide exists because the app has a potty training curriculum. That means the call to action at the bottom of the article is honest: here’s the principle, and here’s the same thing as a dated plan with reminders.
An article that has to invent a reason to mention the product reads like it. One that doesn’t, doesn’t.
The measurement layer
One question matters: which page sends someone to the App Store?
Everything is built around answering it.
GA4 with Consent Mode v2, so European traffic is both lawful and actually measurable. A single app_store_click event carrying which page and which button. Cloudflare Web Analytics as a cookieless backup, because a meaningful share of visitors will decline cookies and I’d rather know my real traffic than my consented traffic.
And the piece I’m most pleased with, because it’s free and almost nobody bothers: every App Store link on this site carries a ct campaign token. Those show up in App Store Connect’s campaign breakdown, which means an install can be traced back to the article that caused it, without an attribution SDK, without a vendor, and without adding a line of code to the app.
The uncomfortable part
A brand new domain takes three to six months to rank for anything worth ranking for. I am starting work this week that will show me approximately nothing for a quarter.
I know the failure mode here, because it’s the same one that killed my ad spend: check the numbers daily, see nothing, conclude it doesn’t work, stop. So I’m writing down the target in advance, publicly, where I can’t quietly move it.
Month one is not measured in revenue. It’s measured in pages indexed and first impressions in Search Console. That’s it. If I hit those, the machine is working, regardless of what the bank says.
What’s next
Four more sessions this week: the technical SEO layer, a content sprint, a free tool worth linking to, and then measurement and hardening.
I’ll post the numbers, including the ones that don’t flatter me.