Websites & Interfaces · Padel club network

Escaping website-builder lock-in: full export of a sports club's site into owned code

A club's entire public site lived inside a website builder it could only edit with a mouse. We exported all 22 pages into a self-owned static codebase the club controls line by line.

Client
Padel club network
Timeline
2026
Role
Export engineering against a read-only…
Status
Migrated, in maintenance
22
Pages exported
Full project export; 20 published routes including home, clubs, league, shop, blog and events
227
Assets mirrored
Every image, script and stylesheet downloaded and deduplicated into a flat, self-hosted folder (~48 MB)
48 lines
Modification layer
All post-export changes live in custom.css and custom.js — exported markup is left byte-comparable to the builder original
133 lines
Export and serving tooling
A 75-line stdlib-only Python exporter plus a 58-line clean-URL preview server — zero external dependencies to maintain

Context

The club network's public site — the surface where players discover courts, prices and the booking entry point — was built on a hosted website builder. The builder model is attractive at day one and expensive at day five hundred: the business does not own its markup, every change routes through a visual editor, and the sophistication ceiling is whatever the builder's blocks allow. For a growing club network that wanted booking integration, tone-of-voice fixes and eventually a video product woven into the same web presence, that ceiling had become the constraint.

The lock-in was concrete, not rhetorical. The builder's API is read-only: a program may fetch pages and assets but cannot write a single change back. Every modification, however mechanical, meant a human clicking through the editor — and any future migration would start from zero because the code, in any usable form, lived only inside the vendor's platform.

The club's requirement was ownership, not a redesign. The site's content and structure were fine; what was missing was the ability to treat the site as code — version it, diff it, script changes across it, host it anywhere, and connect it to the rest of the club's systems without asking a builder's permission.

The task

Extract the complete site from the builder into a static codebase the club owns outright: every page, every asset, byte-accurate, organized so that a developer — or a script — can work on it directly. The read-only API defined the method: this had to be an export pipeline, not a synchronization, and it had to be repeatable in case the builder site changed before cutover.

The export had to be immediately workable, not an archival dump. Builder-hosted sites rely on the vendor's routing, so the exported files needed a local server that reproduces production behavior — clean URLs like /about and /club/1 resolving to the right exported page — before any change could be previewed honestly.

Finally, the first round of real changes had to land on the exported code: wire the booking buttons to the club's CRM booking widget, remove navigation items that led nowhere useful, tone down over-promising copy, and improve the court photography — all without contaminating the exported markup, so the codebase would remain auditable against the builder original.

Approach

The exporter is a small, dependency-free Python script against the builder's official export API: it enumerates the project's pages, fetches each page's full export, and downloads every referenced asset exactly once into a flat site folder, deduplicating across pages. Keys and the project identifier come from the environment, not the source — the script is safe to keep in the repository and rerun. A machine-readable index of every page's route, title and published state is written alongside the files and becomes the routing table for everything downstream.

Serving is solved with an equally small preview server that maps clean URLs to exported files using that index, mirrors the production home and 404 behavior, and resolves the export's one structural quirk: pages under multi-segment routes reference assets relatively, which breaks under clean URLs, so the server falls back to flat basename resolution. The result is a local preview that behaves like the production site, not like a folder of saved pages.

The modification discipline is the decision that makes the export maintainable. Exported HTML is generated markup — verbose, machine-formatted, hostile to hand edits. Instead of editing it, every change is injected through two pluggable files, custom.css and custom.js, currently 48 lines in total. The exported pages stay byte-comparable to what the builder produced, a re-export cannot silently destroy hand work, and the entire delta of studio changes is readable in one place.

What changed on the site

The commercially important change was the booking path: booking buttons across the site were wired to the club's CRM booking widget, closing the gap between a visitor reading about courts and a visitor holding a reservation. Navigation was pruned of dead-end items, and copy was brought down from promotional overstatement to the calmer register the club wanted.

The court photography was enhanced with an image-editing model under a strict scene-preservation constraint — lighting and clarity improved, nothing added or staged — and every original was preserved in a backup folder before any file was touched. A separate delivery pipeline produced marketing collateral from the same material: banners and collages generated by scripted tooling, so future variants are a rerun rather than a design request.

Each change followed the same rule as the code: reversible, non-destructive, documented by construction. The club can see exactly what the studio altered, restore any original in seconds, and accept future rounds of changes without archaeology.

Result

The club now owns a complete, working copy of its site as code: 22 pages, 227 assets, a routing index, a preview server and a 48-line modification layer, all in one folder that runs with a single command. The builder remains the production host for the moment, but the dependency has been inverted — the builder can be left at any time, on the club's schedule, with zero content loss.

The export also unblocked the club's product roadmap. The same network's court-video platform (a separate engagement) needed the web presence to participate in the booking-to-video flow; that wiring is only possible on a site the club controls at code level. The exported codebase is where those integrations now land.

Business measurement stays on the owner's side: booking conversion through the newly wired widget and traffic retention after cutover belong to the club's analytics once the owned deployment carries production traffic. The engineering claim stands on its own — the lock-in is broken, and every future change to this site is a text edit, not a support ticket.

What we built

  • Read-only API exporter

    Dependency-free Python script: enumerates project pages, fetches full-page exports, downloads and deduplicates all 227 referenced assets into a flat site folder; credentials via environment, safely rerunnable.

  • Machine-readable page index

    Route, title and published state for all 22 pages written to _index.json during export — the single routing source for the preview server and future deploy tooling.

  • Clean-URL preview server

    Maps production-style routes (/about, /club/1) to exported files, mirrors home and 404 behavior, and resolves relative-asset breakage under multi-segment URLs via flat basename fallback.

  • Non-invasive modification layer

    All changes injected through custom.css and custom.js (48 lines total); exported markup stays byte-comparable to the builder original so re-exports can never destroy hand work.

  • Booking widget integration

    Booking buttons across the site wired to the club's CRM booking widget, connecting the marketing site to the reservation flow.

  • Scene-preserving photo enhancement

    Court photography improved with an image-editing model under a no-additions constraint; every original preserved in a backup folder before modification.

  • Scripted marketing collateral

    Banner and collage generation tooling in a delivery pipeline, producing club marketing assets from the enhanced photography as a repeatable script run.

Engineering challenges

The API allows reading, never writing

No change could ever be pushed back to the builder, so the architecture had to be a clean one-way export with a repeatable pipeline — not a sync. The exporter is idempotent and environment-configured, so a fresh export before cutover is one command, and the overlay pattern guarantees it cannot overwrite studio work.

Clean URLs broke exported asset paths

Exported pages reference assets relatively, which fails under multi-segment routes like /club/3 once served outside the builder. The preview server resolves any nested asset request to its flat basename in the export folder, reproducing production behavior without rewriting a single exported file.

Generated markup is unmaintainable by hand

Builder-generated HTML is verbose and machine-formatted; editing it directly would make every future re-export a merge conflict. The 48-line custom.css/custom.js overlay keeps the exported files pristine and concentrates the entire studio delta in two readable files.

Improving photos without falsifying them

A sports venue's photography is a factual claim about the premises. Enhancement was constrained to lighting and clarity with the scene preserved, and all originals were backed up before processing — the club can audit or revert any image.