A catalogue of every way the concierge can be launched from the studio website, plus the exact link formats for advertising traffic. Each pattern below is live — press the buttons — and ships with the snippet to paste into a Divi Code module.
Deliberately drawn as a wireframe rather than a copy of the real page, so attention stays on where the concierge attaches and how it behaves, not on styling. Grey blocks stand in for whatever content already lives there.
Six ways to invoke the concierge, from least to most intrusive. They are not exclusive — a real page would likely use two or three.
The CTA links straight to the concierge. Simplest possible integration.
<a class="et_pb_button" href="https://oyf.concierge.rodawi.com/?utm_source=studio_site&utm_medium=web&utm_content=trial_section"> Build my trial → </a>
A preamble that sits in the page and does the selling: what the trial actually is, why it is low-risk, and an invitation to build it. One button, straight into the concierge — which asks for their details as its first step. Styled to match the concierge so the handoff feels continuous.
Come try us
Tell us how you like to move and we'll put together a first week that actually fits your schedule — then book it for you.
Takes about two minutes. No card needed to look.
step_view: contact,
so if that gap is large we will see it rather than guess.data-days / data-price to match.<!-- Paste into a Divi Code module. Self-contained: scoped .oyfp- classes, no external CSS or fonts, nothing that can collide with the theme. --> <style> .oyfp{--a:#146DAE;--ad:#17477E;--as:#e3eef8;--ink:#152a44;--soft:#5b6f88;--faint:#93a4bb; --line:#dbe5f0;--pos:#4CB748;max-width:560px;margin:0 auto;background:#fff;border:1px solid var(--line); border-radius:16px;padding:30px 26px;text-align:center; font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,Roboto,sans-serif;color:var(--ink); box-shadow:0 1px 2px rgba(21,42,68,.05),0 12px 34px -12px rgba(20,109,174,.22)} .oyfp-logo{display:block;width:168px;max-width:60%;height:auto;margin:0 auto 14px} .oyfp-chip{display:inline-flex;align-items:center;gap:8px;background:#f5f8fc;border:1px solid var(--line); border-radius:100px;padding:7px 15px;font-size:.86rem;color:var(--soft);margin-bottom:18px} .oyfp-chip svg{width:14px;height:14px;color:var(--a);flex:none} .oyfp-chip b{color:var(--ink);font-weight:600} /* The artwork is white text on a TRANSPARENT background — it is drawn to sit on the dark photo section of the studio page. On a white card it needs a dark block of its own. */ .oyfp-herobox{background:linear-gradient(155deg,#17477E,#0f2f56);border-radius:12px; padding:10px 14px;margin:0 0 18px} .oyfp-hero{display:block;width:100%;height:auto} .oyfp-eyebrow{font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--a); font-weight:700;margin:0 0 6px} .oyfp-h{font-family:"Charter","Iowan Old Style",Georgia,serif;font-size:1.8rem;line-height:1.2; font-weight:600;margin:0 0 10px} .oyfp-lede{color:var(--soft);margin:0 auto 18px;max-width:44ch;line-height:1.55} .oyfp-offer{display:inline-flex;gap:10px;align-items:center;background:var(--as);border-radius:100px; padding:9px 20px;font-size:.95rem;margin-bottom:18px} .oyfp-offer .amt{font-weight:700;color:var(--ad)} .oyfp-offer .dot{color:var(--faint)} .oyfp-list{list-style:none;padding:0;margin:0 auto 22px;max-width:42ch;text-align:left} .oyfp-list li{position:relative;padding-left:26px;margin-bottom:9px;color:var(--soft);line-height:1.5} .oyfp-list li:before{content:"";position:absolute;left:0;top:.45em;width:14px;height:8px; border-left:2px solid var(--pos);border-bottom:2px solid var(--pos);transform:rotate(-45deg)} .oyfp-cta{display:inline-block;font:inherit;font-weight:600;font-size:1.02rem;border:0;border-radius:100px; padding:15px 32px;background:var(--a);color:#fff;cursor:pointer;text-decoration:none} .oyfp-cta:hover{background:var(--ad)} .oyfp-fine{font-size:.82rem;color:var(--faint);margin:12px 0 0} </style> <div class="oyfp"> <!-- swap the src for the site's own logo asset if you prefer --> <img class="oyfp-logo" src="https://oyf.concierge.rodawi.com/logo.png" alt="Oxygen Yoga & Fitness"> <div class="oyfp-chip"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 10c0 7-9 13-9 13S3 17 3 10a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg> Your trial at <b id="oyfp-studio">Oxygen Yoga & Fitness · Yonge & St Clair</b> </div> <!-- The studio's own offer artwork. data-days / data-price MUST match what the image says — the script below hides it if Mindbody ever disagrees. --> <div class="oyfp-herobox" id="oyfp-herobox"> <img class="oyfp-hero" id="oyfp-hero" data-days="14" data-price="30" src="https://oxygenyogaandfitness.com/wp-content/uploads/2026/08/Intro-Offer-Images-2.png" alt="14 days for only $30 — new members only"> </div> <p class="oyfp-eyebrow">Come try us</p> <h2 class="oyfp-h">Let's build your trial together.</h2> <p class="oyfp-lede">Tell us how you like to move and we'll put together a first week that actually fits your schedule — then book it for you.</p> <!-- fallback: only shown if the artwork above goes out of date --> <div class="oyfp-offer" id="oyfp-offer" hidden> <span class="amt" id="oyfp-days">14 days</span><span class="dot">·</span> <span id="oyfp-classes">unlimited classes</span><span class="dot">·</span> <span class="amt" id="oyfp-price">$30</span> </div> <ul class="oyfp-list"> <li>Take as many classes as you like — every style, every level</li> <li>Your 14 days start on your <b>first class</b>, not the day you pay</li> <li>We pick the classes with you and hold your spots</li> <li>No commitment when it ends</li> </ul> <a class="oyfp-cta" href="https://oyf.concierge.rodawi.com/?utm_source=studio_site&utm_medium=web&utm_content=trial_panel"> Build my trial → </a> <p class="oyfp-fine">Takes about two minutes. No card needed to look.</p> </div> <script> // Offer terms come from Mindbody, so the page never advertises a stale price. // Falls back to whatever is typed above if the call fails. fetch("https://oyf.concierge.rodawi.com/api/config") .then(function(r){ return r.json(); }) .then(function(c){ if (!c.offer) return; var o = c.offer; // The chip names the studio the concierge is actually wired to. If this panel is ever // pasted on another studio's page it will visibly say the wrong one — which is the // point: better an obvious mismatch than silently building the wrong studio's trial. if (c.studio) document.getElementById("oyfp-studio").textContent = "Oxygen Yoga & Fitness · " + c.studio; if (o.days) document.getElementById("oyfp-days").textContent = o.days + " days"; if (o.price) document.getElementById("oyfp-price").textContent = "$" + o.price; document.getElementById("oyfp-classes").textContent = o.unlimited ? "unlimited classes" : o.count + " classes"; // The artwork has "14 Days" and "$30" baked into the pixels. If the studio ever // changes the offer in Mindbody, hide the image and show the live text instead — a // stale price on a marketing graphic is worse than a plain line that is correct. // (Then replace the image and update data-days / data-price.) var hero = document.getElementById("oyfp-hero"); var strip = document.getElementById("oyfp-offer"); var stale = (o.days && String(o.days) !== hero.dataset.days) || (o.price && String(o.price) !== hero.dataset.price); if (stale) { document.getElementById("oyfp-herobox").hidden = true; strip.hidden = false; } }) .catch(function(){}); </script>
Keeps the visitor on the studio site. Falls back to a full-page redirect on phones, where modal iframes are cramped.
<!-- 1. the trigger (use anywhere) --> <button class="et_pb_button" onclick="oyfConcierge()">Start my trial</button> <!-- 2. paste ONCE per page, in a Code module --> <div id="oyf-modal" style="position:fixed;inset:0;z-index:9999;background:rgba(20,24,28,.6); display:none;align-items:center;justify-content:center;padding:18px"> <div style="background:#fff;border-radius:14px;width:100%;max-width:460px; height:min(86vh,760px);overflow:hidden;position:relative"> <button onclick="oyfClose()" aria-label="Close" style="position:absolute;top:9px;right:11px; z-index:2;width:30px;height:30px;border-radius:50%;border:1px solid #ddd;background:#fff; cursor:pointer">×</button> <iframe id="oyf-frame" title="Build your trial" style="width:100%;height:100%;border:0"></iframe> </div> </div> <script> var OYF_URL = "https://oyf.concierge.rodawi.com/?utm_source=studio_site&utm_medium=web&utm_content=modal"; function oyfConcierge(){ // phones get the full page — a modal iframe is too cramped. // guard on >0: some contexts report width 0, and we would rather show the // modal than navigate the visitor away on a value we cannot trust. var w = window.innerWidth; if (w > 0 && w < 768) { window.location.href = OYF_URL; return; } document.getElementById("oyf-frame").src = OYF_URL; document.getElementById("oyf-modal").style.display = "flex"; document.body.style.overflow = "hidden"; } function oyfClose(){ document.getElementById("oyf-modal").style.display = "none"; // about:blank, not "" — an empty src resolves to the current page and keeps running document.getElementById("oyf-frame").src = "about:blank"; document.body.style.overflow = ""; } document.addEventListener("keydown", function(e){ if(e.key === "Escape") oyfClose(); }); </script>
The healcode-widget type="prospects" in the #form section is today's
lead-capture surface. The concierge captures the same details and builds them a trial.
Remove: <healcode-widget data-type="prospects" ... ></healcode-widget> Replace with pattern 1, 2 or 3, using: ?utm_source=studio_site&utm_medium=web&utm_content=prospect_form
A persistent tab that follows the visitor down the page. Catches people who scrolled past the intro-offer section.
<button onclick="oyfConcierge()" style="position:fixed;right:16px;bottom:16px;z-index:9998;
border:0;border-radius:100px;padding:12px 20px;font-weight:600;cursor:pointer;
background:#2f6db3;color:#fff;box-shadow:0 6px 18px rgba(0,0,0,.25)">
Build my trial
</button>
(uses the same oyfConcierge() from pattern 3)
A menu item, for visitors who arrive looking for exactly this.
Divi → Menu → add a Custom Link: URL: https://oyf.concierge.rodawi.com/?utm_source=studio_site&utm_medium=web&utm_content=nav Text: Start a trial
These are the links to hand to Derek. The parameters are what make the pilot measurable — without them we cannot tell which ad produced which trial.
The ad links straight here. The concierge is the only place the lead can be captured, so abandoned sessions are recorded on our side.
https://oyf.concierge.rodawi.com/?utm_source=meta&utm_medium=traffic&utm_campaign=ysc_trial_sep&utm_content=AD_NAME
Meta captures the details in the ad. GoHighLevel then sends the follow-up message — today that starts the Sophia interaction; for the pilot it invites them here instead.
Follow-up SMS / email link: https://oyf.concierge.rodawi.com/?utm_source=meta&utm_medium=leadform&utm_campaign=ysc_trial_sep&utm_content=AD_NAME Suggested message copy — direct, no "Sophia" framing: Thanks for your interest in Oxygen Yoga & Fitness Yonge & St Clair! Build your 14-day trial and pick your first classes here: <link>
| Parameter | Purpose | Values |
|---|---|---|
utm_source | Where the click came from | meta, studio_site, google |
utm_medium | Which stream — this is the comparison the pilot measures | traffic, leadform, web |
utm_campaign | Groups a flight of ads | ysc_trial_sep |
utm_content | The individual ad or placement | your ad name |
The studio site runs WordPress with Divi 4.27.8. Every snippet above goes into a Code module (Divi Builder → Insert Module → Code), except pattern 6 which is a menu item and pattern 1 which can be an ordinary Button module with the URL set.
The studio page already loads Mindbody's healcode.js for its pricing, prospect and
gift-card widgets. The concierge also uses Branded Web for payment. Running both in one document could
conflict — which is an argument for the iframe patterns: an iframe is a separate document, so the two
copies never meet. Pattern 1 sidesteps it entirely by leaving the page.
Payment completes on Mindbody's own checkout, which then messages the page to say it is done — that message is what triggers the class booking. Inside an iframe, that message may be delivered to the studio page rather than to the concierge, which would take the payment and never book the classes.
This is being tested from this page with a real purchase before any iframe pattern is recommended for production. If it fails, the fix is either a few lines on the studio page forwarding the message down, or using pattern 1 for the payment step. Pattern 1 is unaffected and is safe today.