Skip to content
+40 754.636.306 Start a project RO
All Case Studies
Web Development Conversion Astro

Every visitor was paid for. So we rebuilt the site around not wasting them.

Piscine Pro Design SRL / Pools, saunas & spas, Bucharest | Astro 6 + hand-written CSS + PHP

A pool, sauna and spa builder in Bucharest, moved off WordPress onto a static Astro site. 1.1 second LCP on real mobile devices, zero layout shift, and a two-step form converting at 34%.

34%
Form conversion
Of paid search clicks
1.1s
LCP, real mobile users
CrUX field data
0
Layout shift
Exactly zero CLS
29 KB
Total JavaScript
Four files, no framework

Brand direction · UX and UI · front-end engineering · conversion architecture · technical SEO · analytics · deployment

At a Glance

Client
Piscine Pro Design SRL. Pool, sauna and spa construction, Bucharest and Ilfov.
The problem
A WordPress site absorbing paid search traffic with no persistent mobile call to action, no WhatsApp presence in a market where WhatsApp is the default channel, trust signals buried on a single page, and a lead form built for browsers rather than buyers.
What we did
A full rebuild rather than an iteration.
The headline
34% of paid search clicks now submit the lead form, against a 6.6% sector average, which took cost per lead from 215 lei to 35 lei.
Built with
Astro 6, hand-written CSS, no UI framework, deployed to the client's existing shared hosting.
Next step
Book a 30-minute conversion audit of your current site. Tell us your traffic source and we will tell you where it leaks.

The Brief: The Site Is the Last Step of a Purchase Already Paid For

This business runs on paid search. Somebody types "constructor piscine bucurești", clicks an ad, and that click has a price attached. Every second of load time and every unnecessary form field is spending money that has already been spent.

That reframes the job. The site is not a brochure. It is the last step of a purchase the client has already paid to start.

Three things were working against it:

  • The old site leaked mobile visitors. No persistent call to action, no WhatsApp, and a contact form asking cold traffic for a name, phone, email, service and a written message before it would accept a lead.
  • The URL structure had drifted. Years of WordPress had produced overlapping service pages: /servicii/piscine-private, /servicii/piscine-publice, /servicii/constructii-piscine, /servicii/saune, /servicii/spa-jacuzzi and more. Consolidating them was necessary, and losing their ranking history was not an option.
  • It looked like a contractor. Which is accurate, and commercially wrong. Nobody buys a pool because they need a hole in the ground. They buy the Saturday afternoon it creates.

Brand Direction: A Boutique Resort That Happens to Build Pools

That sentence is the idea the whole project resolves from. Three attributes: relaxed, inviting, assured. The tone is warm confidence rather than urgency. Not "call now, limited offer". Closer to "we have done this before, relax, we will handle it".

We wrote down what we were refusing before we designed anything:

  • No stock photography. The client had eight years of real project photos.
  • No cold corporate minimalism. It reads as competent and expensive, which is half right and half fatal.
  • No aggressive calls to action. This is a considered purchase with a long deliberation window. Pressure reads as desperation.

Palette. Deep navy through an eleven step scale, from #0a1628 to #e8f2ff, with a warm gold accent at #d4a843. The decision that mattered most was the smallest: the neutral ramp was rebuilt warm, #faf8f6 through #1c1917, instead of the cool grays most systems default to. Cool grays make photography look clinical. Warm neutrals make the same photograph look like a holiday.

Type. DM Serif Display for display, Inter Variable for body. Inter on its own read too clinical for a brand selling relaxation, so the serif carries the warmth and the sans carries the reading load.

Layout. Editorial rather than gridded. The photography is the product, so the interface frames it instead of chopping it into cards.

Language. Romanian throughout, correct diacritics, with every string in a single dictionary so tone stays consistent across 38 pages.

Conversion Architecture: Every Decision Started as a Hypothesis

Not as a preference. Each of the five decisions below was made against a number we expected to move, and each is written here with the reasoning that produced it. The same discipline drives our landing page optimization work on campaigns we did not build.

The form asks for two things

