Zlaja 2015
a plumber and electrician site that people call, not browse
A site that people call from, not buy from. The visitor is usually standing in a bathroom with water on the floor, looking for a phone number, not a catalog. Everything on this site serves that one second in which they decide whether to call or go back to Google.
- Multi-page website
- Belgrade
- August 2026
- 12 min read
- PHP 8.5
- nginx + FastCGI cache
- MySQL
- PWA panel
- Vanilla CSS/JS
- Customer
- Zlaja 2015
- Industry
- Plumber and electrician, 24/7 emergency call-outs
- Area
- Belgrade and surroundings
- Type
- Multi-page website with a work order panel
- Technologies
- PHP 8.5 · nginx FastCGI cache · MySQL · PWA
- Website
- vodoinstalaterzlaja2015.rs
- Status
- Live site, actively maintained

01 / 11
What Zlaja 2015 does
Zlaja 2015 is a plumbing and electrical business from Palilula that works across Belgrade and the surrounding area. Two trades, one phone number, and availability that the company lists on its site as around the clock, seven days a week, with more than thirty years of experience.
The plumbing side of the work is what people call about at night: machine drain unclogging with a Rotenberg cable, high-pressure cleaning with the WOMA system, septic tank emptying, water heater installation and servicing, fitting of bathroom fixtures and leak detection. The electrical side covers complete installations, replacing sockets, switches, fuses and distribution boards, lighting installation and fault finding — all of it described on a separate page about electrical services.
The combination is more practical than it looks. When a pipe bursts inside a wall and soaks the wiring, one person comes instead of two, and nobody shifts the blame to the other. That is the business's real advantage, and the site was written from the start so that the advantage shows instead of hiding behind a generic “services” heading.

02 / 11
What needed solving
This is not a store. There is no browsing, comparing or coming back tomorrow. The visitor has a problem that is leaking, usually at the worst moment, and is looking for one thing — a number that works right now. Anything that stands between them and that number is lost business.
All the requirements came out of that one sentence:
- A phone number visible on every screen, without scrolling, as a tappable link that opens the dialer right away — not as text someone has to copy out.
- A site that loads on a poor mobile connection, because it is not opened at a desk but in a bathroom, a basement, a stairwell.
- A separate URL for each service, because people do not search for “plumber” but for “drain unclogging Belgrade” or “water heater replacement price”.
- Proof that the equipment exists — a WOMA machine, a septic tank truck and a thermal camera are not something every tradesman has, so they should be shown in photos, not just claimed.
- A place to keep track of jobs that is not a notebook in the van.
The last item is what set this project apart from an ordinary website for a service business. The site brings in calls, but calls without records end up as money never collected, so the site came with a work order app.

