Programmatic SEO has an obvious failure mode: generate a page per city, fill the gaps with a template, and ship 500 pages that are the same page. Beamo Sites generates 518 and each one says something true about the place it names.
28 July 2026 · 3 min read · Beamo Sites
A web design agency competes locally. Someone searching for a designer types their own city into the query, and the results are dominated by pages that name that city. You can write those pages by hand for the five cities you care about, or you can generate them for every city you could plausibly serve.
Beamo Sites generates 518: 467 cities across the United States and Canada, plus 51 state and regional hubs. Each has its own URL, its own title, its own headline, its own copy and its own structured data, all built at compile time from a single data file. The sitemap comes to over 550 URLs.
The tempting way to fill 467 pages is a template with a slot in it. Take a sentence like "our designers know the character of {city}, from {landmark} to {neighborhood}", populate it from a list, and you have plausible looking local copy in an afternoon.
It is also worthless, and worse than worthless if the generator hallucinates. A page that names a landmark that is not in that city, or describes a neighborhood that does not exist, is a page that tells any reader who lives there that nobody involved has been paying attention. Search engines have spent years getting better at recognising exactly this pattern, and the reader recognises it instantly.
So every city blurb on Beamo Sites is written by hand from real local signals, and nothing invents a landmark. That is a much slower way to build 467 pages. It is the only way the pages are worth having.
Unique copy makes a page worth indexing. Structure is what gets it found. The pages are arranged in a three tier silo: a national hub links to state and regional hubs, and those link down to their cities. Every page has a real path back up.
This matters because 467 orphan pages are 467 pages a crawler has to be told about individually and has no reason to trust. The same 467 arranged under 51 hubs are a site, and the hubs accumulate the internal links that make the cities discoverable.
The static pages cover the visitor who arrives from a search for their own city. A Cloudflare edge function covers the one who does not: it reads the visitor's metro from edge geo and injects their own city into the headline on the home page. Same page, and it greets a Nashville visitor and a Toronto visitor differently.
The other live piece is pricing. A self optimizing experiment runs an epsilon greedy bandit across price points and shifts traffic toward whichever converts best. This is a genuinely better fit than a fixed split A/B test for a site with this traffic shape: a bandit spends most of its traffic on the current best option while continuing to sample the others, so the cost of running the experiment is much lower than splitting evenly for weeks.
The contact form is deliberately boring by comparison. Validate the input, catch bots with a honeypot, store the lead, email the team. The clever parts of a marketing site should be the parts that find people, not the part that has one job.
The whole thing is localized into 8 languages with localized URL prefixes and hreflang, and the non English pages are prerendered like the English ones. A translated page that only exists once JavaScript runs is a page some crawlers will treat as empty, which turns a real localization effort into a duplicate of the English site.
It ships as a React single page app prerendered to static HTML on Cloudflare Pages, with route prefetching so navigating between the hubs and cities feels immediate. The generation happens at build time, so serving 518 pages costs the same as serving one.