What it is
Dubai has thousands of salons and no fair way to find one. Discovery runs through 2 channels, and neither of them ranks on whether a salon actually suits you. Booking platforms can only show you the businesses that are on them, and Fresha, the big one here, lists 1,156 venues on its own Dubai page against the 2,777 salons in this catalogue. Google Maps ranks on how well a listing is optimised rather than on how well it matches what you asked for.
So a few thousand independent salons have no route to being found on merit. SalonsInDubai covers all of them in one place, ranked on verified information rather than on ad spend.
Why WordPress
The first real decision was the platform, and I made it for speed rather than for elegance. I had already worked with contractors who knew WordPress, and I knew it myself. It has drawbacks and I hit most of them. I still think it was the right call. The proof is that I never migrated: when the site broke badly 8 months later, holding the platform is what made the repair survivable rather than a restart.
The data was the real product
I scraped 10,566 salons across the UAE, pulling from Google Maps, the salons' own websites and other marketplaces, and collected the images alongside the records. Just over 3,000 of those were Dubai. Then the slow part started.
Collecting is the easy half. Validation is what decides whether the site is worth anything: is this website still live, is this contact real, is this the same business appearing twice under two spellings, is this place still trading at all. I think a directory is only as good as its worst record, because a visitor who clicks through to a salon that shut down last year stops trusting the rest of them. So the dataset has been through 2 passes, not one. 2,777 salons are live today, with 377 held back and flagged as closed rather than published. Every one of them failed validation.
- 10,566 records scraped UAE-wide from Google Maps, salon websites and other marketplaces, not a single feed or a bought list
- Images collected alongside the records, so listings did not launch as text
- Every record checked for a live website, a valid contact, and whether it already existed under another spelling
- Re-verified end to end a second time after closures, rather than letting the catalogue quietly rot
Designed around one decision
About 6 weeks of design and UX iteration went in before the catalogue was worth showing anyone. The brief I gave the designer was narrow on purpose: premium and modern enough that a Dubai audience takes it seriously, and simple enough that someone picks the right salon in the fewest possible steps. Those two pull against each other, which is why it took 6 weeks rather than 1, and why the Figma file ended up with 686 comments on it.
This is the decision that paid off twice. The design was built to hold at several thousand pages rather than to look right on the 12 that existed at launch, so when the rebuild came it needed no redesign at all.
The design file
Three systems on top of the catalogue
A grid of pages is not a product. Three systems sit on top of it, and the third is the one I would point at first.
The programmatic layer. 2,700+ pages generated from structured data across 207 locations, 205 services and 38 venue types. I gated it instead of generating it blindly. A service-and-area combination with fewer than 3 real listings is set to noindex, because a page with one result on it is a thin page, and generating thousands of those is basically how programmatic SEO fails.
The filters. 5 ways to narrow the catalogue: salon type, area, service, price range and rating. They match how someone actually decides rather than the taxonomy underneath.
The points system, which is the part I am most pleased with. Every salon is ranked by a transparent points score built on verified information, service quality and ratings, and the site says so publicly. A more complete listing ranks higher in its category and its filters. That gives salon owners a reason to claim their listing and keep it current, which means the people best placed to maintain the data have an incentive to do it.
Then it broke
The early signs were fine. Pages began to index and a first trickle of organic traffic arrived. Then a change to the URL structure broke the mapping between the catalogue and what search engines had already indexed. The listing pages fell out of the index and the traffic went with them.
The symptom was blunt. A lot of pages returned a 404 instead of the page that should have been there, so part of the catalogue had stopped existing as far as a visitor or a crawler could tell.
What kept it broken was the repair loop. Each change fixed one symptom and introduced another somewhere else, and every cycle took weeks to go live and longer to verify. A directory has thousands of near-identical templated pages, so a small template defect is never small: it repeats across the entire catalogue at once.
That ran for about 8 months, and it is the most demoralising kind of broken. Nothing looks wrong when you open it. The site loads, the listings are all there, every page is exactly what it should be, and none of it counts for anything. Search Console only keeps 16 months, so the drop itself has already aged out of it. Semrush kept the longer history.
Fixing it with AI
I could not find the cause of the 404s. I paid a contractor to read the code and find it, and they could not either. That is the honest state it was in: 2 people who knew the codebase, looking directly at it, and neither of us could say why a page that existed was returning a 404.
What worked was reading the whole templated surface at once with AI rather than going file by file, which is how the URL slugs and the routing that generated them turned out to be the problem. Once that was fixed I went back to Search Console, submitted the affected pages for validation, and waited. Google recrawled, the validation passed, and the pages came back.
AI did the parts that had made the old loop slow: finding where the templates diverged, generating the repetitive fixes, and checking the result against what a crawler actually receives rather than what the page looks like in a browser. I ran a second round in November 2025.
From August 2025 I rebuilt the technical layer without migrating the CMS and without redesigning a single page. A migration would have reset whatever authority had survived, and the design had been built for this scale, so it held.
- URL structure repaired so the catalogue mapped cleanly to what was already indexed
- Templates fixed to render their links server-side, so a crawler and a browser receive the same page
- Archive and hub pages returned to indexable, self-canonical, and linked into the catalogue
The fundamentals, built as components
A directory is thousands of near-identical pages, so nothing here is worth doing once. Every technical decision had to be a component the whole catalogue inherits. A fix applied page by page is out of date before it finishes.
That is also what made the recovery survivable. The 404s came from a defect that repeated across every templated page at once, and the repair worked for the same reason in reverse: one change, the whole catalogue.
- Crawlability. Every area, type, service and combination page renders its salon links server-side and canonicals to itself, and Googlebot receives byte-identical HTML to a browser. An A-Z hub links every salon detail page, so nothing sits more than one hop from a crawlable index
- Schema generated per listing, never hand-written. Every salon page emits a full LocalBusiness entity assembled from its own record: postal address, geo coordinates, opening hours for each day it trades, price range, aggregate rating with review count, and a service catalogue running to 26 offers on a well-populated listing. Nobody types any of it. Google's Rich Results Test returns 5 valid items on a sampled listing, and 4 on an area page, where the detected types change to articles and carousels because that page is an index rather than a business
- One schema layer, so a fix lands everywhere. The same applies to the editorial side: structured data comes from one theme-level component rather than being written per post, so a correction to how an article declares its subject applies to every article at once. The entity is selected from the service axis rather than whichever tag sorts first alphabetically, a defect that looks fine on one page and is wrong across hundreds
- E-E-A-T as components. A canonical author with a published fallback account, so a byline and its author schema cannot break if one account is lost. A reviewer field kept deliberately separate from the author. Author archives, and a public editorial policy
- Indexation gating. Any service-and-area combination with fewer than 3 real listings is set to noindex, so the catalogue never inflates itself with thin pages
- Link integrity at render. An internal link pointing at a post that has not published yet degrades to plain text and reactivates by itself the moment the target goes live. 55 of those existed across the corpus before the guard was built
- Cannibalization checked before writing, rather than after a piece underperforms
Summary
Page speed
Speed is the part with a public score, which makes it the easiest to check and the hardest to argue with. The homepage runs 100 on desktop and 92 on mobile, with 100 for SEO and 100 for best practices on both.
The honest part is the one metric still amber. Mobile Largest Contentful Paint is 3.3 seconds, against 0.7 on desktop, measured on a throttled 4G emulation of a mid-range Android. That is a directory homepage carrying live counts and images rather than a static page, and closing it is the current job.
Mobile
An agentic content engine, throttled on purpose
Fixing the technical layer made the catalogue visible again. It did not make it rank for anything a person searches before they pick a salon. A directory answers "which one", but almost every query that comes before that is informational, and a catalogue cannot answer those.
I had already built content automation in n8n and could have done it again. I went agentic instead, for a reason worth being precise about: the fragility. A single upstream API problem takes an n8n workflow down and the whole chain stops. For a system I wanted to leave alone for weeks, I wanted something that could handle a step going wrong without me watching it. The engine chains skills in sequence: research, planning, writing, scheduling, publishing, with a lot of steps in between.
The most important setting is the throttle. It publishes a few posts a day and no more. Everything about the tooling would let me publish hundreds, and that is exactly the behaviour Google has spent 2 years learning to catch. The other control that matters at this scale is cannibalization: adding hundreds of articles on top of 2,700 templated pages in one narrow vertical is the fastest way to make a site compete with itself. So every piece is checked against what already ranks before it is written rather than after it underperforms. First post shipped 26 April 2026.
One article the engine wrote, end to end
Where it is now
The site runs at 3,900 monthly sessions and 207,000 monthly search impressions. Impressions compounded at roughly 40% a month from April to July 2026, the 3 months after the first post. Authority Score sits at 20, up from nothing.
The Search Console chart shows what happened better than any single number does. Impressions sat near zero through most of 2025, climbed slowly after the rebuild, then turned sharply upward in the weeks after the first post went out. Across the full range that is 965,000 impressions and 6,020 clicks.
The average position is 12.6 and the click-through rate is 0.6%. Both are what a site looks like just after it becomes visible: most of those impressions sit on page 2, where almost nobody clicks. Tracked visibility is 1%, 1 keyword sits in the top 3, and referring domains are down 3% over the quarter. That is the same story rather than a different one: a directory 3 months into publishing, with most of its visibility still on page 2 and a link profile that is still thin. The keyword in position 1 is "how much does a pedicure cost", which is exactly the kind of question a catalogue could never answer on its own.
What the AI channel is doing
Close to 15% of sessions now arrive from AI assistants rather than from a search results page. In the last 28 days every one of those sessions came from ChatGPT. Semrush tells the same story from the other side: 98 mentions and 499 cited pages across the assistants, and 493 of those citations are ChatGPT. That channel did not meaningfully exist when this started, and it rewards exactly the kind of specific, structured content that answers the question a person actually typed.
The number I did not expect sits on the AI side. In the answers where the directory appears at all, Semrush counts fresha.com cited 42 times, salonsindubai.ae 34, and google.com 27. Being cited nearly as often as the biggest booking platform in the market, in a channel where the citation is the visibility, is the part I would not have predicted at the start.
What I would do differently now
I would build it end to end myself. The fix came out of reading the whole surface at once with AI, and I have kept going that way since. The repairs, the improvements and the new features on this site are mine, with nobody else in the loop. Design is the exception, and I would rather be straight about it than pretend otherwise. It is where I am weakest, AI gets me to something respectable, and a good designer or UX person still beats it.
What transfers
Eight months of repairs, each one fixing a symptom and introducing another, then reading the whole templated surface at once found it in a single pass.
A defect that repeats across 2,700 near-identical pages is invisible file by file, because every file looks correct on its own. The unit you debug in has to match the unit the defect lives in, and on a templated site that unit is the template.