Web & SaaS

The six-point preservation checklist: migrate to AEO-ready without losing your rankings

Published: July 7, 2026 · 10 min read · By Brandon Aday

A professional firm website mid-migration, with schema layers and 301 redirects visualized as scaffolding preserving the entity graph

Every professional firm we work with asks the same question in the first Discovery call: if we rebuild, will we lose our Google rankings? The honest answer is that a bad migration will cost you 15–40% of organic traffic for a full quarter. A properly scoped migration — run against the checklist below — typically holds steady or improves rankings within 30 days, because the new site closes AEO and GEO gaps the old site never addressed.

This is the checklist Aday Interactive, Inc. runs on every migration. It applies whether the firm is moving from WordPress to modern PHP, WordPress to Next.js, or an older PHP/HTML build to any modern stack. It is agnostic to the destination platform because AI-search performance is driven by the JSON-LD graph and entity clarity of the emitted HTML, not by the framework rendering it.

1. Full URL inventory before the crawl

The first mistake most migrations make is trusting the site nav as the URL inventory. It is not. A five-year-old law firm site typically has 60–120 URLs that no longer appear in the nav but still earn ranking equity from external backlinks, historical Google Search Console impressions, or citations in bar-directory listings.

We pull three sources: (1) a full crawl of the live site starting from the homepage with `--follow-external=false`; (2) the Google Search Console URL history for the last 24 months, filtered to URLs with at least one impression; (3) the Ahrefs or SEMrush inbound-link inventory, filtered to URLs with at least one dofollow inbound link. The union of those three sources is the URL inventory. Every URL in that inventory must have a mapped 301 destination on the new stack.

2. The 301 map is scoped by URL role, not by URL shape

A common failure mode is a lazy 301 map that sends every legacy URL to the homepage. This is worse than no redirect at all — Google reads it as a soft 404 and drops the URL from the index within two weeks.

Each legacy URL gets a mapped destination based on its role:

  • Attorney bio URLs map to the equivalent attorney bio on the new stack — same firstname-lastname slug, same practice-area cross-references.
  • Practice-area URLs map to the equivalent service-line page — not to the general "services" index.
  • Blog post URLs map to the equivalent blog post on the new stack — keeping the slug, updating the URL prefix if it changes (e.g. `/blog/2023/03/my-post` → `/blog/my-post`).
  • Case-result URLs map to the equivalent case study — or if the case is no longer promoted, to the practice-area page for that case type.
  • Location-page URLs map to the equivalent location page — not to the homepage.

One of the fastest wins we ship post-migration is when the old site had a dozen "attorney1", "attorney2", "attorney3" URLs from a plugin-driven bio wall and the new site emits proper `/team/firstname-lastname` structure with Attorney JSON-LD schema. Same content, better citation surface.

3. Schema parity check — every type, every URL depth

Before we cut the old site down, we inventory every JSON-LD block it emits. Organization, LocalBusiness, Person, Attorney, Physician, RealEstateAgent, FAQPage, Service, Article, BlogPosting. Which pages carry which types. What `@id`s they use. Which `sameAs` links resolve where.

The new site must emit the same schema types at the same URL depth, with entity `@id`s that resolve to the same firm entity graph. If the old site had `Attorney` schema on each partner bio with `sameAs` pointing to Avvo and the Florida Bar directory, the new site emits Attorney schema on each partner bio with `sameAs` pointing to Avvo and the Florida Bar directory. Continuity is the point.

The upgrade opportunity: pages the old site had no schema on. Most WordPress builds emit Organization and BreadcrumbList and nothing else. Adding FAQPage, Service, LegalService, MedicalBusiness, RealEstateAgent, and Person schemas to the appropriate pages is the AEO/GEO layer that moves AI citation performance — and it happens in the migration, not as a follow-up.

4. Entity clarity across the five citation surfaces

