Case study · Google Ads and website

The website first, the first ad three months later

Website, business profile, then paid campaign — in that order. The collaboration has run since December 2024.

The situation
You run a trade business, and in search you barely exist. Either you have no website, or you have one that brings no enquiries — and you cannot tell whether advertising would fix that or just burn the money.
The approach
Foundations first: a website and a Google Business Profile with the right search categories. Only then, three months later, the paid campaign — narrowly targeted, run in budget-based cycles.
The result
The campaign has run since March 2025, renewed cycle after cycle. By July 2026: 6,478 visits, 87,740 impressions, at an average of HUF 49 per click.

The campaign in numbers

Key metrics of the search campaign and the website
Collaboration startedDecember 2024
Campaign runningsince March 2025
Total visits (to July 2026)6,478
Total impressions (to July 2026)87,740
Average cost per clickHUF 49
Google optimisation score97.5%
Project
air-conditioning installation and maintenance
Role
Website, business profile, campaign management, operations
Arrangement
Monthly maintenance, with a cyclical campaign budget alongside
Two roads lead to an enquiry From a search, a visitor can arrive two ways: through the Google Business Profile, which is free and live since December 2024, or through the paid search ad, running since March 2025. Both lead to the same place: the website, where the enquiry happens. A Google search “AC repair”, “servicing” Business Profile local result, free since December 2024 Search ad paid, cyclical budget since March 2025 Website custom theme, loads fast this is where it is decided Enquiry phone or email
The business profile brings results for free, the ad speeds things up for money. Both lead to the same website — which is why what greets the visitor there matters.
  1. 01 A Google search “AC repair”, “servicing”
  2. 02 Business Profile local result, free since December 2024
  3. 03 Search ad paid, cyclical budget since March 2025
  4. 04 Website custom theme, loads fast this is where it is decided
  5. 05 Enquiry phone or email

Why the website alone was not enough

A new site is not found on its own. The keywords showed that people search for a concrete fault or a purchase, not for a company name.

So the work fell into two parts. One is traffic, because climbing the organic results takes years. The other is the site itself, because an ad only takes someone as far as the click.

Each of these without the other is money thrown away. Ads pointing at a weak site: bought visitors who leave. A good site without ads: nobody finds it.

The order: foundations first, ads after

The collaboration began in December 2024, and in the first three months not one forint went on advertising. That time went into the website, and into getting the business onto Google's Business Profile with the right search categories.

The paid campaign only started in March 2025. The order is deliberate: advertising amplifies what is there — with nothing to amplify, you buy visitors at a premium for a place they walk away from. The business profile also brings local search results for free, and paying for those with ads would be a waste.

What this means if your situation is similar

If you run a trade or service business, the question is rarely “to advertise or not”. It is rather what an enquiry costs, and whether it is worth that much. A few weeks of running shows the number, and from then on the decision is made with figures, not feelings.

The other question that came up before this campaign launched: if a hundred visitors arrived right now, what would happen to them? If the site is slow, shows no work, and carries no sign that others were satisfied, most of the ad budget is gone before anything happens.

And before paying for anything: check whether your Google Business Profile appears for the phrases your customers actually use. It is free, and for many trade businesses it brings enquiries on its own. With this client, the first three months of the collaboration were exactly that — with no ad spend at all.

If this sounds familiar — a website that brings no enquiries, or an urge to advertise without knowing whether it pays — write a few sentences about what you do and where your customers come from now. One exchange of emails usually shows whether a campaign makes sense.

kristof@kristofkarner.com
Technical details

From here on come the implementation details: how the campaign is built, the website's technical solutions, and the traps we ran into along the way. If you only wanted to know what can be achieved, everything is above — this part shows the background of the decisions.

Size of the implementation
Custom theme18 PHP files; 1,795 lines of PHP + CSS + JS combined
Custom command-line tooling3 WP-CLI commands

The campaign

Narrow targeting, cost per click kept low

The search campaign is built on few, precisely matching keywords, and on the consistent exclusion of irrelevant searches. That is what keeps the cost per click around HUF 49–50 since the campaign started — while Google's optimisation score stands at 97.5%.

The low click price is not a trick here but a consequence: someone searching for exactly what the ad offers is more likely to click, and the system rewards that with cheaper impressions. Broad targeting achieves the opposite.

Keywords set up to tolerate imprecise searches