03 / 11
Site structure — services, municipalities, emergencies
The sitemap lists twenty-five URLs, and they are not random. The home page, ten service pages, an overview page of the covered municipalities and seven municipality pages, the gallery, about, contact, an emergency call-out page and the legal texts.
The service pages are split according to how people actually search: an overview of plumbing services, then separately drain unclogging, WOMA high-pressure cleaning, water heater installation and servicing, septic tank emptying, replacement of pipes, faucets and traps, bathroom fixture fitting and electrical services. Each has the same skeleton — what the service is, how it is done, frequently asked questions, a call to action at the end — but not the same text. The WOMA page compares high pressure with cable cleaning and explains when each is better. The water heater page lists the types and the most common faults. The septic tank page covers when emptying must not be put off.
In the first version, the municipalities were handled the opposite way from the usual approach: instead of seven nearly identical pages with only the municipality name swapped — the fastest way to get Google to rate that whole section of the site as thin content — the /vodoinstalater-zemun and /vodoinstalater-palilula URLs, and others like them, led to a single page about the covered municipalities and pointed to it with a canonical tag. At the end of August 2026, each of the seven municipalities got its own page with its own text about the neighborhoods, the type of buildings and the faults that come up most often there, and with its own canonical URL, while the overview page stayed as a summary. All covered municipalities, together with neighborhoods such as Kotež, Borča, Krnjača and Mirijevo, are listed on the page about locations across Belgrade.
04 / 11
The call as the only real action
There is exactly one thing the visitor needs to do on the site, and it is not hidden. On November 12, 2026, the home page got a new look: the headline “We come in our own vehicle, with our own machine”, right below it what the business fixes, a single call button and the rating from its Google profile. All photos are from the business itself.
Below the headline come five scenes that stay pinned on screen while you scroll, on phones too: the vehicle fleet, the WOMA machine, the drain cable, the septic tank truck and completed jobs. Each one says what the machine does and which problem it solves, so before calling, the visitor sees that the business comes with its own equipment. On phones, a bar with the number stays at the bottom of the screen, and the page ends with a “Call any time” contact section, with 24-hour opening hours and the address in Kotež.
The contact form exists as a second option, for those who do not call right away but want an estimate. Messages go through the PHP function mail() to the mail server on the same machine, from an address on the business's domain. One detail once took far too much time: in the message text, the word “BEOGRAD” had a Cyrillic letter O instead of a Latin one, three times. It looks identical but is not the same letter, and a small thing like that can push a message toward the spam filter.
05 / 11
Work gallery and equipment
For a tradesman, the gallery matters more than in most industries. When someone is choosing whom to let into their apartment at two in the morning, a photo of a finished job is worth more than any description. That is why the work gallery is not decoration but an argument.
Filters split it into completed jobs, vehicles and equipment. Jobs show photos from the field: patching pipes, fitting a toilet, fixing a leak. Vehicles and equipment show what you cannot rent by the day — the Rotenberg machine, the septic tank truck, a thermal camera for leak detection and the business's vehicles. Every image exists in two WebP versions, a smaller one for the grid and a full-size one for viewing.
The gallery also produced a finding that is easy to overlook. The lightbox originally had an empty <img src=""> element that was filled in only on click. The browser treats an empty image source as a request for the current page, so the whole page was loaded a second time just to be thrown away. It was replaced with a transparent one-pixel placeholder, and the unnecessary request disappeared.
06 / 11
Serbian and English without a second copy of the site
The site has a language switch in the header. The usual solutions are two sets of files, a translation database or an off-the-shelf plugin — all three mean every text change has to be made in two places, and in practice the second place gets forgotten.
Here it was done differently. Text is written in the HTML as a pair, the Serbian and then the English version separated by a single character, on an element that carries data-translate. Before the page is sent, PHP's output buffer goes through the document and keeps only the half of each pair that matches the cookie with the chosen language. The translation sits exactly where the text it translates is, so the two cannot drift apart.
The catch was in the cache. The site sits behind an nginx FastCGI cache, which means a finished page is stored and served without running PHP — and that is exactly the step that picks the language. Without a fix, the first visitor would set the language for everyone else for the next ten minutes. It was solved by bypassing the cache when the cookie asks for the English version, so only the Serbian version is cached. It is the kind of bug that does not exist in testing, because a test is always run by one person with one language, but on the live site it shows up immediately.
07 / 11
Technical implementation
The site is written in PHP 8.5 behind nginx, without WordPress and without a single plugin that would need watching and updating. Pages live in their own directories, the shared parts — header, footer and the closing call-to-action bar — in a shared include, and the styles are split into a critical part inlined in the page and the rest, which loads afterwards.
In front of everything sits a FastCGI cache with its own zone and a ten-minute lifetime. The cache stores only GET and HEAD responses, so form submissions always reach PHP — because a cached response to a submitted form means another visitor sees someone else's confirmation.
Three things from the server configuration are worth singling out, because they come up everywhere and cost a lot:
- The redirect from the www address dropped the path. The rule returned the bare domain instead of the domain with the path, so every link to the
wwwversion of a subpage ended up on the home page. One missing argument on one line, and it means that every shared URL and every backlink to a subpage does not land where it should. - The rule that blocks access to hidden files also blocked
/.well-known/, and with itsecurity.txt. The fix is an exception placed before the block, not instead of it. - For some visitors, the site was in the wrong place. The zone had an IPv6 record, but the vhost listened only on IPv4. Visitors on networks that try IPv6 first — and in Serbia that includes the mobile operators — did not reach the right vhost. The fix is one line per block, but you will not find it by looking at the site in a browser, because on most connections everything looks fine.
On top of that, the home page has a locked attribute at the file system level as protection against unauthorized changes. In practice, every deploy has to remove the lock first and then put it back — which is deliberately inconvenient, because that is the point.
08 / 11
Speed and what actually helped
Measurements were taken before and after, in two passes, and the biggest gain did not come from where you would expect.
On mobile, the performance score went from 83 to 97 in the first pass and to 98 in the second. The time the main thread was blocked fell from 610 milliseconds to 170, then to 140. Mobile LCP was brought down from 2.3 seconds to 2.1. Accessibility is 99, SEO 100, and best practices went up from 96 to 100.
The decisive move was not image compression but when Google Tag Manager loads. Instead of starting right away, it was deferred until the visitor's first interaction — a scroll, tap or click — or until four seconds after load, whichever comes first. Analytics still measures everything it needs to, but it does not hog the processor while the page is being drawn. That one change brought more than two thirds of the total gain.
The nicest finding was with the fonts. The subset with the accented letters was not preloaded, and the font was set up not to be waited for if it was not ready. The result: on a first visit with an empty cache, the letters č, š, ž, ć and đ fell back to the system font — in the heading “Električar”, one letter came from a different font, visibly larger and darker. On every later visit everything looked right, so the bug survived for months. It was fixed by adding the preloaded subset to all twenty-two pages.
What was not solved is worth stating just as clearly. Layout shift during loading on desktop stayed at 0.194, above the recommended threshold. An attempt to reserve the height in advance made it worse, at 0.265, so it was rolled back. A real fix needs the hero section layout reworked, not one more property added. On mobile, where this site's traffic is, the value is below 0.01.
The hero section was reworked with the new home page design on November 12, 2026. A measurement the same day, Google PageSpeed: performance 100 on both phone and desktop, layout shift 0.001 on phone and 0.002 on desktop.
09 / 11
SEO, schema and local visibility
Every page has its own title, description and canonical URL, Open Graph and Twitter cards, and structured data that matches what is on it. The home page and the service pages carry the Plumber type with the address, phone number, opening hours from 00:00 to 23:59 all seven days and the service area. The municipalities page lists twenty administrative areas as areas served. The questions the client actually gets — how much unclogging costs, what the warranty is, what the WOMA system is — are marked up as FAQPage so that their content is machine-readable. Google decides for itself whether and how to show a rich result, and for most business sites the FAQ rich result is no longer shown.
There were also two passes through the W3C validator. The first showed four to six errors per page on all fifteen pages checked; after the second there were zero on all of them. The errors were not so much cosmetic as contagious — one extra closing tag sat in the shared include for the closing bar, so it repeated on every page of the site. Besides that: a block of styles placed directly in the footer instead of the CSS file, a font preload tag with an invalid value that the standard does not allow, and skipped heading levels where an H4 came right after an H2.
On the infrastructure side, the DMARC policy was raised from monitoring to quarantine for all messages, CAA records were added that define who may issue a certificate for the domain, and a security.txt file was published with a contact for reporting vulnerabilities. The sitemap was cleaned up after a pass through Search Console — redirecting URLs have no place in a sitemap, because Google picks them up from there, sees the redirect and reports them as not indexed.
10 / 11
The work order panel
Alongside the site, an app for running the business was built on a separate subdomain. It is not public and not part of the site — search engines do not index it, and sensitive directories are locked down at the server level.
It is a single-page app that installs on a phone like a real app and works even without a connection, which is not a luxury in this line of work — half the call-outs are in a basement or boiler room with no signal. The panel holds what a tradesman actually needs:
- Work orders with a status — pending, in progress, completed, unpaid, canceled — and a priority from low to urgent. Each order comes with photos from the field and a link to the client.
- Clients split into individuals and companies, with multiple contacts and a tax ID (PIB) for companies, and statistics per client: how many orders there were, how much was paid, how much is owed.
- Expenses by category — materials, fuel, wages, tools, vehicle, office — tied to a specific order, so you can see what each job really cost.
- Reports: monthly with income, expenses and the difference, yearly by month, and an overview of performance per technician.
- Roles: the administrator sees everything, a worker sees only their own open orders. Someone out in the field does not need to see other people's billing.
The “unpaid” status as an equal item next to “completed” is a small detail that shows who the app was written for. A job that is done and a job that is paid for are not the same thing, and for a tradesman that difference is the most expensive item of the year.
11 / 11
What the client ends up with
A site that is his own. No monthly platform subscription, no plugins that fall apart with the next update, no license that expires. The code and the database sit on the server and can be copied.
In practice it looks like this: someone types the service and their part of town into a search, opens a page about exactly that service, and has the number under their finger before scrolling at all. The call comes in on one number. The job is entered in the panel on the phone, with a photo and a price, and at the end of the month there is a report instead of a guess.
The site is in active maintenance. The last full pass covered nineteen pages on two screen sizes plus the panel: no console errors, no horizontal overflow, no broken images, all sitemap URLs reachable, and the form checked all the way to message delivery. Whatever changes is changed on the live site, with a backup before every edit.
On a phone
The same site, in your hand.
Most visitors come from phones, so the layout, buttons and images are arranged for the small screen first.