Step one takes a name, a phone number and consent. Email and message move to step two and are optional. Multi-step forms convert around 86% better than single-step equivalents, 13.85% against 4.53% in the research we based this on, and three-field forms outperform five-field by around 27%. For cold traffic, every field is a chance to reconsider.

There is always a way to call

A bottom bar appears after 300px of scroll on mobile, carrying WhatsApp and Call, at 48px minimum tap targets, hidden entirely above 1024px. Desktop gets a floating WhatsApp button instead.

The hero stopped selling the portfolio

Its secondary button used to say "view portfolio". It now shows the phone number. On bought traffic, every call to action that is not a conversion is dilution.

Trust is distributed, not centralized

Five proof points, contract guarantee, 24 hour response, 150+ projects, 8+ years, free quote, in a component with full and compact variants, placed in the hero, in CTA banners and on the thank-you page. Present at the moment of decision, not filed on an about page.

The thank-you page is a real page

It greets the customer by name, gives them a six character reference they can quote on the phone, and reinforces the decision instead of dead-ending it.

Then the parts nobody sees. A honeypot field that returns a fake success, so bots cannot detect they have been filtered. Per-IP rate limiting at five submissions an hour. And one detail worth keeping: inactive form steps are disabled with the inert attribute rather than disabled, because disabled inputs are silently dropped from FormData and would have quietly destroyed every step-one answer. That bug does not throw an error. It just loses leads.

What the rebuild did to paid search

1 June – 20 July 2026 · 412 clicks · 140 leads · unchanged ad spend

Form conversion rate

Form conversion rate compared with the paid search sector average Piscine Design landing pages convert 34 percent of paid search clicks. The paid search sector average is 6.6 percent. Piscine Design landing pages 34% Paid search sector average 6.6%

Cost per lead

Cost per lead before and after the rebuild Cost per lead fell from 215 lei before the rebuild to 35 lei after it, on unchanged ad spend. Before rebuild 215 lei After rebuild 35 lei

Phone and WhatsApp conversions are counted separately and are not included in the 34%. Nothing about the campaigns changed. The change is entirely on the page.

Measurement: The Invisible Half That Changes What the Client Can Decide

Most of this is invisible, and it is the part that determines whether the ad account learns anything.

Enhanced conversions for leads. First-party email and phone are passed to Google at the conversion event, so the platform can match a lead back to the click that produced it with far better accuracy.

Click IDs survive the journey. gclid, gbraid and wbraid are captured on whichever page the visitor lands on and stored for 90 days, matching Google's attribution window, then attached to whichever form is eventually submitted. Without this, a visitor who arrives from an ad, reads six pages and converts on the seventh is recorded as unattributed traffic. The campaign that paid for them gets no credit, and the client optimizes against a lie.

Campaign data reaches the inbox. Five UTM parameters ride along into hidden form fields, so the client can see which campaign produced which lead, not just how many arrived.

Personal data does not linger. Lead details pass to the thank-you page in the URL, fire the conversion, then get erased from the address bar with history.replaceState(). Nothing survives in browser history or in a link someone pastes into a chat.

Tag Manager loads late. It waits for the first real interaction, an idle moment or a four second timeout, whichever comes first. Loading it eagerly costs 200 to 400 milliseconds of blocking time on mobile, and conversions fire long after the user has started interacting, so nothing is lost by waiting.

Engineering: Four JavaScript Files, 29 KB, No Framework

No React, no Vue, no hydration layer. The entire site ships four JavaScript files totalling around 29 KB, and 7.3 KB of that is a WebGL effect most visitors never download.

JavaScript shipped to the browser

Compressed transfer size, first page view

JavaScript payload compared with a median WordPress page Piscine Design ships 29 kilobytes of JavaScript. A median WordPress page ships roughly 640 kilobytes. Piscine Design 29 KB Median WordPress page ~640 KB

Roughly a twentieth of what a typical WordPress build ships. On a mid-range Android phone, JavaScript is not just download time: it is parse time and main-thread time, both of which land squarely on the moment the visitor is deciding whether to stay.

