Website2026-08-21
Detailing 016 — a one-page site for auto detailing in Leskovac
Detailing studio does not have a product catalog or shopping cart, but it has a price list that is more complex than most web stores: seven groups of services, eight classes of vehicles and two prices in the same row. All that should have been put on one page that can be read on the phone, opened immediately and does not ask the visitor to search for anything twice.
- Client
- Detailing 016
- Activity
- Auto detailing — polishing, ceramic protection, interior
- Area
- Leskovac i environment
- Type
- One-page site with price list and contact form
- Technologies
- PHP · Nginx · JSON-LD · AVIF/WebP
- Site
- detailing016.rs
- Status
- Live site, under active maintenance
- Technology
- PHP · Nginx · JSON-LD schema · AVIF/WebP
Problem and context
What does Detailing 016 do
Detailing 016 is an auto detailing studio in Leskovac, in Sime Pogačarevića Street 19. The number in the name is the area code of the city, so the name immediately tells what is done and where it is done — rarely a good choice for a local job that is wanted just like that, around the city.
The job has four units. Regular maintenance and washing, from quick refreshing to detailed manual washing with cleaning of rims and bays. Varnish correction — polishing with clay preparation and decontamination, with or without ceramic protection. In-depth cleaning of the interior, where the seats are removed if necessary, and the roof, floors, trunk and dashboard are cleaned. And a series of individual treatments: restoration of headlights with graphene protection, protection of rims, polishing and hydrophobic coating on the windows, cleaning of the engine compartment, ozone against odors, removal of foils.
The fifth thing is what distinguishes this studio from a laundromat — training. The owner lists on the website fourteen years of work in authorized Audi and Porsche centers in Zurich and his own detailing studio in Switzerland, and he sells this knowledge as individual training, one-on-one, in his workshop in Leskovac.
Works by appointment and by appointment, on weekdays and Saturdays. For the city of Leskovac, there is also a vehicle pick-up from the address, so the car owner does not even have to come.
What needed to be solved
The request was one site, one page, without a branching menu and without pages that no one opens. But that one page has to do four different jobs:
- To carry the entire price list. Not "prices on request", but everything, with vehicle classes and how much it costs — because half of the calls the detailer gets are actually questions about price.
- To be read on the phone. The price list with two price columns and eight vehicle classes on a width of 360 pixels is a table that either collapses, or scrolls sideways, or turns into something else. It was transformed into something else.
- To lead to a call. Detailing is scheduled by phone. The number must be visible at all times, and clicking on it must open the dialer — which sounds trivial until it's checked, and the number in the link has spaces and the phone can't call it.
- Yes the form actually sends. A contact form that looks like it works, but the message never arrives, is worse than a site without a form.
With that came the unseen: cookies and analytics by regulation, a privacy policy and terms of use written for this business, and a site that stands up to scrutiny before someone else does.
Why one page, not five
With a local service, a visitor comes with one question and a little patience. He wants to see if what he needs is done, how much it costs and what the phone number is. Every click that stands between it and that answer is where someone gives up.
That's why everything is at one address, and navigation leads through anchors in the same page: services with price list, training, about us, contact with map. The menu is fixed at the top, on the phone it opens in full screen and closes with a touch outside itself, and the call button is in the header and in the footer — the same number in seven places on the page, always as a tel: link without spaces.
One page does not mean one file though. The header is PHP of about 1,560 lines, the style is a separate file of over 3,600 lines, the script is delayed and small — about 240 lines, only for the menu, anchors and form submission. The privacy policy and terms of use exist twice: as a modal in the page, for those who read in passing, and as a separate page with its own address, because the legal text must have an address that can be sent, saved and indexed.
The site also has its own error pages — 404 and 500 are not the default server message, but a page in the same style, with a link back to the home page.
Price list readable on the phone
This is the biggest part of the work and the part that has changed the most. The price list is divided into seven groups: regular maintenance and washing, color correction and paint protection, in-depth interior repair, leather seat care, partial polishing and damage retouching, premium individual services and special treatments.
Above all that is a guide to vehicle categorization — eight classes, from small city cars to the largest luxury SUVs, each with examples of specific models. Without that guide, the price has no meaning: the car owner doesn't know if his car is "bigger" or "big", but he knows what model he drives.
The table for polishing is a special case, because there are two prices in the same row — polishing and polishing with ceramic protection. On the desktop, these are two columns with a common header. Below 575 pixels the header disappears, and each price gets its tag from the attribute in the markup and turns into a chip under the class name, one below the other. No side scrolling and no zooming — and it's still clear which digit is which.
The entire price list on the website also takes into account what the detailer has to say out loud: that the final price of polishing and deep washing may vary after an on-site inspection of the vehicle, and that the ceramic and graphene protection is maintained with pH-neutral shampoos, not with chemicals from a self-service car wash. Those notes are at the end of the price list, not in fine print somewhere else.
When the client sent a new price list in June 2026, the change was big: from six to eight vehicle classes and from five to seven service groups. The design was not touched — new style components were added and the content was rewritten, so after the same changes, all prices in the structured data, in the FAQ and in the page description were withdrawn. A price list in one place, and its echo in four others, and all four had to match.
Training section, added later
Training was not in the first agreement. The client requested it by e-mail, and then revised the package and prices with another e-mail — which is a normal process for a service that is just being introduced.
The section is inserted between services and "about us", with its own anchor, with an entry in the desktop menu, in the mobile menu and in the quick links in the footer. There are three packages inside - the basics of detailing, professional correction and protection, and the longest program that, in addition to everything previously, also covers recording and photographing works for social media. The medium package is marked as the most requested, because it is also the most frequently chosen.
Below the package are four things that the participant gets: one-on-one work without a group, standards from Swiss practice, working with professional equipment and chemistry of recognized brands such as Rupes, Koch-Chemie and Gyeon, and the relationship between theory and practice turned in favor of practice. Appointments are agreed in advance, so the training section ends with a phone and a form, not a purchase button.
On the code side, the addition of the section also meant a new block of structured data of type Course, with three instances of course, duration and price, and one new question in the FAQ. The content also appeared in Google as a course, not just as a paragraph of text.
The contact form that actually sent
This is the part where it was the worst and where it is worth being open. The form sat on the site and returned an error when submitted — it never even worked properly. When it opened, there were three separate, overlapping faults underneath.
- The message wasn't even read. The script in the browser was sending the data as a multipart form, and PHP was trying to read it as JSON from the input stream. The result was always the same response about incorrect data format. It is now read from the form, with JSON as a fallback.
- Wrong way to encrypt the connection. Sending was via implicit SSL on port 587, and that port is STARTTLS — the connection opens unencrypted, then lifts to encrypted after greeting. Now the flow goes as it should: open connection, hello, STARTTLS, lift encryption, hello again, login.
- An account that did not exist. It was sent from an address that was not created on the mail server, so the application was rejected. The account was created on the client's domain and aligned with SPF, DKIM and DMARC records, so messages from the site go from the address of that domain and pass the authentication check.
Since there is no mail library layer on this site, the entire conversation with the server is written manually in the form editor — hence the file of about 675 lines for one contact form. With sending comes things that are rarely done: names in message headers are encoded when they contain our letters, all user input is sanitized before entering HTML messages, and the customer receives a separate confirmation to their address, with a reply directed to the studio's inbox.
Bot protection goes through a common module for the entire fleet — a hidden field that is not filled in by a human, a content check and a limit on the number of attempts per address. The address is checked for format, and the message is not sent until the visitor accepts the terms and privacy policy. After the repair, the correct entry with contact form, in the record of the mail server, was checked until the delivery confirmation.
Performance and images
The detailing site should logically be full of photos. This one isn't — it's basically just a logo and an social sharing image. That was the decision: the client publishes photos of the works on Instagram and TikTok, where they are viewed, and the site carries prices, descriptions and a phone number. Fewer images means a page that opens immediately.
The few pictures that exist have been finished to the end. The logo was a single 68 kilobyte JPEG that served as both an icon, a header image, and a shareable image. Now there are three versions — AVIF of about 23 kilobytes, WebP, and JPEG as a backup — and the server chooses the format based on what the browser accepts, without a single markup change. The share image is separated into a separate file in the correct 1200 by 630 ratio, because the logo looks the way it does in that frame.
Static files are cached for a year, which is a great decision until the style is changed — so the returning visitor is stuck with the old look. That's why the style carries a timestamp of the change in the address: when the file changes, the address changes, and the cache flushes itself. Without that detail, every appearance change would be invisible to everyone who has already visited the site.
Measurement after pass in May 2026: on desktop a score of 99 with a maximum view of about 0.9 seconds, on phone a median of about 96 with a maximum view of 1.5 seconds and zero content scrolling. Before that, the mobile rating was 88, and the largest view was waiting for 3 seconds. It is also worth saying that the mobile measurement is uneven between passes, so the real value is the median of three, not the best result.
Cookies, analytics and legal texts
The analytics were set to load before the visitor said anything. It is a risk today, not a detail. It now works in consent mode: until the visitor accepts, the measurement is set to declined and no analytics and marketing cookies are set; when he accepts, the permission is retrieved and remembered for the next visit. The banner also offers an option with only necessary cookies, because a choice that has only one button is not a choice.
The banner itself comes from a common module used by a whole fleet of sites, with one flag set just for this site: the style is not inserted into the body of the page, but loaded as a separate file. The reason is concrete — the markup validation reports the style in the body of the page as an error.
With that fix, the remaining two errors from the same check went away. The first was a map wrapped in a link, which is not allowed by the rules — the map remained independent, and over it stood a transparent layer with a link that opened it in the application. Another was the width of the map set by attribute instead of style. The site came to zero with three errors.
Privacy policy and terms of use are not copied from someone else's site. They write what is collected via the form, what are the three types of cookies and what does it do, what rights does the visitor have and who does he contact, and the terms also mention what is really important for this business — that the photographs of the works are the author's work of the studio.
SEO and visibility in local search
For a local service, almost all of the gain is that Google understands exactly who the business is, where it is, and what it does. That's why the site carries four blocks of structured data.
- Company — name, address in Leskovac, coordinates, telephone, working hours per day, method of payment, currency and area served within fifty kilometers.
- Services — price list translated into a catalog of offers, with amounts and currency per item, in the same groups as on the page.
- Frequently asked questions — questions that are actually asked on the phone: how much does polishing cost, how long does ceramic protection last, where is the studio located, how much does the interior cost, is there training.
- Course — three training packages with duration and price.
The rest is the craft part. The page title and description are written for local search intent rather than decorative wording; the canonical URL is correct; robots.txt allows search crawlers and explicitly allows AI bots, as these systems increasingly assemble direct answers, and only bans error and maintenance pages. The site is also reported in Bing Webmaster Tools, not just Google Console.
The security side is part of the same story, because anything that knocks down a site knocks down rankings: a certificate configuration that earns the top external rating, the domain on the browser preload list for mandatory HTTPS, the DNS record that determines who can issue a certificate for a domain, and a standard security.txt vulnerability-reporting file. In addition, the vhost also received listening on the IPv6 address — without that, part of the visitors from mobile networks, and occasionally Googlebot itself, could not reach the correct virtual host.
Outcome
What the client received
One address that answers all the questions that would otherwise come to him by phone, and a phone number for those that remain. No monthly platform subscriptions, no plugins that break on the next update, and no content management system to protect against hacking.
Maintenance is straightforward: the client sends a new price list or a new section by e-mail, the change is made to the code, it goes through the private repository and is pulled to the server itself, with a backup copy before each change. The new price list and the training section were thus created, within ten days.
What is left for further has been opened and written down. There is still room in the critical part of the style that loads first. Mobile speed measurement is still uneven between aisles. And if one day you need a gallery of work with a before-and-after comparison, the site is ready for it — it just wouldn't bring anything that Instagram doesn't already do better.
In the meantime, the site serves its intended purpose: a customer from Leskovac types in polishing or ceramic protection, opens the page, sees the class of his car and the price next to it, and calls. Everything else on this page exists to make that one move as short as possible.
FAQ
Frequently asked questions
Why one page and not a multi-page site?
Because the visitor comes with one question — what is being done, how much does it cost and what is the number. With a local service, every extra click is where someone gives up. There's five pages of content here, but it's organized into a scrollable flow, with menu anchors instead of new URLs.
Can the client change the prices themselves?
Not yet — the price list is part of the code and changes by agreement. For a site with a single price list that is refreshed once or twice a year, it is cheaper and safer than a panel that needs to be maintained and defended. If the rhythm of changes changes, the panel is added without creating a new site.
How does the price list behave on the phone?
The table with two prices in a row is arranged in chips one below the other, and each price has its own label. No side scrolling and no zooming. This was the main reason to do the price list manually and not through a ready-made component.
Does the contact form actually send messages?
Yes, and it is checked until the delivery confirmation in the mail server record. The form previously had three separate failures that overlapped and caused the message to never arrive. Now the message goes from the address on the site's domain, with aligned SPF, DKIM and DMARC records, and the customer also receives a confirmation to his address.
Why are there almost no photos of the works on the site?
Because the client publishes them on Instagram and TikTok, where they are seen and appear daily. The site does what the networks don't do well — a full price list, service descriptions and contact information. A before and after comparison gallery can be added when there is a real need for it.
How long does it take to build a site like this?
Shorter than a multi-page site, but not as much as it looks. The price list and legal texts take the most time, because they are written for a specific job. Code is written quickly; harmonizing the prices on the page, in the structured data and in the frequently asked questions is a part that cannot be seen, and must match.
Next step
Have a project that needs to work better?
Send me your goal and current situation. I will reply with a concrete scope proposal.
Start a project