Questions
What clients ask.
Why does a tradesman need a website at all when people call him through referrals?
Referrals bring people who already know the name. A website brings those who know no one and type “drain unclogging Belgrade” at two in the morning. Those are two separate groups of customers, and you do not get the second one without a website. Besides, even someone who gets the number through a referral usually checks the website before calling.
Why does each service have its own page instead of everything on one?
Because people do not search for the name of a trade but for a specific problem. Someone looking for a water heater replacement and someone who needs a septic tank emptied are different people with different questions. A separate page can answer exactly that question, while a combined page cannot answer any of them properly.
Does the site load fast on a weak mobile connection?
That was a requirement, not a wish, because a site like this gets opened in basements and bathrooms. The critical part of the styles is inlined in the page itself, images are in modern formats with a fallback for older browsers, and analytics starts only after the first interaction so it does not slow down the first render.
What is the panel, and do I need it with the site?
The panel is a separate app for managing work orders, clients, expenses and reports, which installs on a phone and works even without a connection. It is not required with the site. It makes sense once the number of jobs passes the point where a notebook starts to lie, and especially when several people work on the crew.
Can the site be expanded later with new services or municipalities?
Yes, and the structure is designed for it. A new service is a new page on the same pattern, with its own title, description and structured data. A new municipality gets its own page from a shared template, with its own text about the neighborhoods, and is added to the overview page of the service area, without empty copies that search engines would devalue anyway.
How do you know something was actually fixed and not just reported as fixed?
By measuring before and after, on the live site. Speed scores, the number of validator errors, time to first render and how the form behaves all the way to message delivery — everything is checked twice. What did not work is written down too: layout shift on desktop is still above the threshold and needs a layout rework, not one more CSS property.
Related projects
From the same field.

Klimatronik 016
Glass Service Bošnjace