July 13, 2026
PageSpeed Insights showing 100/100 for both mobile and desktop on webbroi.comWe moved webbroi.com off Squarespace onto Astro + Cloudflare Pages. Mobile PSI went from 65 to 100. JavaScript bundle dropped from 1.24 MB to zero render-blocking bytes. LCP dropped from 14.5 seconds to 1.7 seconds on mobile. Then we ran an AEO audit on the new stack so ChatGPT, Perplexity, and Google AI Overviews could actually cite it.
This post covers both halves: the migration itself, and the repeatable AEO audit we now run on every Astro build we ship for clients.
Squarespace is a capable platform for most small business sites. We build on it for clients every week. But there's a performance and control ceiling — and once you hit it, no amount of theme tweaking or code injection gets you through.
We hit it on our own site.
The webbroi.com site on Squarespace 7.1 (Fluid Engine):
We were paying $65/month (Commerce plan) to serve a mostly-static marketing site. And we couldn't fix the speed without leaving the platform.
If your site is hitting any of these, it's worth looking at a platform move:
1. Page speed ceiling. The Squarespace JS bundle isn't removable. The theme framework, Fluid Engine editor runtime, and site-chrome scripts ship together. If mobile PSI matters to your business and you're stuck below 70, this is where you plateau.
2. Schema control ceiling. Squarespace injects its own JSON-LD (Organization, WebPage). You can add more via code injection, but you can't remove or fully override the platform's markup. For AEO, where FAQPage and Service schema drive citation eligibility, this is a real limit.
3. AEO scale ceiling. llms.txt, per-page canonical control, robots.txt custom rules, server-side rendering of all content — Squarespace handles some of this. Not all.
4. Cost ceiling. Business and Commerce plans run $23–$65/month. Astro on Cloudflare Pages runs $0–$5/month for most sites.
If you're not hitting any of these, stay on Squarespace and put the migration budget elsewhere. But if you're hitting even two of them, the math starts working for a move.
Phase 1 — Inventory and redirect map. Every URL exported from the sitemap, mapped to its Astro equivalent, documented in a `_redirects` file. Missed redirects = lost rankings. This is the phase most teams underinvest in.
Phase 2 — Astro scaffold. Base layout with the Head component managing meta, canonical, schema, and OG tags per page. Content collections for the blog. TypeScript for type safety on frontmatter.
Phase 3 — AEO setup. Schema per page type. llms.txt at `/public/llms.txt`. robots.txt allowing GPTBot, PerplexityBot, ClaudeBot, Google-Extended, CCBot. Direct-answer H1s and FAQ blocks on every money page.
Phase 4 — Cloudflare Pages deploy. GitHub repo connected. Build command `npm run build`, output `dist`. Custom domain added, DNS pointed. First deploy: 9 seconds.
Phase 5 — Post-launch. Sitemap submitted in GSC. URL Inspection on top 10 pages to request indexing. Coverage report monitored daily for the first two weeks.
After the migration, one week later:
The site loads before your finger leaves the tap target.
Speed is a prerequisite for AEO, not the goal. Once webbroi.com was fast, we needed to make sure it was citable — that ChatGPT, Perplexity, Gemini, and Google AI Overviews would actually pull our content into their answers.
Here's the checklist we now run on every Astro build we ship for clients. It applies to any stack, but the fixes are especially straightforward on Astro because you have full control of the `<head>` and content structure.
AI engines can't cite pages they can't read. Verify your site isn't blocking them.
robots.txt. Fetch `https://yourdomain.com/robots.txt`. Confirm none of the following are disallowed: `GPTBot`, `PerplexityBot`, `ClaudeBot`, `anthropic-ai`, `Google-Extended`, `CCBot`. A single `Disallow: /` under any of these blocks that crawler completely.
llms.txt. Fetch `https://yourdomain.com/llms.txt`. If it 404s, you're missing a low-cost, high-signal file. llms.txt gives AI models a structured summary of your site's key pages and preferred framing — the difference between an AI guessing what your site is about and knowing.
JavaScript rendering. AI crawlers often skip JavaScript execution entirely. If your content is only visible after JS runs, it may be invisible to them. Test by fetching your page with `curl` and checking whether the main content appears in the raw HTML response.
Schema markup gives AI engines pre-parsed, trusted data. Without it, they have to infer everything from your prose — and they often get it wrong.
Organization schema on the homepage: `@type: Organization` with `name`, `url`, `description`, `sameAs` links to verified social profiles. This is the foundational signal AI engines use to identify and trust your brand.
FAQPage schema on any page with Q+A content: `@type: FAQPage` with `acceptedAnswer.text` for each question. AI engines lift these directly into answers. A heading with no answer text underneath produces no signal.
Service or Product schema on service and product pages: declares what you offer so AI engines can match you to relevant queries.
Validation: Run everything through Google's Rich Results Test and Schema.org's validator. Errors and warnings reduce trust.
This is the highest-leverage step. AI engines cite pages that answer questions clearly, near the top, in plain language.
For each key page, ask:
Page speed is a prerequisite for AEO, not a bonus. Slow pages get crawled less frequently, and AI engines that reach them may time out before parsing the content.
Targets for any AEO-serious site:
If you're on Squarespace, the JS bundle and lack of control over render-blocking resources make hitting these difficult without a rebuild. If you're on a static stack like Astro, these targets are achievable without heroics.
Citation tracking is the only metric that tells you whether the rest of the audit is working.
Manual spot checks. Search your target queries in ChatGPT, Perplexity, Gemini, and Google AI Overviews. Is your brand named? Is your content quoted? Is your URL linked? Do this for 5–10 priority queries and record the results monthly.
Non-branded queries matter most. Branded queries (`WebbROI AEO`) confirm awareness. Non-branded queries (`best AEO agency for small business`) are where new revenue comes from. If you're only cited on branded queries, you have an awareness problem, not a citation problem.
GSC as a proxy. Google Search Console impressions for your target queries are a reasonable proxy for AI Overviews inclusion, since AI Overviews draw from indexed content.
Not every finding carries equal weight:
1. Unblock AI crawlers first. A blocked crawler makes every other fix irrelevant.
2. Add Organization + FAQPage schema. High impact, low effort, ships in one commit.
3. Fix direct-answer content on your top service pages. Restructure, don't rewrite.
4. Add llms.txt if missing.
5. Fix page speed if below targets.
6. Build citation tracking into monthly reporting.
Astro is fast by default, but a few specific choices made the difference between 90 and 100 on PSI.
Self-hosted fonts. Download the `.woff2` files, serve from `/public/fonts/`, add `font-display: swap`. Eliminates a render-blocking cross-origin request and a DNS lookup. On our migration, this alone moved LCP down by ~400ms.
Zero client JS by default. Astro's static output ships no JavaScript unless you explicitly add islands via `client:load` or `client:idle`. Most business sites don't need any. If you do, use `client:visible` to defer until the component enters the viewport.
Cloudflare edge caching. HTML served from the edge, not the origin. In `public/_headers`:
/blog/*
Cache-Control: public, max-age=3600, s-maxage=86400
/fonts/*
Cache-Control: public, max-age=31536000, immutable
No above-the-fold third-party scripts. Analytics loads deferred with `defer` or `type="module"`. No tag manager firing on initial paint. If you need consent-gated tracking, use a partytown island so it runs off the main thread.
Astro Image component. Use `<Image>` from `astro:assets`. WebP output with explicit `width` and `height` on every image. Eliminates CLS.
Preload only what matters. One critical font, one hero image. Not fifteen preload tags. Over-preloading blocks the browser as much as under-preloading.
Migration is a real project — plan for 3–5 days of focused work on a straightforward 5–15 page site, longer if you have ecommerce or 100+ blog posts to move. Don't do it because it sounds fun. Do it because:
If those criteria don't match your situation, stay put and put the budget into content and conversion instead.
If they do match — the toolchain (Astro + Cloudflare Pages) is mature, cheap, and gives you speed and AEO control you cannot get on a hosted CMS.
This post is a condensed version of two longer pieces on the WebbROI blog: Why we moved off Squarespace to Cloudflare and How to run an AEO audit. WebbROI is an AEO + web development agency specializing in Astro + Cloudflare Pages builds and Squarespace-to-Astro migrations. Get a fixed-price AEO audit.