People do not search the way the trade talks about itself. They type something, then add another word: a city, a brand, an “urgent”. So the keywords are not set to exact match. This is what I wrote to the client when the campaign launched in March 2025:

“These keywords will be set up so that if the searcher adds something else to their query, the ad can still appear.” Kristóf Karner, handing over the keyword list, March 2025 — translated from Hungarian

The client received the full keyword list in a shared document, to see what the money goes on. In the first weeks a weekly report went out with results and suggestions. A campaign is cheapest to steer in its first month — every correction later costs more.

Budget-based, cyclical running — for the campaign

The campaign does not burn continuously but in cycles: the client tops up the budget when there is capacity for new work, and the campaign runs while the budget lasts. At the end of each cycle a report goes out, and the client decides about the next one.

In a seasonal trade this fits reality better than advertising on a flat monthly fee — in summer, at peak, there is no point paying for more enquiries than can be taken on. The clearest sign the model works: since March 2025, every cycle has ended in a renewal.

Website maintenance runs separately, on a contract with a monthly fee. Splitting the two is deliberate: the ads should burn when there is capacity for new work, but updates, backups and fixes should continue even while the campaign rests.

The June 2025 cycle also ended in a renewal; according to the client's feedback, the number of incoming orders had risen noticeably.

The website that receives the traffic

A custom block theme, no page builder

The website runs on a custom WordPress block theme with its own block patterns — not on a page-builder plugin. This decision is about loading speed: a visual builder generates code in layers, and with traffic arriving from ads that costs money directly, because visitors leave a slow-loading page.

The theme splits into 18 PHP modules, each with one job: image conversion, gallery, reviews, loading screen, header clean-up. A change touches one file, not the whole theme.

Google reviews that refresh on their own

The reviews come from the Google Places API Place Details endpoint, on a daily schedule. The site does not call the API on every load — it reads a local snapshot that the scheduled task refreshes. That is faster and cheaper at once: the Places API charges per call.

The original site did this with a third-party review widget. The custom solution replaced it, so that no third party stands between the most important element of trust and the visitor.

Automatic image conversion

JPG and PNG images uploaded to the media library convert to WebP automatically. For the existing images a custom command-line tool was built (wp cspk webp-backfill), so hundreds of older images switched over in a single run. On a trade site this is not a side issue: the gallery showing the work is the heaviest content on the page.

The parts that are not obvious

The business profile's category decides which searches you appear for

A few days after the business profile went live, the client reported this: searching with one name for the trade, he found his business — with the other, he did not. Both names mean the same work.

The primary and additional categories set in a Google Business Profile decide which searches the business enters the local results for. A single category is usually narrower than what the business actually does — and the missing categories cause not a weaker position but a complete absence for that search.

The only way to uncover this is real searches: trying the phrases customers actually type — not the ones the trade uses for itself.

Brand logos cannot simply be put on a website

Displaying the manufacturer logos of the products you install is trademark use, which needs the owner's permission — typically an official dealership or reseller agreement. So no such logos went onto the site, and the hero image comes from licensed stock.

In the short term this looks plainer than the competitors' walls of logos. In exchange there is no legal risk for a trademark owner to dig up later.

The Google Places API returns at most five reviews at a time

How every review is kept The Google Places API returns at most five reviews per fetch. The daily scheduled task merges these into a local snapshot, filtering duplicates by author and timestamp. The website reads this snapshot, so it calls no external service on page load, and old reviews do not disappear. Places API at most 5 reviews Merge by author + timestamp Snapshot stored locally Website calls no external API daily · old reviews stay
Every fetch merges into the previous one. The shown review count can only grow — it never shrinks because a new one arrived.
  1. 01 Places API at most 5 reviews
  2. 02 Merge by author + timestamp
  3. 03 Snapshot stored locally
  4. 04 Website calls no external API

daily · old reviews stay

The Place Details response carries at most five reviews. If the site simply printed the fresh response, every new review would push an old one out of sight — the trust the business earned over years would turn invisible.

The solution is a merging store: every fetch folds into the earlier snapshot, and duplicates are filtered by author identifier and timestamp. The shown review count can only grow, never shrink.

