Case Studies

How Aesthetic Clinics Use AI to Increase Sales: Inside Partner Wzrostu's Growth Engine

I build the software behind Partner Wzrostu, a Polish agency for aesthetic clinics. Here is how their per-ad revenue attribution really works, and what it caught that Meta never would.

Spend to revenue
P&L per ad creative
14 days
Cohort maturity before verdicts
15 live funnels
Quiz + booking landers
Multi-tenant RLS
One platform, isolated clinics

I run Coldabry, and for the past while the biggest thing on my plate has been the software behind Partner Wzrostu, a Polish agency that gets clients for aesthetic medicine clinics and beauty salons. Their pitch to clinics is simple: we don't just run your ads, we run the whole machine. Ads, funnels, CRM, SMS, deposits, all of it. The CRM part is a platform called Palyri, and that's the part we build.

Partner Wzrostu landing page: a system for acquiring premium clients for aesthetic clinics in Poland
The promise clinics buy: predictable bookings, deposits that hold, and software that makes sure people actually show up. Everything below is what has to be true underneath for that sentence to survive contact with reality.

I wanted to write down how the AI side of it actually works, because most articles about "AI for clinics" are written by people who have never had to explain to a clinic owner why her cheapest leads never pick up the phone. I have. It's an awkward conversation.

The cheapest lead is usually the worst one

If you run Meta ads for a clinic, the dashboard gives you impressions, clicks and cost per lead. And cost per lead feels like the number that matters, so everyone optimizes it.

But a lead in this business is just a phone number. Someone still has to call it, book the visit, get a deposit, send the reminders, and hope the person actually shows up. Every step loses people. And here's what took me embarrassingly long to see in the data: the losses are not spread evenly across ads. Some creatives attract people who book and show up. Others attract people who fill out a form on the couch at 11pm and never answer the phone again.

Meta can't see any of that, because it all happens after the click, inside the CRM. So we built the missing half. Partner Wzrostu wrote about the economics of this in Polish, in their piece on what a premium client actually costs, and the software is basically that article turned into code.

The only ad metric I trust anymore is what a creative puts on the treatment chair. Everything before that is a guess.

ADS MANAGER VIEW cost per lead PALYRI VIEW cost per booked visit, same two creatives Creative A similar Creative B similar Verdict on CPL alone: no difference worth acting on. Creative A PLN 250 Creative B PLN 686 Verdict on bookings: 2.7x gap hidden by CPL.
Real numbers from one clinic account, rounded and anonymized. Two creatives that look interchangeable on cost per lead, and one of them books visits at 2.7x the cost of the other.

A profit and loss statement for every ad

So the core feature is boring to describe: one table, one row per ad creative. Spend, leads, bookings, visits, revenue, and a verdict. Scale it, watch it, kill it, or "too early to tell". The clinic sees it right in their panel. That's it. Getting that table to tell the truth is where all the work went, and a few of those lessons cost us real money to learn.

The first one was attribution over time. A lead in aesthetic medicine can convert three weeks after clicking the ad. If you count revenue by the date of the sale, this month's creative gets credit for last month's leads and the numbers look great while being wrong. So we count everything by cohort: an ad owns the leads it generated and whatever revenue those leads ever bring, whenever it lands. The annoying side effect is that a fresh creative always looks like it's losing money, because its revenue hasn't arrived yet. We had to teach the system patience: verdicts wait until a cohort is two weeks old with enough leads, and until then it literally says "too early" instead of pretending to know.

The second one surprised me: Meta duplicates your ads. Same creative, six different ad IDs across ad sets. We found this in production. If you evaluate by ad ID, one good creative looks like six mediocre ones. We group by the creative itself now and keep the IDs underneath for debugging.

The third one is my favorite, because it stopped a genuinely bad decision. One account showed four quiz ads with around 7,000 clicks and about PLN 4,300 spent, and zero leads attributed. Every rule we had said: dead creatives, turn them off. Except the leads existed. They were sitting in the CRM without an ad ID, because the links in those ads weren't passing it. The ads were fine. The tracking was broken. After that one, we added a separate verdict: lots of clicks plus zero attributed leads doesn't mean "kill the ad", it means "check your tracking". I'd rather the system admit it can't see than confidently point at the wrong ad.

Then averages started lying to us in a new way. A creative had a clean "scale it" verdict, and when we split it by ad set, it turned out one ad set was booking visits at PLN 47 and the other at PLN 226, on almost identical budgets. Same ad, same numbers on top, two completely different businesses underneath. The same breakdown once caught a campaign spending PLN 710 of one clinic's money on ad sets targeting a different city. No average would ever have shown either.

And finally, burnout. A creative can look healthy on the month while dying this week. We now compare the last few days against the few days before, and it catches things like a cost per lead going from PLN 81 to PLN 294 while the click-through rate sits flat around 2.6 percent. Flat CTR, tripled CPL. On a 30-day average that ad looked completely fine.

What actually feeds the numbers

