Skip to content
Marketing & Lead-Generation Platform, Youth Sports

Academy Marketing Platform

An SEO-first marketing platform and full CMS for a UK children's football academy

Home page with hero photography, free-trial banner, and class search
The CMS-driven home page: academy branding over full-bleed class photography, a persistent free-trial banner, and the inline location and age search that feeds the class finder.

The academy runs weekly classes, holiday camps, birthday parties, and school programmes across a growing list of UK towns. Its entire acquisition channel is one search: "football classes near me." We delivered the three applications behind that funnel, the public website, the admin CMS, and the REST API, along with the AWS media pipeline, SEO architecture, and analytics wiring that connect them.

The project was as much a re-architecture as a build. The site began life as a client-rendered React single-page application: content arrived after page load, metadata lived in the browser, and every new town page was hand-built by a developer. We migrated it to server-rendered Next.js incrementally, using scripted, idempotent migrations so the live site kept shipping throughout the transition.

The result is a platform where a small academy team runs its full acquisition funnel, indexable town pages, class discovery, enquiry routing, and ad-spend attribution, without calling a developer for content changes.

Problem

A local-search business built on an unindexable site

Parents need to find a class close to home, for the right age group, and book a free trial with as little friction as possible. Meanwhile the academy's small team needs to update programmes, venues, prices, testimonials, and blog content across multiple towns without developer involvement.

The existing client-rendered architecture worked against both goals. Search engines saw an empty shell rather than real content, a serious limitation when the business model depends on ranking for "football classes in {town}", and each town landing page was hardcoded, making geographic expansion a development task instead of a content task.

Find a Class page with location and age search form
The class finder geocodes an address and returns classes within a 10 km radius, filtered by age and sorted by driving distance.
Approach

Incremental re-architecture, with SEO as a product feature

We migrated the public site to Next.js server rendering without a big-bang rewrite. An idempotent migration script converted image tags to optimized image components, replaced browser-side SEO tooling with Next.js metadata, and centralized the shared layout, while legacy routes stayed mounted through a catch-all until each page was migrated.

We made locations data, not code. A migration consolidated per-town collections and hardcoded pages into a single locations collection with admin CRUD, so the academy opens a page for a new town from the CMS. A URL rewrite serves each page at a keyword-rich address like /football-classes-in-barnet while one implementation renders them all.

We treated SEO and measurement as product features: structured data on every page type, canonical URLs with slug normalization and redirects, a database-driven sitemap, per-page titles and descriptions editable from the CMS, and named conversion events wired for Google Ads import, including the outbound click that hands a parent off to the booking platform.

CMS-driven town landing page at a keyword-rich URL
A town landing page served at /football-classes-in-barnet, one dynamic template renders every location the academy opens from the CMS.
Solution

From "classes near me" to a booked free trial

A parent lands on the home page or a town landing page, opens the class finder, and types an address or shares their location. The finder geocodes the input through Google Maps, queries the API for classes within a 10 km radius filtered by the child's age, computes driving distance to each venue with a straight-line fallback, and lists classes sorted by miles. Radius search runs on a MongoDB 2dsphere geospatial index, so proximity filtering happens in the database rather than in application code.

The admin panel gives the academy control over effectively every word and image on the site: home page sections, programmes, holiday camps, birthday parties, school and nursery programmes, franchise recruitment, testimonials, FAQs, a blog with slug management, a hall of fame for player success stories, coupons, and the location pages themselves. A dedicated Page SEO module sets title, description, keywords, and social-share image per URL, merged over per-entity defaults at render time.

Around the core funnel we built the operational machinery of a production site: enquiry forms delivering templated emails per enquiry type, an S3/CloudFront media pipeline with presigned browser-direct video uploads and FFmpeg thumbnails, a bulk WebP conversion pipeline that rewrites stored URLs across the database with dry-run and restore paths, and scheduled jobs for coupon and membership expiry.

Key features
  • Geolocation class finder

    Address geocoding, 10 km radius search on a MongoDB geospatial index, age filtering, and results sorted by driving distance, answering the core customer question in one flow.

  • CMS-managed local-SEO landing pages

    Town pages served at keyword-rich URLs like /football-classes-in-barnet, opened from the CMS without developer involvement, with structured data, canonical redirects, and a database-driven sitemap.

  • Full-site content management

    Rich-text editing, drag-and-drop ordering, and validated forms across programmes, camps, parties, schools, franchise recruitment, blog, testimonials, FAQs, success stories, and coupons.

  • Per-page SEO control

    A dedicated CMS module for titles, descriptions, keywords, and social-share images per URL, merged into Next.js generateMetadata with a secured revalidation endpoint to refresh cached pages.

  • Conversion tracking across a third-party handoff

    GA4 events wired for Google Ads import capture the outbound booking click with a callback-and-timeout pattern, so the event is recorded before navigation but a blocked analytics script never stops a parent from booking.

  • Enquiry and lead capture

    Contact, franchise, birthday-party, school-programme, and recruitment forms post to dedicated endpoints delivering templated HTML emails, giving each enquiry type its own routing.

Holiday camp page with location tabs, camp description, and discount code
A holiday camp page with real CMS content: location tabs, the camp description for ages 5 to 13, and an early-bird discount code with its expiry date.
Hall of Fame gallery of academy player signings
The Hall of Fame: a CMS-managed gallery of academy alumni photographed at professional club signings and trophy presentations.
Blog listing page with category filter and news cards
The CMS-managed blog listing with category filtering and slug management, feeding the site's content and SEO footprint.
Under the hood
  1. 01

    Server-rendered Next.js public site

    Next.js App Router with server-side CMS fetches so copy ships in the initial HTML, JSON-LD for Organization, LocalBusiness, and Breadcrumb schemas, dynamic sitemap and robots, and Vercel deployment pinned to the London region with hardened security headers.

  2. 02

    Three-application architecture

    A React and Material UI admin panel with Redux Toolkit, Formik validation, and drag-and-drop ordering; an Express API with JWT-authenticated route groups and roughly 90 admin endpoints; and MongoDB with around 50 Mongoose collections.

  3. 03

    AWS media pipeline

    S3 and CloudFront storage, presigned URLs for browser-direct 100 MB video uploads that bypass the API server, FFmpeg video thumbnails, and Sharp-based bulk WebP conversion that rewrites every stored image URL, runnable as a dry-run CLI or an authenticated admin endpoint.

  4. 04

    Repeatable migration tooling

    Scripted migrations for the CRA-to-Next.js transition, legacy location consolidation, blog slug changes, and image URL rewrites, all supporting dry runs, reflecting the caution of operating against live production data.

  5. 05

    Quality and measurement wiring

    GA4, Meta Pixel, and optional GTM loaded from server-read configuration with route-change tracking, plus Lighthouse CI asserting 90+ targets for performance, accessibility, best practices, and SEO across five key URLs.

Outcome
  • Every page, including town-level landing pages, is server-rendered, indexable, structured-data-annotated, and editable by non-developers.
  • Opening a page for a new town became a content task in the CMS rather than a development task.
  • The academy can attribute ad spend to trial bookings despite bookings completing on a third-party platform.
  • The site was re-architected from a client-rendered SPA to server-rendered Next.js incrementally, while it kept running in production.
  • The full historical media library was converted to WebP with database URL rewriting, safely enough to run against live data.

Next project

Consulting Site & EstimatorConstruction Consulting