Ampy: one town site in April 2025, then a network, then the flagship
One client since April 2025, seven town sites with six of them live, then the national flagship, and the running of all of it ever since.
One town site in April 2025, and everything that grew out of it
The engagement began in April 2025 with one site, elektriker-solna.com, for a single municipality in greater Stockholm. It was meant to be one site, and it became the template for everything after it.
What worked in Solna was rebuilt for Täby, then for the other towns, until seven sites existed and six of them were live. The seventh is built and has not launched yet. All of them sit under the Ampy umbrella, which owns and operates the lot.
Ampy’s own flagship, ampy.se, is the newest part of this relationship rather than the beginning of it. Planning began in October 2025 and the site went live in February 2026. That is the date of one project inside a longer engagement, and on its own it dates the whole relationship from the flagship instead of from its start.
Everything described below is still in service, and the person who built it is still the person running it.
One engine, repainted for each town
Somebody standing in a dark kitchen at nine in the evening with a tripped consumer unit does not search for a regional electrical group. They search for an electrician in the town they are standing in, and then they spend a few seconds scanning the results for anything that says this firm is actually here: a local number, an address they recognise, reviews from streets nearby. One national site can be convincingly local for one town. It struggles to be convincingly local for seven at once, because it is not.
So the network is separate sites, one per municipality, each presenting itself as the local firm with its heart in that town: its own domain and brand, its own address and phone, its own Google Business profile, and content written around the town rather than around the group behind it. Seven have been built and six of them are live.
The engineering is the opposite of the presentation. All seven are the same engine, repainted. Each site is a WordPress build on Elementor Pro over a lightweight base theme, where a single master template defines the structure and the design system and each town is a repaint with local content. Every site is a complete local-SEO machine rather than a homepage: a town hub with neighbourhood sub-area pages beneath it, one per named district worth having, which catch electrician-near-me searches below the municipality level where the intent is sharpest and the competition thinnest, a full set of service pages, a localised blog, local trust furniture (a Google Maps embed, local reviews, certification badges, an FAQ and a callback prompt), and local-business schema so each site reads as a distinct local entity.
A new market is launched by cloning the working engine and localising it: town content, address and phone, district pages, local schema and a Google profile. The hard engineering is done once, so entering a new town is a content and configuration exercise rather than a build. Each town captures leads two ways, a quote form and a callback prompt.
Isolated per town, managed as one fleet
The network is a multi-tenant deployment: seven fully independent WordPress sites, each on its own domain in its own isolated environment, running side by side on shared, centrally managed and hardened infrastructure. Isolation means a problem on one site never touches another. Central management means the whole fleet is maintained, updated and secured as one operation. Each site runs the same stack, Cloudflare at the edge, an in-memory full-page cache, Redis for object caching, and a tuned web server with PHP and MariaDB, so a typical visitor is served a fully cached page with effectively no database work.
The data follows the same shape. MariaDB per site holds isolated content, pages and leads; template data and custom fields carry the shared architecture, localised; structured schema per site gives each town its own name, address and phone; and each town runs its own form and callback intake. The pattern worth naming is structural reuse with data isolation: every site shares one content model and one local-business schema shape, and each owns its town pages, reviews and lead pipeline. The network compounds into broad local-search coverage while each town stays clean and self-contained.
One optimisation recipe is applied identically across the fleet, in-memory caching, CSS and JavaScript aggregation, font and icon optimisation and modern image formats, so tuning it once improves every site. Cache purging, updates, security and backups run across the whole fleet as one managed operation. Tuning stops being seven jobs: a change is tested on one site and shipped to the rest, and a regression is one thing to find rather than seven.
Putting a national installer online
The site is the flagship of Ampy, a Swedish electrical services group that runs on in-house tooling paired with certified, employed electricians rather than subcontracted middlemen. It is a full electrical-services business. Alongside battery storage and EV charging, it offers a deep range of home and commercial electrical work, from installations, consumer-unit replacements, fault-finding and load balancing to lighting, kitchens, bathrooms, floor heating, smart-home and emergency call-out.
It serves homes, businesses and establishments alike: villas and apartments, companies and offices, restaurants and hotels, housing associations (BRF) and municipalities. Every offering is tied to a Swedish tax incentive the company administers for the customer: 50% Grön Teknik on batteries and chargers, 30% ROT on labour.
The site was built to present that whole range clearly and turn it into booked work through a solid lead pipeline. Trust markers are part of that, and they are the part that quietly costs you the page. Review scores, certifications and completed-work counts all live with somebody else, and the default way to show them is the vendor’s embed: a third-party script renders your social proof and gets to decide when your page paints. Here the reviews are held locally instead, as a custom post type with the rating, the author and the date as real fields, so they render server side with everything around them. There are still third-party tags on the page, analytics and the like, and they take their own tuning to keep out of the way. But no review widget sits between a visitor and the first paint.
Built with Bricks, powered by SCF
The site is a WordPress build assembled with Bricks, a developer-grade builder chosen because it produces lean, controllable markup instead of the bloat of mainstream page builders. The battery and charger ranges are not a webshop: there is no cart, no checkout, no payment. Each product, like the Dyness Stack100, the SAJ HS3 or the Zaptec Go, is a custom post type with specification-rich fields modelled in SCF (capacity, number of phases, IP rating, warranty and more), presented for comparison and leading straight to a tailored quote. SeoPress handles sitemaps and metadata, but structured data is owned by a single custom schema-generator class, so a page has exactly one authoritative source of JSON-LD instead of two or three plugins each publishing their own version of the truth. Getting there was less tidy than that sentence makes it sound. The obvious fix, unhooking the SEO plugin’s schema output by the class name it had always registered under, ran cleanly and did absolutely nothing: the plugin had moved its emitters into a new namespace, so the removal matched nothing and failed without complaint. The page carried on shipping duplicate ld+json blocks and no log anywhere mentioned it. Schema breaks quietly, which is why the check that counts is fetching the rendered page and reading what actually came back, not trusting that the code you wrote to remove something ran. A deep library of standards-aware Swedish articles, each attributed to a named author, editor and fact-checker for genuine E-E-A-T authority, plus a network of location pages under a single “we are where you are” banner, builds local-SEO authority and funnels traffic toward the quote flow.
A heavy, dynamic site that loads like a static one
The platform runs on dedicated, self-managed infrastructure, engineered around one goal: serve a heavy, dynamic, content-rich site as if it were a static page. The defining feature is a multi-layer cache where each layer absorbs a different load: Cloudflare at the edge for CDN, WAF and DDoS protection, Varnish as a full-page cache serving HTML in microseconds, Redis as an in-memory object cache, and a page-cache plugin for application-level optimisation. Underneath sit a tuned web server, a modern PHP runtime and MariaDB. Repeat visits are served from cache almost instantly, while the database and PHP layer are reserved for the work that genuinely needs them: the forms and the calculators.
A suite of custom calculators and a self-orchestrating cache
The lead engine is not one tool but a suite of bespoke calculators that work as lead magnets on a shared platform. Each one lets a visitor model a real decision and hands back a concrete answer in exchange for their details. A battery-storage calculator sizes a system and computes the economics including the Grön Teknik deduction and the payback period; an EV-charging savings calculator does the same for wallboxes; a consumer-unit checker assesses a property’s electrical panel; an authorisation checker maps twenty-six electrical jobs to whether an authorised electrician is legally required, gated so a certified electrician signs off the matrix before launch; and an LED-lighting calculator models a lighting upgrade. They all work from live product data parsed straight from the studio’s own spreadsheets. Each is genuine custom application logic with its own backend and REST API, each renders a crawlable server-side fallback so the tools stay indexable, and each captures a qualified, pre-contextualised lead with instant webhook or email notification, so a senior electrician can call back fast.
Because the stack runs four cache layers, a naive content update could serve stale pages. So the platform carries a custom cache manager that cascades an intelligent purge across WordPress, the page cache, Varnish, Redis and Cloudflare in the right order, on every save and on a schedule, so editors always see their changes live. Every quote form and every calculator feeds a single structured intake, captured as owned first-party data ready for sales and remarketing.
Structured products and an owned lead pipeline
The site is a structured data system as much as a website, and it does it without WooCommerce. MariaDB holds content and configuration; the products live as custom post types with SCF-modelled specification fields, structuring batteries, chargers, location pages, lead magnets and campaigns; Redis caches query results. The two assets that matter most are the structured product catalogue, a specification-rich database that powers both the product pages and comparison content, and the lead pipeline, every quote and calculator session captured as owned, first-party data ready to feed sales and remarketing. Each calculator also encodes the client’s own sizing and payback logic as reusable business data, not just a one-off interface.
What it measures on desktop, and how it was measured
A dynamic, content-heavy site built with a visual builder, carrying a product catalogue, a suite of calculators and a large local-SEO network, is exactly the combination that usually produces a slow page. The multi-layer cache is the structural answer: most requests are served as cached HTML without waking PHP or the database at all, so both are left for the things that genuinely need them, the forms and the calculators. That is the architecture, and here is what it measures.
On the flagship, desktop Lighthouse runs 98 to 99. That figure comes from Cloudflare Observatory, which runs Lighthouse from European datacentres against the zone rather than from a laptop on a domestic line: eight runs across Hamina, Frankfurt and London, on 2 and 19 August 2026. Largest Contentful Paint on desktop lands between 756 ms and 1,030 ms across those runs, so the main image is on screen in about a second. Cumulative Layout Shift is 0.00 in every run, meaning nothing slides out from under a thumb that is already moving towards a button. Server response measured from Europe is 19 to 41 ms. A separate set of five desktop PageSpeed Insights runs, taken against a cache verified warm at 832 preloaded pages, puts the homepage at a median of 98 with First Contentful Paint at 361 ms and 11 ms of spread across the set, and the homepage HTML at 330 KB, arriving as 76 KB over the wire.
Across the town network the recipe is the same and so are the results. Largest Contentful Paint came in under 1.2 seconds on every live site, and the worst Cumulative Layout Shift anywhere on the network was 0.04, measured on 28 July 2026 across the six live sites, two runs each.
Two things about how those numbers were taken matter more than the numbers. PageSpeed Insights caches its results, and four back-to-back calls once came back byte-identical down to the millisecond. That looks like beautiful stability and is actually one sample printed four times. Zero spread is the tell, which is why runs are spaced minutes apart now and the raw set is kept. The second is that a comment in a codebase asserting a past measurement is not evidence. One in this platform’s preload snippet claimed a figure that could not be reproduced in four attempts, and it cost days spent measuring the wrong layer.
These are desktop figures and they are labelled that way deliberately.
The failures that do not announce themselves
Building the platform took the first few months. Running it is the part that does not stop, and the failures that cost the most in production are the ones that never raise a hand.
The cache purge is the best example. Four cache layers sit in front of the site, so a content update that does not purge cleanly leaves visitors on a stale page, which is why there is a custom manager that cascades a purge across WordPress, the page cache, Varnish, Redis and Cloudflare in the right order. It reported success every single time. It was calling a method the plugin no longer exposed, swallowing the failure and returning true anyway, so every “cache cleared” in the log was untrue. Separately, and at the same time, the cache directory had drifted to root ownership, so the preloader ran for seven and a half minutes and wrote zero pages, with no error in any log, while real visitors were served uncached PHP. A cache operation that cannot fail loudly will eventually fail quietly, and you will spend a week measuring the wrong thing. Both of those now fail visibly, and a purge is confirmed by fetching a page and looking at what came back rather than by trusting a return value.
WordPress cron was the same class of problem wearing different clothes. WP-Cron is not cron. It only fires when somebody loads a page, so on a site with quiet hours the scheduled work simply does not run, however healthy the settings screen looks. Maintenance now runs from real system cron, under a lock, on a staggered minute, so it happens whether or not anyone is on the site that night.
Not every fix earned its keep. The testimonials slider was rendering ten SVG nodes for each star rating, so it was rebuilt to draw all five stars as one path with an offset applied per star, two nodes instead of ten, and the loop mode was cloning slides without a cap. The DOM got measurably smaller. Largest Contentful Paint did not move at all. That belongs in the write-up too, because a change that is obviously correct on paper still has to be measured, and this one bought maintainability rather than speed.
The technical detail, written up:
- When your WordPress database buckles under load
- Running a multi-region WordPress site from one VPS
- Programmatic location pages that scale without becoming spam
- Schema that inherits itself across a large site
- Build vs buy, and how to replace a WordPress plugin without downtime
- How to make a heavy WordPress site load like it is static
See it in production.
By the numbers.
Guides from this engagement.
The technical detail behind this work, written up in full.
Start with a conversation.
A short conversation first, to work out which of the two routes you are on and whether this is a problem I can solve. The audit is the paid step that follows, and what it produces is yours whether or not anything comes after it.
Twenty-five minutes on Google Meet, and a straight answer either way.
- 01
You describe what you are running, in whatever words you use for it internally.
- 02
You get a straight answer on whether the audit is worth doing at all, including when it is not.