None of the above works if the data path from click to chair is leaky. On the capture side, clinics don't send ad traffic to a generic contact form. They use quiz funnels we host, 15 of them live across clinics right now, which qualify people a bit before asking for a phone number.

Meta ad link carries ad_id + campaign_id Quiz funnel qualifies intent + consent CRM lead ad ID verified per clinic SMS + deposit booking backed by prepayment Visit + outcome showed / no-show recorded Revenue joined to spend per-creative P&L updates
The path from click to attributed revenue. Everything writes into the same database, so nobody reconciles spreadsheets at the end of the month.

One detail here I'm a bit paranoid about, and I think rightly: the funnel reads the ad and campaign IDs from the URL, and URLs can be pasted by anyone with anything in them. So before an ID gets attached to a lead, we check it against the ads we've actually synced from that specific clinic's own Meta account. Several clinics share this platform. The nightmare scenario is one clinic's leads landing in another clinic's stats because somebody shared a link. That check makes it impossible, and it costs us one lookup.

The other thing that changed clinic economics more than any targeting trick: deposits. No-shows are the silent tax of this industry, and the booking flow is built around prepaid appointments with SMS confirmations. Partner Wzrostu has a whole Polish guide on no-shows and deposits if you want the operational side. From where I sit, a paid deposit is also the most reliable signal in the whole pipeline. People lie on forms. They don't lie with a blik transfer.

Nobody opens dashboards, so we stopped expecting them to

Early on I noticed clinic owners weren't logging in. Not because the product was bad, but because they're injecting lips at 7pm, not refreshing analytics. So the information goes to them instead.

Every morning the platform sends each clinic a Telegram digest: yesterday's leads and what happened to them, bookings, sales, how fast the team reacted to new leads, which SMS conversations are hanging without a reply, and a warning if the prepaid balance is running low. There's a weekly email version too. Nobody has to remember to check anything.

Inside the panel, a suggestion queue does the follow-up thinking. It watches for two patterns: leads that were called, didn't answer and nobody scheduled a retry, and patients whose first visit was more than two weeks ago with no second appointment. Those come out as a call list sorted coldest first, so the receptionist doesn't have to build filters, she just calls from the top. Anything you act on drops off the list. Anything you dismiss can be undone, because people misclick.

And the feature I ended up liking most is the least glamorous: the system telling clinics their own data is bad. At one point a big share of bookings in an account had no recorded outcome. Nobody had marked whether the patient showed up or not. Which means visits were undercounted, revenue per creative read low, and the verdicts were quietly too pessimistic. We could have hidden that. Instead it's the first line above the table, in plain words, because it undermines everything under it and the fix is a habit at the front desk, not code. The software's job there is just to say it out loud.

The stack, briefly

Postgres (Supabase) row-level security per clinic SQL RPCs for attribution math Next.js app clinic panel + agency panel Meta Graph API sync spend, ads, creatives Embedded funnels quiz + booking landers Messaging SMS + Telegram digests Scheduled jobs pulse, reminders, sync
One multi-tenant platform. Every integration writes into the same row-level-secured Postgres, and the attribution math runs as SQL next to the data.

Next.js on top, Supabase Postgres underneath, row-level security keyed to the clinic so everyone shares one codebase without ever seeing each other's rows. The attribution math is a single Postgres function, not JavaScript, because joining every złoty of spend to every lead an ad ever produced is a set operation and doing it in app code was slow the one time I tried. Meta sync is deliberately forgiving: if a token can't fetch ad thumbnails, it logs it and moves on, because a missing permission must not kill the whole nightly sync. And the definition of "booked", "showed" and "sold" lives in exactly one place, mirrored between the UI and the SQL, after I learned the hard way that two definitions of the same word will eventually disagree in front of a client.

One more thing I'd call engineering rather than translation: Polish. Currency grouping, plural forms, CSV files that open correctly in Polish Excel with commas as decimals. Clinic staff drop a tool the first time a number looks weird, and I don't blame them.

The first production leads went through in March 2026. Since then it's been hundreds of ad-attributed leads and tens of thousands of złoty in tracked Meta spend across live clinic accounts, and every new clinic gets the whole thing on day one: funnels, attribution, digests, the call queue, provisioned automatically.

Why bother

Most agencies stop at the ad account, because everything after the click is somebody else's software. Partner Wzrostu made the opposite bet: own the whole path from creative to chair and let the software enforce the method. The loop this creates is the actual advantage. Media buyers hit an attribution gap and file it as a bug to me. I find a data-quality problem and it becomes a warning in the product. The next clinic inherits both fixes without knowing either ever existed.

If you run an aesthetic clinic or beauty salon in Poland and want the whole system, agency plus software, look at Partner Wzrostu's offer. If you're in a different industry and want this kind of revenue attribution built around your own operations, that's what we do at Coldabry. I've written about the broader platform in the patient acquisition case study. This piece is what happened when we pointed it at the one question every advertiser avoids: which ad actually makes money.

case studyaimeta adsaesthetic clinicsattribution
Work with us →