The stylesheet decision, with the number attached. Astro's default behaviour left two stylesheets, 3.6 KB and 9.2 KB, as render-blocking external requests, costing roughly 700 milliseconds. Forcing every page to inline its CSS trades about 50 KB of extra HTML for the removal of those round trips. On a 4G connection that is unambiguously the right trade, and it is visible in the field data below.

Fonts, chosen for what they cost. Variable Inter covers every weight in about 30 KB per subset, against roughly 1.1 MB for the equivalent static files, and only Latin and Latin-Extended are preloaded because that is all Romanian needs. DM Serif Display bypasses its packaged stylesheet, which would have forced font-display: swap and triggered a late layout change that browsers re-count as the largest contentful paint. It uses font-display: optional with a 100 millisecond window instead. If the font is not there in time, the system serif renders and nothing moves.

That decision has a measurable payoff: cumulative layout shift of exactly zero.

Effects that know when to stay away. A WebGL water surface animates the hero, but only after checking four conditions: the visitor has not requested reduced motion, the viewport is at least 768px, data saver is off, and the connection is above 1.5 Mbps. Only then is the code fetched, and only when the canvas scrolls into view. Scroll-driven animation uses the native CSS timeline where the browser supports it, with a JavaScript fallback underneath.

Media. 155 responsive WebP variants generated at build time, and a separate lighter encode of the hero video for mobile, 471 KB against 687 KB.

Search: One Connected Graph, Not Scattered Fragments

Every page emits a single JSON-LD @graph with stable identifiers for the business, the site and the logo, so search engines resolve one entity rather than reassembling several. The business is typed as both GeneralContractor and HomeAndConstructionBusiness. The reasoning behind that approach is the same one we documented in our llms.txt and AI search visibility case study.

The catalogue maintains itself. Service area covers 13 named localities and the offer list is generated from the service catalogue, so adding a service updates the structured data without anyone remembering to.

One address per page. Canonical URLs are normalized once and that single source feeds the sitemap, the internal links and the canonical tag, so there is no disagreement between them.

The migration was double insured. Legacy URLs are redirected both at the framework level and at the server level, with anchored patterns so /hidroizolatii cannot accidentally swallow /hidroizolatii-extra. Two independent layers, because a redirect that silently stops working is a slow leak nobody notices.

Accessibility and Security

WCAG AA contrast targets, a skip link, and visible gold focus outlines rather than suppressed defaults.

Reduced motion is respected across 17 files, and respected properly: the scroll reveal observer is never registered rather than merely being hidden. There is a real print stylesheet that strips the conversion furniture and expands link URLs.

On the server: a full content security policy, HSTS, a locked down permissions policy, server identification headers stripped, mail credentials at owner-only permissions, error logs unreachable from the web, and user-facing errors that never leak anything about the mail transport.

Shipping: Standard Shared Hosting, No New Dependencies

Deployed to standard shared cPanel hosting. The site is fully static apart from a single PHP endpoint for the form, with the mail library vendored into the build, so no Node runtime, no Composer and no new operational dependency. The client keeps the hosting bill they already had.

Caching runs in tiers: five minutes on HTML so a deploy propagates quickly, a week on CSS and JavaScript, a month on images and fonts, a year and immutable on fingerprinted assets and video.

Handover includes a written deployment runbook with a post-deploy checklist, including explicit checks that certain URLs must return 403.

Results, Verified in the Field

Chrome User Experience Report, 28 day window, real visitors on real devices and connections, not a lab simulation.

Core Web Vitals against Google's "good" thresholds

Mobile · CrUX 28-day window · bar length = share of the budget used

Core Web Vitals mobile field data against Google's good thresholds Largest contentful paint 1.1 seconds against a 2.5 second threshold. First contentful paint 1.0 seconds against 1.8 seconds. Time to first byte 0.5 seconds against 0.8 seconds. Cumulative layout shift zero against a threshold of 0.1. All four pass. threshold Largest contentful paint 1.1s 2.5s First contentful paint 1.0s 1.8s Time to first byte 0.5s 0.8s Cumulative layout shift 0 0.1