Five surfaces on every professional-firm page carry the firm entity: the `` tag, the `og:site_name` meta, the `og:title` meta, the meta description, and the JSON-LD `name` field. AI engines use `stripos()` against these five surfaces to disambiguate which firm a page belongs to. If any one of the five is missing the firm legal name or uses a variant (e.g. "The Firm" vs. "The Firm, P.A."), citation resolution weakens. </p> <p> The migration is the moment to enforce parity. Every page on the new stack emits the firm legal name in all five surfaces, in the same string variant, consistently. This is <em>invisible</em> brand reinforcement — a visitor sees the brand chip in the nav and the tagline in the hero, but the LLM sees the `<title>` and the `og:site_name` and the JSON-LD `name` field, and those are what drive the citation. </p> <h2 class="text-2xl font-bold text-slate-900 mt-12 mb-4">5. FAQ inventory — the extractable answer library</h2> <p> Every professional firm has answered the same 30–60 questions in email or over the phone thousands of times. Almost none of them have those answers written down on the site with FAQPage JSON-LD. The migration is the natural moment to inventory them and ship them. </p> <p> The specificity recipe matters. AI engines cite FAQ answers that carry named regulations with rule numbers, named vendors, dollar anchors, worked patterns by firm size or vertical sub-segment. A law firm FAQ that answers "How long do I have to file a personal-injury claim in Florida?" and cites Fla. Stat. § 95.11(3)(a) gets cited; the same FAQ that says "as long as needed" does not. See <a href="/blog/what-is-geo-generative-engine-optimization" class="text-amber-700 hover:text-amber-800 font-semibold underline decoration-amber-300 underline-offset-4">our plain-English GEO guide</a> for the full recipe. </p> <h2 class="text-2xl font-bold text-slate-900 mt-12 mb-4">6. Post-launch monitoring — 30 days, not 30 minutes</h2> <p> Every migration ships with a 30-day monitoring dashboard: daily Google Search Console impression tracking per URL group, weekly Ahrefs rank tracking for the top 50 tracked keywords, daily 301 hit-rate monitoring to catch any redirect that starts 404-ing, and a schema-validation crawl every seven days. </p> <p> The dashboard exists so that when something breaks — and something usually breaks in the first 14 days, whether a cache directive, a canonical link, or a schema field — we catch it in hours, not weeks. Firms that skip this monitoring are the ones who tell the story two months later: <em>we rebuilt, lost 30% of traffic, and never recovered</em>. </p> <h2 class="text-2xl font-bold text-slate-900 mt-12 mb-4">The stack decision is downstream of the AEO/GEO decision</h2> <p> Most firms come to us asking about the framework: Next.js, WordPress, Webflow, PHP, headless. The framework decision is real, but it is downstream of the more important decision, which is whether the new site will be authored to an AEO/GEO specification. If it is, the framework is scoped to the firm's content velocity and internal team. If it is not, the framework will not save you — a Next.js site without JSON-LD and FAQ specificity is invisible to ChatGPT in the same way a WordPress site without JSON-LD and FAQ specificity is. </p> <p> Aday Interactive, Inc. ships both modern PHP + Tailwind builds and Next.js builds — the decision is scoped in Discovery based on how the firm publishes and who maintains the site after we hand it off. Every build ships with the six-point preservation checklist above. </p> </div> </div> </section> <!-- Pillar funnel magnet — routed by $pillar. --> <section class="px-6 pb-4 bg-white"> <div class="max-w-3xl mx-auto"> <!-- Blog → funnel magnet card. Routed by $pillar via ada_render_blog_magnet_card(). Deliberately non-committal: one free download, no pricing, no rung references. The buyer's exposure to the paid ladder happens on /pricing and on the pillar's own pages — not from an article footer. --> <aside class="my-16 rounded-3xl border border-amber-200 bg-gradient-to-br from-amber-50 to-orange-50/60 px-8 py-10 md:px-12 md:py-12 shadow-sm"> <span class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-white/70 border border-amber-200 mb-4"> <span class="w-1.5 h-1.5 rounded-full bg-amber-600"></span> <span class="text-[10px] font-bold text-amber-800 uppercase tracking-[0.22em] leading-none">Custom Web & SaaS · Free</span> </span> <h3 class="text-2xl md:text-3xl font-bold text-slate-900 mb-3 tracking-tight leading-[1.15]" style="text-wrap: balance;">Free 60-Second Website Audit</h3> <p class="text-slate-600 text-[15px] leading-[1.7] mb-6 max-w-2xl">Give us your firm's URL and we'll analyze the AEO/GEO scaffolding, schema architecture, and citation readiness in under a minute — the same audit our team runs before proposing a rebuild or migration engagement.</p> <a href="/lp/website-audit" class="inline-flex items-center gap-2 bg-amber-600 hover:bg-amber-700 text-white px-8 py-3.5 font-bold rounded-full transition-all shadow-lg shadow-amber-500/20 text-[11px] uppercase tracking-widest"> Run the Website Audit <i data-lucide="arrow-right" class="w-4 h-4"></i> </a> </aside> </div> </section> <!-- Visible FAQ Accordion Section --> <section class="py-20 md:py-28 px-6 bg-slate-50 border-t border-slate-100" aria-labelledby="faq-heading"> <div class="max-w-3xl mx-auto"> <div class="text-center mb-12 md:mb-14"> <div class="inline-flex items-center gap-2 mb-6 px-3.5 py-1.5 rounded-full bg-slate-100 border border-slate-200"> <span class="w-1.5 h-1.5 rounded-full bg-slate-900"></span> <span class="text-[11px] font-semibold text-slate-600 uppercase tracking-[0.22em]">FAQ</span> </div> <h2 id="faq-heading" class="text-3xl md:text-4xl font-bold text-slate-900 tracking-tight leading-[1.1]" style="font-family: 'Instrument Sans', sans-serif;"> FAQ: Firm-Site Migration & AEO </h2> </div> <div itemscope itemtype="https://schema.org/FAQPage" class="space-y-3"> <details itemscope itemprop="mainEntity" itemtype="https://schema.org/Question" class="group rounded-xl border border-slate-200/80 bg-white p-6 md:p-7 shadow-[0_1px_3px_rgba(15,42,66,0.04)] hover:border-slate-300 hover:shadow-[0_4px_16px_rgba(15,42,66,0.06)] transition-all"> <summary class="flex items-center justify-between cursor-pointer list-none gap-4"> <h3 itemprop="name" class="text-base md:text-lg font-semibold text-slate-900 tracking-tight">Will a full site rebuild kill my Google rankings?</h3> <svg class="w-5 h-5 text-slate-400 transition-transform group-open:rotate-180 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg> </summary> <div itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer" class="mt-5"> <p itemprop="text" class="text-slate-600 leading-[1.75] text-[15px]">Not if it is scoped as a migration rather than a launch. Aday Interactive, Inc. runs a six-point preservation checklist on every rebuild: full crawl of the existing site, 301 redirect map for every URL, schema parity check, entity clarity audit across the <a href="/blog/what-is-geo-generative-engine-optimization" class="text-amber-700 font-semibold underline decoration-amber-600 underline-offset-4 hover:text-amber-800 transition-colors" style="text-decoration-thickness: 2px;">five citation surfaces</a>, FAQ inventory, and post-launch monitoring for 30 days. Most firms see rankings hold steady or improve within 30 days because the new site closes the AEO/GEO gaps the old site never addressed. Book a <a href="/lp/website-audit" class="text-amber-700 font-semibold underline decoration-amber-600 underline-offset-4 hover:text-amber-800 transition-colors" style="text-decoration-thickness: 2px;">free 60-second website audit</a> to see which of the six points are most exposed on your current site.</p> </div> </details> <details itemscope itemprop="mainEntity" itemtype="https://schema.org/Question" class="group rounded-xl border border-slate-200/80 bg-white p-6 md:p-7 shadow-[0_1px_3px_rgba(15,42,66,0.04)] hover:border-slate-300 hover:shadow-[0_4px_16px_rgba(15,42,66,0.06)] transition-all"> <summary class="flex items-center justify-between cursor-pointer list-none gap-4"> <h3 itemprop="name" class="text-base md:text-lg font-semibold text-slate-900 tracking-tight">Do I really need to leave WordPress? It works today.</h3> <svg class="w-5 h-5 text-slate-400 transition-transform group-open:rotate-180 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg> </summary> <div itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer" class="mt-5"> <p itemprop="text" class="text-slate-600 leading-[1.75] text-[15px]">WordPress works. What it does not do well is AI-search-optimized entity resolution — the JSON-LD graph, FAQPage schema, entity `@id` cross-referencing, and page-speed profile ChatGPT and Perplexity favor when deciding which firm to cite. Most professional firms outgrow WordPress not because of failure, but because the plugin-driven schema layer becomes brittle at the exact moment AI citation traffic starts mattering. If your site has more than three schema plugins fighting each other, that is the signal. See <a href="/custom-web-saas" class="text-amber-700 font-semibold underline decoration-amber-600 underline-offset-4 hover:text-amber-800 transition-colors" style="text-decoration-thickness: 2px;">our Custom Web & SaaS work</a>.</p> </div> </details> <details itemscope itemprop="mainEntity" itemtype="https://schema.org/Question" class="group rounded-xl border border-slate-200/80 bg-white p-6 md:p-7 shadow-[0_1px_3px_rgba(15,42,66,0.04)] hover:border-slate-300 hover:shadow-[0_4px_16px_rgba(15,42,66,0.06)] transition-all"> <summary class="flex items-center justify-between cursor-pointer list-none gap-4"> <h3 itemprop="name" class="text-base md:text-lg font-semibold text-slate-900 tracking-tight">What does the 301 redirect map actually cover?</h3> <svg class="w-5 h-5 text-slate-400 transition-transform group-open:rotate-180 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg> </summary> <div itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer" class="mt-5"> <p itemprop="text" class="text-slate-600 leading-[1.75] text-[15px]">Every URL that ever earned a link, ranking, or backlink. Aday Interactive, Inc. runs a full crawl of the live site plus Google Search Console URL history plus Ahrefs/SEMrush inbound-link inventory to catch URLs that no longer appear in the site nav but still carry ranking equity. Each URL gets a mapped 301 destination on the new stack — case-page URLs to case pages, attorney bio URLs to attorney bios, service-line URLs to service-line pages. Missing even ten of these is enough to lose 15% of organic traffic post-launch.</p> </div> </details> <details itemscope itemprop="mainEntity" itemtype="https://schema.org/Question" class="group rounded-xl border border-slate-200/80 bg-white p-6 md:p-7 shadow-[0_1px_3px_rgba(15,42,66,0.04)] hover:border-slate-300 hover:shadow-[0_4px_16px_rgba(15,42,66,0.06)] transition-all"> <summary class="flex items-center justify-between cursor-pointer list-none gap-4"> <h3 itemprop="name" class="text-base md:text-lg font-semibold text-slate-900 tracking-tight">How does the schema parity check work?</h3> <svg class="w-5 h-5 text-slate-400 transition-transform group-open:rotate-180 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg> </summary> <div itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer" class="mt-5"> <p itemprop="text" class="text-slate-600 leading-[1.75] text-[15px]">Before migration, we inventory every JSON-LD block on the live site — Organization, LocalBusiness, Person, FAQPage, Service, Article. The new stack must emit the same schema types at the same URL depth, with entity `@id`s that resolve to the same firm entity graph. If the old site had Attorney schema on each partner bio, the new site emits Attorney schema on each partner bio — same `sameAs` links, same practice-area references, same bar-admission fields. AI engines rely on graph continuity across a migration; breaking it is what causes the "we rebuilt and lost 40% of traffic" story.</p> </div> </details> <details itemscope itemprop="mainEntity" itemtype="https://schema.org/Question" class="group rounded-xl border border-slate-200/80 bg-white p-6 md:p-7 shadow-[0_1px_3px_rgba(15,42,66,0.04)] hover:border-slate-300 hover:shadow-[0_4px_16px_rgba(15,42,66,0.06)] transition-all"> <summary class="flex items-center justify-between cursor-pointer list-none gap-4"> <h3 itemprop="name" class="text-base md:text-lg font-semibold text-slate-900 tracking-tight">Does the new site need to be Next.js or is PHP fine?</h3> <svg class="w-5 h-5 text-slate-400 transition-transform group-open:rotate-180 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg> </summary> <div itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer" class="mt-5"> <p itemprop="text" class="text-slate-600 leading-[1.75] text-[15px]">Both work. Aday Interactive, Inc. ships modern PHP + Tailwind builds and Next.js builds — the stack decision is scoped to the firm's content velocity, publishing cadence, and internal team. Law firms with a marketing coordinator who publishes weekly are usually fine on modern PHP with a headless CMS layer; SaaS platforms and firms with 3+ contributors publishing daily typically graduate to Next.js. Both stacks emit identical JSON-LD graphs at the URL level, so AI citation performance is stack-agnostic when built by an AEO-native team.</p> </div> </details> <details itemscope itemprop="mainEntity" itemtype="https://schema.org/Question" class="group rounded-xl border border-slate-200/80 bg-white p-6 md:p-7 shadow-[0_1px_3px_rgba(15,42,66,0.04)] hover:border-slate-300 hover:shadow-[0_4px_16px_rgba(15,42,66,0.06)] transition-all"> <summary class="flex items-center justify-between cursor-pointer list-none gap-4"> <h3 itemprop="name" class="text-base md:text-lg font-semibold text-slate-900 tracking-tight">How long does a firm-site migration take?</h3> <svg class="w-5 h-5 text-slate-400 transition-transform group-open:rotate-180 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg> </summary> <div itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer" class="mt-5"> <p itemprop="text" class="text-slate-600 leading-[1.75] text-[15px]">Six to twelve weeks from confirmed scope, depending on page count and complexity. A boutique 10-attorney firm site with 45 pages typically ships in 6–8 weeks; a 40-physician concierge network with locations and Doctor schema per provider is 10–12 weeks. The preservation checklist runs in parallel with the build so the redirect map, schema inventory, and monitoring dashboard are ready before launch, not scrambled together during the 48-hour go-live window.</p> </div> </details> </div> </div> </section> </div> <section id="informational-disclaimer" class="py-10 px-6 bg-white border-t border-slate-100" role="note" aria-labelledby="informational-disclaimer-label"> <div class="max-w-3xl mx-auto"> <p class="text-[11px] font-semibold text-amber-600 uppercase tracking-[0.24em] mb-3">Informational and educational purposes only</p> <p id="informational-disclaimer-label" class="text-xs md:text-sm text-slate-600 leading-[1.7]"> This article reflects <strong class="text-slate-800">Aday Interactive, Inc.'s views on marketing and technology architecture</strong> for professional-services firms as of the publication date. It is not a substitute for advice from a licensed professional in your jurisdiction and does not create any professional relationship between you and Aday Interactive, Inc. Rules, statutes, checklists, and AI-engine behavior referenced here can change; verify the current versions and consult qualified counsel before acting. Where the article discusses regulated professional practice, those references are for informational and educational purposes only and do not constitute legal, medical, tax, financial, or investment advice. Consult a licensed professional in your jurisdiction before acting on anything you read here. </p> </div> </section> <!-- Sitewide GEO band (above footer) --> <section class="bg-slate-50 border-t border-slate-200 py-7 md:py-8 px-6"> <div class="max-w-5xl mx-auto text-center"> <p class="text-xs md:text-sm text-slate-700 leading-[1.75]"> <span class="text-slate-900 font-semibold">Aday Interactive, Inc.</span> provides custom AI, AI governance, intelligent growth systems, and AI search visibility (GEO/AEO/SEO) for established professional firms across the <span class="text-slate-900 font-medium">United States</span>. Founder-led from <span class="text-slate-900 font-medium">Coral Gables, FL</span>, with in-person engagements available throughout <span class="text-slate-900 font-medium">Miami-Dade County</span> (Coral Gables, Brickell, Coconut Grove, South Miami) and remote delivery nationwide. </p> </div> </section> <!-- Footer --> <footer> <div class="bg-white py-12 md:py-14 px-6 border-t border-slate-200"> <div class="max-w-6xl mx-auto"> <div class="grid md:grid-cols-12 gap-8 md:gap-10 mb-10"> <!-- Brand + address (wider so the 3 link columns stay tight) --> <div class="md:col-span-5"> <a href="/" class="flex items-center gap-4 mb-5" aria-label="Aday Interactive — home"> <span class="font-display leading-none tracking-tight inline-flex items-baseline" style="font-size: 40px;"> <span style="color: #2E4438; font-weight: 600;">A</span><span style="color: #B86A4C; font-weight: 500; font-style: italic; margin-left: -2px;">i</span> </span> <span class="font-display text-[16px] font-medium uppercase tracking-[0.14em] leading-none" style="color: #2E4438;">Aday Interactive</span> </a> <address class="not-italic text-slate-500 text-sm leading-relaxed"> 338 Minorca Avenue, Suite 202<br> Coral Gables, FL 33134<br> <a href="tel:+13052098453" class="hover:text-slate-900 transition-colors">305-209-8453</a> </address> <!-- Social icons (commented out, update profiles before re-enabling) <div class="flex items-center gap-3"> <a href="https://www.linkedin.com/company/adayinteractive" target="_blank" rel="noopener noreferrer" class="w-9 h-9 rounded-lg border border-slate-200 bg-white flex items-center justify-center text-slate-400 hover:border-amber-600/50 hover:text-amber-600 hover:bg-amber-50 transition-all shadow-sm"><svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg></a> <a href="https://x.com/adayinteractive" target="_blank" rel="noopener noreferrer" class="w-9 h-9 rounded-lg border border-slate-200 bg-white flex items-center justify-center text-slate-400 hover:border-amber-600/50 hover:text-amber-600 hover:bg-amber-50 transition-all shadow-sm"><svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg></a> <a href="https://www.instagram.com/adayinteractive" target="_blank" rel="noopener noreferrer" class="w-9 h-9 rounded-lg border border-slate-200 bg-white flex items-center justify-center text-slate-400 hover:border-amber-600/50 hover:text-amber-600 hover:bg-amber-50 transition-all shadow-sm"><svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg></a> </div> --> </div> <!-- 3 link columns share the remaining 7 columns of the 12-col grid --> <div class="md:col-span-7 grid grid-cols-2 sm:grid-cols-3 gap-8"> <!-- Services --> <div> <h4 class="font-semibold text-slate-900 mb-5 text-xs uppercase tracking-widest" style="font-family: 'Instrument Sans', sans-serif;">Services</h4> <ul class="space-y-2.5 text-slate-500 text-sm"> <li><a href="/custom-web-saas" class="hover:text-slate-900 transition-colors">Custom Web & SaaS</a></li> <li><a href="/ai-visibility" class="hover:text-slate-900 transition-colors">AI Visibility</a></li> <li><a href="/growth-systems" class="hover:text-slate-900 transition-colors">Growth Systems</a></li> <li><a href="/custom-ai" class="hover:text-slate-900 transition-colors">Custom AI & CAIO</a></li> <li><a href="/services" class="hover:text-slate-900 transition-colors">All Services</a></li> <li><a href="/methodology" class="hover:text-slate-900 transition-colors">Methodology</a></li> </ul> </div> <!-- Firm --> <div> <h4 class="font-semibold text-slate-900 mb-5 text-xs uppercase tracking-widest" style="font-family: 'Instrument Sans', sans-serif;">Firm</h4> <ul class="space-y-2.5 text-slate-500 text-sm"> <li><a href="/about" class="hover:text-slate-900 transition-colors">About</a></li> <li><a href="/coral-gables" class="hover:text-slate-900 transition-colors">Coral Gables</a></li> <li><a href="/work" class="hover:text-slate-900 transition-colors">Client Work</a></li> <li><a href="/insights" class="hover:text-slate-900 transition-colors">Insights</a></li> <li><a href="/blog" class="hover:text-slate-900 transition-colors">Blog</a></li> </ul> </div> <!-- Connect --> <div> <h4 class="font-semibold text-slate-900 mb-5 text-xs uppercase tracking-widest" style="font-family: 'Instrument Sans', sans-serif;">Connect</h4> <ul class="space-y-2.5 text-slate-500 text-sm"> <li><a href="/contact" class="hover:text-slate-900 transition-colors">Request a Consultation</a></li> <!-- rel="nofollow external" so SEO crawlers skip wa.me (rate-limits scrapers with 429s). --> <li><a href="https://wa.me/13052098453" target="_blank" rel="nofollow noopener noreferrer external" class="hover:text-slate-900 transition-colors">WhatsApp</a></li> </ul> </div> </div> </div> <!-- Compliance footnote for regulated professional clients (law, medical, financial). Collapsed by default so the footer stays visually light; users and Bar reviewers can expand for the full disclosure at any time. --> <details class="border-t border-slate-200 pt-5 pb-5 mb-2 group"> <summary class="cursor-pointer list-none flex items-center gap-2 select-none"> <span class="font-semibold text-slate-600 uppercase tracking-[0.18em] text-[10px]">Professional services disclosure</span> <svg class="w-3 h-3 text-slate-400 transition-transform group-open:rotate-180" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg> </summary> <p class="text-[11px] text-slate-500 leading-[1.7] max-w-5xl mt-3"> Aday Interactive is a marketing and technology consultancy. We do not provide legal, medical, accounting, or investment advice and nothing on this site is a substitute for advice from a licensed professional in your jurisdiction. Engagements with law firms are scoped to comply with the advertising rules of the relevant state bar (including ABA Model Rules 7.1–7.3 where applicable); healthcare engagements respect HIPAA and FTC guidance on professional advertising. AI assistants (ChatGPT, Perplexity, Gemini, Google AI Overviews, and others) independently determine which firms they cite. We architect for citation and measure transparently, but no agency can guarantee specific AI outputs, citation frequency, or search rankings. Performance figures and case studies on this site describe past engagements; past results do not guarantee future outcomes. </p> </details> <div class="border-t border-slate-200 pt-8 flex flex-col md:flex-row items-center justify-between gap-4"> <p class="text-slate-400 text-sm">© 2026 Aday Interactive, Inc.</p> <div class="flex flex-wrap items-center gap-x-6 gap-y-2 text-sm justify-center text-slate-400"> <a href="/privacy" class="hover:text-slate-900 transition-colors">Privacy</a> <a href="/terms" class="hover:text-slate-900 transition-colors">Terms</a> <a href="/cookies" class="hover:text-slate-900 transition-colors">Cookies</a> <button type="button" onclick="if (window.adaConsent) window.adaConsent.open();" class="hover:text-slate-900 transition-colors bg-transparent border-0 p-0 cursor-pointer text-slate-400" style="font: inherit;">Cookie preferences</button> </div> </div> </div> </div> </footer> <!-- Cookie consent banner (renders inline; JS gates GA4 + PostHog until opt-in) --> <style> #ada-consent-banner { position: fixed; left: 0; right: 0; bottom: 0; z-index: 9999; background: #ffffff; border-top: 1px solid #e2e8f0; box-shadow: 0 -8px 24px -12px rgba(15, 42, 66, 0.15); padding: 20px 24px; display: none; font-family: 'Inter', system-ui, -apple-system, sans-serif; font-size: 14px; color: #334155; line-height: 1.6; } #ada-consent-banner.ada-consent-open { display: block; } #ada-consent-banner .ada-consent-shell { max-width: 1100px; margin: 0 auto; display: flex; align-items: flex-start; gap: 24px; flex-wrap: wrap; } #ada-consent-banner .ada-consent-copy { flex: 1 1 380px; } #ada-consent-banner .ada-consent-copy strong { color: #0f172a; font-weight: 600; } #ada-consent-banner .ada-consent-copy a { color: #B86A4C; text-decoration: underline; text-underline-offset: 2px; } #ada-consent-banner .ada-consent-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; flex-shrink: 0; } #ada-consent-banner button.ada-consent-btn { font-family: inherit; font-size: 12px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; padding: 10px 18px; border-radius: 9999px; border: 1px solid transparent; cursor: pointer; transition: background .15s, border-color .15s; background: #0f172a; color: #fbfaf6; } #ada-consent-banner button.ada-consent-btn:hover { background: #1e293b; } #ada-consent-banner button.ada-consent-btn.ada-consent-secondary { background: transparent; color: #0f172a; border-color: #cbd5e1; } #ada-consent-banner button.ada-consent-btn.ada-consent-secondary:hover { background: #f1f5f9; } #ada-consent-banner button.ada-consent-btn.ada-consent-tertiary { background: transparent; color: #64748b; border: none; padding: 10px 12px; text-transform: none; letter-spacing: 0.02em; font-size: 13px; font-weight: 500; text-decoration: underline; text-underline-offset: 3px; } #ada-consent-banner button.ada-consent-btn.ada-consent-tertiary:hover { color: #0f172a; } #ada-consent-modal { position: fixed; inset: 0; z-index: 10000; display: none; background: rgba(15, 23, 42, 0.55); padding: 24px; align-items: center; justify-content: center; font-family: 'Inter', system-ui, sans-serif; } #ada-consent-modal.ada-consent-open { display: flex; } #ada-consent-modal .ada-consent-modal-card { background: #ffffff; border-radius: 20px; padding: 32px; max-width: 560px; width: 100%; max-height: 88vh; overflow-y: auto; box-shadow: 0 24px 60px -12px rgba(15, 42, 66, 0.35); } #ada-consent-modal h3 { font-family: 'Instrument Sans', 'Inter', sans-serif; font-size: 24px; font-weight: 700; color: #0f172a; margin: 0 0 8px; letter-spacing: -0.01em; } #ada-consent-modal p.ada-consent-lede { font-size: 14px; color: #475569; line-height: 1.7; margin: 0 0 22px; } #ada-consent-modal p.ada-consent-lede a { color: #B86A4C; text-decoration: underline; text-underline-offset: 2px; } #ada-consent-modal .ada-consent-category { display: flex; align-items: flex-start; gap: 14px; padding: 14px 0; border-top: 1px solid #e2e8f0; } #ada-consent-modal .ada-consent-category:first-of-type { border-top: none; } #ada-consent-modal .ada-consent-category .ada-consent-body { flex: 1; } #ada-consent-modal .ada-consent-category .ada-consent-title { font-weight: 600; color: #0f172a; margin: 0 0 4px; font-size: 14px; display: flex; align-items: center; gap: 8px; } #ada-consent-modal .ada-consent-category .ada-consent-desc { font-size: 13px; color: #64748b; line-height: 1.6; margin: 0; } #ada-consent-modal .ada-consent-badge { font-size: 9px; letter-spacing: 0.14em; text-transform: uppercase; font-weight: 700; padding: 3px 8px; border-radius: 4px; } #ada-consent-modal .ada-consent-badge.always { background: #d1fae5; color: #065f46; } #ada-consent-modal .ada-consent-badge.reserved { background: #f1f5f9; color: #475569; } /* Switch */ #ada-consent-modal .ada-switch { flex-shrink: 0; position: relative; width: 44px; height: 24px; display: inline-block; margin-top: 2px; } #ada-consent-modal .ada-switch input { opacity: 0; width: 0; height: 0; } #ada-consent-modal .ada-switch-track { position: absolute; inset: 0; background: #cbd5e1; border-radius: 24px; transition: background .15s; cursor: pointer; } #ada-consent-modal .ada-switch-track::before { content: ''; position: absolute; left: 3px; top: 3px; width: 18px; height: 18px; background: #ffffff; border-radius: 50%; transition: transform .15s; } #ada-consent-modal .ada-switch input:checked + .ada-switch-track { background: #B86A4C; } #ada-consent-modal .ada-switch input:checked + .ada-switch-track::before { transform: translateX(20px); } #ada-consent-modal .ada-switch input:disabled + .ada-switch-track { background: #a7f3d0; cursor: not-allowed; } #ada-consent-modal .ada-switch input:disabled + .ada-switch-track::before { background: #10b981; } #ada-consent-modal .ada-consent-modal-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 24px; justify-content: flex-end; } #ada-consent-modal button.ada-consent-btn { font-family: inherit; font-size: 12px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; padding: 10px 18px; border-radius: 9999px; border: 1px solid transparent; cursor: pointer; transition: background .15s, border-color .15s; background: #0f172a; color: #fbfaf6; } #ada-consent-modal button.ada-consent-btn:hover { background: #1e293b; } #ada-consent-modal button.ada-consent-btn.ada-consent-secondary { background: transparent; color: #0f172a; border-color: #cbd5e1; } #ada-consent-modal button.ada-consent-btn.ada-consent-secondary:hover { background: #f1f5f9; } </style> <div id="ada-consent-banner" role="dialog" aria-live="polite" aria-labelledby="ada-consent-banner-heading"> <div class="ada-consent-shell"> <div class="ada-consent-copy"> <strong id="ada-consent-banner-heading">We use cookies.</strong> Essential cookies keep the site working. Analytics cookies (Google Analytics, PostHog) help us understand which pages perform — they only load if you accept. We do not use marketing / ad pixels today. See our <a href="/cookies">Cookies Policy</a> and <a href="/privacy">Privacy Policy</a> for detail. You can change your choice any time via <em>Cookie preferences</em> in the footer. </div> <div class="ada-consent-actions"> <button type="button" class="ada-consent-btn ada-consent-tertiary" data-ada-consent="customize">Customize</button> <button type="button" class="ada-consent-btn ada-consent-secondary" data-ada-consent="reject">Reject non-essential</button> <button type="button" class="ada-consent-btn" data-ada-consent="accept">Accept all</button> </div> </div> </div> <div id="ada-consent-modal" role="dialog" aria-modal="true" aria-labelledby="ada-consent-modal-heading"> <div class="ada-consent-modal-card"> <h3 id="ada-consent-modal-heading">Cookie preferences</h3> <p class="ada-consent-lede">Choose which categories of cookies you allow. Essential cookies always load because the site cannot function without them. Read the <a href="/cookies">Cookies Policy</a> for the full list.</p> <div class="ada-consent-category"> <label class="ada-switch" aria-label="Essential cookies (always on)"> <input type="checkbox" checked disabled> <span class="ada-switch-track"></span> </label> <div class="ada-consent-body"> <p class="ada-consent-title">Essential <span class="ada-consent-badge always">Always on</span></p> <p class="ada-consent-desc">Session, CSRF, and consent-choice cookies. Required for forms, admin login, and remembering this preference.</p> </div> </div> <div class="ada-consent-category"> <label class="ada-switch" aria-label="Toggle analytics cookies"> <input type="checkbox" id="ada-consent-analytics"> <span class="ada-switch-track"></span> </label> <div class="ada-consent-body"> <p class="ada-consent-title">Analytics</p> <p class="ada-consent-desc">Google Analytics 4 and PostHog. Help us understand which pages perform and where users get stuck. Aggregate reporting only.</p> </div> </div> <div class="ada-consent-category"> <label class="ada-switch" aria-label="Toggle marketing cookies"> <input type="checkbox" id="ada-consent-marketing"> <span class="ada-switch-track"></span> </label> <div class="ada-consent-body"> <p class="ada-consent-title">Marketing <span class="ada-consent-badge reserved">Reserved</span></p> <p class="ada-consent-desc">Reserved for future ad-pixel tracking (Meta Pixel, LinkedIn Insight Tag, etc.). No marketing cookies are active on this site today; the toggle is here for future consistency.</p> </div> </div> <div class="ada-consent-modal-actions"> <button type="button" class="ada-consent-btn ada-consent-secondary" data-ada-consent="reject">Reject non-essential</button> <button type="button" class="ada-consent-btn" data-ada-consent="save">Save preferences</button> </div> </div> </div> <script> (function () { // The stored-consent shape: // {v: 1, analytics: 0|1, marketing: 0|1, ts: '<ISO date>'} var STORAGE_KEY = 'ada_consent'; var COOKIE_NAME = 'ada_consent'; var COOKIE_MAX_AGE = 60 * 60 * 24 * 365; // 12 months var VERSION = 1; var listeners = []; function readCookie() { var match = document.cookie.match(new RegExp('(?:^|; )' + COOKIE_NAME + '=([^;]*)')); if (!match) return null; try { return JSON.parse(decodeURIComponent(match[1])); } catch (e) { return null; } } function writeCookie(prefs) { var val = encodeURIComponent(JSON.stringify(prefs)); var attrs = '; max-age=' + COOKIE_MAX_AGE + '; path=/; SameSite=Lax'; if (location.protocol === 'https:') attrs += '; Secure'; document.cookie = COOKIE_NAME + '=' + val + attrs; } function readStored() { var stored = null; try { var raw = localStorage.getItem(STORAGE_KEY); if (raw) stored = JSON.parse(raw); } catch (e) { stored = null; } if (!stored) stored = readCookie(); if (!stored || stored.v !== VERSION) return null; return stored; } function writeStored(prefs) { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(prefs)); } catch (e) {} writeCookie(prefs); } function emit(prefs) { listeners.forEach(function (cb) { try { cb(prefs); } catch (e) { /* ignore */ } }); try { document.dispatchEvent(new CustomEvent('ada:consent', { detail: prefs })); } catch (e) { /* CustomEvent unsupported */ } } var current = readStored() || { v: VERSION, analytics: 0, marketing: 0, ts: null }; var banner = document.getElementById('ada-consent-banner'); var modal = document.getElementById('ada-consent-modal'); var toggleAnalytics = document.getElementById('ada-consent-analytics'); var toggleMarketing = document.getElementById('ada-consent-marketing'); function showBanner() { if (banner) banner.classList.add('ada-consent-open'); } function hideBanner() { if (banner) banner.classList.remove('ada-consent-open'); } function showModal() { if (!modal) return; // Sync current values into the toggles before showing. if (toggleAnalytics) toggleAnalytics.checked = !!current.analytics; if (toggleMarketing) toggleMarketing.checked = !!current.marketing; modal.classList.add('ada-consent-open'); } function hideModal() { if (modal) modal.classList.remove('ada-consent-open'); } function persist(prefs) { var normalized = { v: VERSION, analytics: prefs.analytics ? 1 : 0, marketing: prefs.marketing ? 1 : 0, ts: new Date().toISOString(), }; current = normalized; writeStored(normalized); emit(normalized); } function grantAll() { persist({ analytics: 1, marketing: 1 }); hideBanner(); hideModal(); } function rejectAll() { persist({ analytics: 0, marketing: 0 }); hideBanner(); hideModal(); } function saveCustom() { persist({ analytics: toggleAnalytics && toggleAnalytics.checked ? 1 : 0, marketing: toggleMarketing && toggleMarketing.checked ? 1 : 0, }); hideBanner(); hideModal(); } function openPrefs() { showModal(); } function closePrefs() { hideModal(); } function resetConsent() { try { localStorage.removeItem(STORAGE_KEY); } catch (e) {} document.cookie = COOKIE_NAME + '=; max-age=0; path=/; SameSite=Lax'; current = { v: VERSION, analytics: 0, marketing: 0, ts: null }; emit(current); showBanner(); } // GPC signal — treat as an implicit "reject non-essential" for cookies // that would count as sale/sharing under CCPA (analytics inferences + // marketing). We still show the banner so the user knows the site // respects their signal, but pre-lock the toggles off. var gpc = false; try { gpc = !!navigator.globalPrivacyControl; } catch (e) {} // Public API. window.adaConsent = { granted: function (cat) { return !!current[cat]; }, grantAll: grantAll, rejectAll: rejectAll, save: function (prefs) { persist(prefs || {}); hideBanner(); hideModal(); }, open: openPrefs, close: closePrefs, reset: resetConsent, on: function (cb) { if (typeof cb === 'function') listeners.push(cb); }, current: function () { return current; }, gpc: gpc, }; // Wire button clicks. document.querySelectorAll('[data-ada-consent]').forEach(function (el) { el.addEventListener('click', function () { var action = el.getAttribute('data-ada-consent'); if (action === 'accept') grantAll(); else if (action === 'reject') rejectAll(); else if (action === 'customize') showModal(); else if (action === 'save') saveCustom(); }); }); // Escape closes the modal. document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && modal && modal.classList.contains('ada-consent-open')) hideModal(); }); // Click outside modal card closes it. if (modal) { modal.addEventListener('click', function (e) { if (e.target === modal) hideModal(); }); } // First-visit banner. Skip on the policy pages themselves so the user can // read the policy without a banner blocking the bottom of the viewport. var path = (location.pathname || '/').replace(/\/+$/, ''); var isPolicyPage = /^\/(privacy|terms|cookies)$/.test(path); var stored = readStored(); if (!stored && !isPolicyPage) { if (gpc) { // GPC user: pre-lock toggles off, show banner so they can override. if (toggleAnalytics) toggleAnalytics.checked = false; if (toggleMarketing) toggleMarketing.checked = false; } // Show after a short delay so first-paint isn't disrupted. setTimeout(showBanner, 300); } // Fire the initial emit so listeners registered before this script runs // (unlikely — script is inline in body) or after (typical) both get the // current state. setTimeout(function () { emit(current); }, 0); })(); </script> <!-- Initialize Lucide Icons --> <script>lucide.createIcons();</script> <!-- Sitewide form autofill — captures canonical lead fields on submit and prefills matching fields on subsequent pages. Zero-config: any form whose input `name` attrs match the alias set in form-autofill.js is auto-wired at DOMContentLoaded. Runs before chatbot.js so the concierge (when enabled) sees a filled form on its second visit. --> <script src="/js/form-autofill.js?v=1783574035" defer></script> <!-- Aday Interactive Concierge — page context + widget --> <!-- LeadConnector (GoHighLevel) chat widget — sitewide. Loaded at end-of-body so the widget's Stencil components mount against a fully-parsed DOM. Placing this in <head> without defer caused a regression where the Send button rendered but its click handler never bound (Stencil components silently fail to hydrate if their host body doesn't exist at script eval). --> <script src="https://widgets.leadconnectorhq.com/loader.js" data-resources-url="https://widgets.leadconnectorhq.com/chat-widget/loader.js" data-widget-id="6a4d82d0c1e521454a6235ea"></script> </body> </html>