The key derivation in the theme's codePHP
// a review's identity: author URL + timestamp
$key = trim( $r['author_url'] ) . '|' . $r['time'];
if ( ! isset( $by_key[ $key ] ) ) {
    $new_count++;
}
// fresh API data always wins — the author may edit the text
$by_key[ $key ] = $r;
Checked on the local copy — the theme's size
$ find . -name "*.php" | wc -l ; find . \( -name "*.php" -o -name "*.css" -o -name "*.js" \) -exec wc -l {} + | tail -1
      18
    1795 total

The loading screen and lazy image loading rule each other out

A dark overlay covers the content until everything has loaded, then fades away. This only works if lazy loading is switched off meanwhile — otherwise the images would start loading after the overlay is gone, and the visitor would see exactly the flicker the loading screen is there to hide.

So the theme disables WordPress's native lazy loading, and the plugins', in a separate module. Two optimisations that make sense on their own and hurt together — the kind of thing you only notice in production. On two other projects lazy loading went two opposite ways: on one, turning it off helped; on the other, turning it back on did.

The scheduled task does not run reliably without visitors

WordPress's built-in scheduler only fires when someone visits the site. In a low-traffic period that means the daily review refresh can be skipped. So the system can also be run from the command line (wp cspk fetch-reviews) and driven by real server-side scheduling — the built-in way is just the convenient default.

Questions about this project

Which comes first: getting a website or advertising?

The foundations first: a website and a Google Business Profile, and the paid advertising after. Advertising amplifies what is there — if there is nothing to amplify, you are buying visitors at a premium for a place they will leave. With this client the collaboration began in December 2024 with the website and the business profile, and the paid campaign only started three months later, in March 2025.

Why does my business not appear in Google for certain search terms?

Typically because of the Google Business Profile categories. The primary and additional categories set in the profile decide which searches the business appears for in the local results, and a single category is usually narrower than what the business actually does. A missing category does not mean a weaker position — it means a complete absence for that search. The way to uncover this is real searches: trying the phrases customers actually use, not the ones the trade uses for itself.

Is a Google Ads campaign worth it for a small trade business?

It is worth it when there is concrete demand for the service and an enquiry is worth far more than a click costs. In this case a trade company's campaign has been running continuously since March 2025 at an average cost of around HUF 49 per click. At that price level, even a few hundred forints of spend can bring an enquiry that covers a whole job — which is why the client chose to renew the campaign again and again.

How much does a click cost in a trade-sector Google Ads campaign?

It depends heavily on the trade, but with a narrow, well-aimed keyword set it can be kept low. In this campaign the average stayed around HUF 49–50 up to July 2026, alongside 87,740 impressions and 6,478 visits. The low cost per click is not a trick of the ad account but a result of narrow targeting: few, precisely matching keywords, and the consistent exclusion of irrelevant searches.

Is advertising enough if I already have a website?

Not necessarily. Advertising buys traffic, but the decision happens on the website. If the site loads slowly, shows no work, or carries no visible sign that others were satisfied, most of the bought visitors leave. For this client the site was rebuilt alongside the campaign: a custom theme, automatically refreshing Google reviews, and image optimisation.

How can Google reviews be shown automatically on your own website?

With the Google Places API Place Details endpoint, but there is an important limit: the response carries at most five reviews. If the site simply showed the fresh response, older reviews would vanish. The solution is a merging store: every fetch merges into a local snapshot, and duplicates are filtered by author and timestamp. The site reads this snapshot, so it does not call an external service on every page load.

How long should a search campaign run?

As long as it brings enquiries — but a campaign does not have to burn continuously. With this client a budget-based, cyclical run worked out: the client tops up the budget when there is capacity for new work, and the campaign runs until the budget lasts. In a seasonal trade this fits reality better than a flat monthly ad spend.

Summary

An air-conditioning company's online presence was built from December 2024 in a strict order: first a website and a Google Business Profile with categories matched to real searches, then — three months later, from March 2025 — a search campaign. The campaign runs on a narrow keyword set with consistent exclusions, in budget-based cycles; by July 2026 it had brought 87,740 impressions and 6,478 visits at an average of HUF 49 per click. The website is a custom WordPress block theme with no page builder, in 18 PHP files; Google reviews refresh daily from the Places API into a merging store, because the API returns at most five reviews per call. Images convert to WebP on upload, with a custom WP-CLI command for the back catalogue. Maintenance runs separately from the campaign, on a monthly contract.

Karner Kristóf

Independent developer in Budapest. I run the website, the business profile and the campaign — questions are welcome at the address in the contact section.

← All case studies