Core Web Vitals assessment: Passed. Interaction to next paint returns no data, which is what happens when a site ships almost nothing to interact with. This is field data: it is what Google recorded from actual visitors, and anyone reading this case study can verify it in thirty seconds at PageSpeed Insights.

Lighthouse, desktop: 100 performance · 100 accessibility · 92 best practices · 100 SEO.

Conversion. 34% of Google Ads clicks submitted the lead form between 1 June and 20 July 2026, across 412 clicks, producing 140 leads. Sector average for paid search landing pages is 6.6%. Phone and WhatsApp conversions are counted separately and are not included in this figure.

Cost per lead fell from 215 lei to 35 lei across that same window, because the same ad spend now produces six times the leads. Nothing about the campaigns changed. The change is entirely on the page.

Worth separating the two periods, because they are not the same number. In the first month after launch, lead volume roughly doubled. The six-fold figure is the steady state measured from 1 June to 20 July, once the campaigns had settled and the form had been live long enough to read properly. A rebuild does not deliver its full effect in week one, and any case study that claims otherwise is measuring a launch spike.

What changed for the client

Two things, in the client's own account of the first month. Lead volume doubled. And the leads got better: fewer people price-checking a number they had no intention of acting on, more people ready to book a site visit.

The second half of that matters more than the first, and it is the part a conversion rate cannot show you. Asking for a phone number and consent up front, then making email and the written message optional, filters on intent rather than on patience. The people who fill in a two-field form are the people who expect to be called.

Organic search, five months after launch

Google Search Console · March – July 2026

Organic impressions

/month

Organic impressions: 4,100 in March 2026 rising to 11,800 in July 2026 4,100 11,800 Mar Jul

Organic clicks

/month

Organic clicks: 78 in March 2026 rising to 340 in July 2026 78 340 Mar Jul

Average position

1 = top

Average position: 18.4 in March 2026 rising to 9.6 in July 2026 18.4 9.6 Mar Jul

Average position is plotted with 1 at the top, so an improving rank moves upward. Zero 404 errors were recorded in Search Console after the URL migration.

Our approach

The performance work and the form work are usually treated as separate projects by separate people. They are the same project. A 1.1 second page with a five-field form is a fast way to lose a lead, and a two-step form on a four second page never gets seen. The compounding is where the 34% comes from.

Frequently Asked Questions

How long does a rebuild like this take?

Nine weeks from kickoff to launch, covering brand direction, design, build, content migration, structured data and analytics. The largest single block is not the build. It is agreeing what the site is for, because every later decision resolves from that answer.

Why static instead of WordPress?

A pool builder does not need a publishing platform, a plugin ecosystem or a database. Those are ongoing costs in maintenance, security exposure and load time. A static site removes all three and, as the field data shows, arrives faster on the phones that most visitors are actually using. We compared the options in detail in our WordPress alternatives guide.

Can the client update content themselves?

No, and that was deliberate. Content lives in structured files rather than behind an admin panel, which is exactly what keeps the site this fast and stops it drifting out of shape over time. Updates come through us, within two business days. For a business that changes its content a few times a year rather than weekly, that is usually the right trade. A client who needs to publish daily should be built something different, and we would say so.

How do you protect rankings during a migration?

Map every legacy URL to its replacement before launch, redirect at two independent levels, keep one canonical address per page, and watch Search Console for 404s in the weeks after. Ranking equity is lost through neglect, not through moving.

What do enhanced conversions actually change in a Google Ads account?

They let Google match a lead back to the click that caused it with much higher accuracy. More matched conversions means the bidding algorithm learns from real outcomes rather than a fraction of them, which usually shows up as lower cost per lead over time rather than as an immediate jump. Our conversion tracking and analytics work treats this as setup, not as an optimisation to get to later.

Does a faster site really produce more leads?

Conversion drops by around 4.42% for every additional second of load time. On paid traffic that is a direct cost, because the click has already been bought whether the page arrives or not.

Paying for traffic your site is losing?

Book a 30-minute conversion audit. Tell us your traffic source and we will tell you where it leaks.