A URL architecture the product suite could grow into
Pendo was shipping product faster than its website could hold. The product surface of pendo.io had grown one page at a time, each launch bolting a new route onto a structure that was never designed to carry a suite. By the time I joined, the marketing site had become the slowest part of a product launch: the copy was ready, the design was ready, and the architecture was the thing everyone waited on.
Challenge
Pendo's product line was expanding faster than the website architecture that carried it. Every new product needed a page, every page needed a place in the information architecture, and the existing structure had no room left. The site could absorb another launch, but only by hand, and only with an engineer in the loop for each one.
Solution
I built the product surface of the main site as a component-driven system on a headless WordPress back end, with React and Gatsby rendering the front. Content lived in structured ACF and Gutenberg fields rather than in page markup, and product family sections were organized under a shared /{family}/{use-case}/ URL pattern, so a new page composed into an existing family instead of bolting on a one-off route. A new product page became a matter of composing existing components against a new content record.
Outcome
The architecture stopped being the constraint on launches. New product family pages assembled from components the team already had, in a URL structure that had room in it, without an engineer rebuilding the section each time.
The build
The first decision was to stop treating product pages as pages. A product page is a content type — it has a name, a positioning line, a set of capability blocks, proof, and a call to action — and it repeats. Once you model it that way, the work moves from producing markup to producing a schema and the components that render it. I built that model in headless WordPress, using ACF and Gutenberg so the content team edited structured fields rather than layouts, and rendered it through React on a Gatsby build.
The URL structure was the other half of the architecture. Product family sections were organized under a shared /{family}/{use-case}/ pattern rather than each page getting its own bespoke route, which sounds like a routing detail and is actually a product decision: it forced a family to express how its capabilities were organized, gave it room to accept new members, and made the shape of the navigation follow from the shape of the catalog rather than from whatever had been added most recently.
Decoupling the CMS from the front end is what made the rest safe. Content changes stopped touching render code, so the marketing and content teams could work on pages without a deploy on the critical path, and I could change how a component rendered everywhere at once without opening every page. That separation is the whole point of a headless stack, and it only pays off if the component library on the front end is disciplined enough to be the single place a pattern lives.
The thing I care about in this build is what it removed. Before, launching a product page meant a scoping conversation, an engineering ticket, and a bespoke template. After, it meant a content record and a composition of existing components — the same primitives, assembled differently. The platform absorbed the next launch instead of the team absorbing it.
This is the version of a marketing site I keep building toward: not a set of pages that happen to describe a product, but a system whose structure mirrors the product it sells, so that growth in one shows up as configuration in the other rather than as a rebuild.


Built with
- Headless WordPress
- ACF
- Gutenberg
- React
- Gatsby
- Next.js