Case Study - We Move Montana
Moving On Up, a Missoula moving company with 123+ five-star Google reviews, traded a 2000s-era BlueVoda site for a phone-first Astro build with perfect Lighthouse and agent-readiness scores, made to turn the traffic it already earns into calls, texts, and quotes.
- Client
- Moving On Up LLC
- Year
- Service
- Website Development · Conversion Design · GEO

Overview
Most small-business rebuilds start with a traffic problem. This one didn't. Moving On Up already ranked well and already had the reviews; Gage Lockwood, the owner, picks every crew member and works the jobs himself, and his customers say so. The old site was the weak link: a legacy BlueVoda build that looked its age, broke on phones, and buried the phone number.
So the brief was narrow on purpose: convert the traffic, don't chase more of it. Every page exists to get a visitor to tap the number, send a text, or fill out a short quote form.
The stack: Astro 6, Tailwind CSS 4, TypeScript, Resend, and Vercel. See it live at wemovemontana.com.
The Challenge
Nobody shops for movers for fun. The person on the site is usually two weeks from a move date they can't push, comparing two or three companies on their phone, braced for the horror stories: the quote that doubles on move day, the crew that shows up four hours late, the surprise invoice. In a category where every site says "licensed and insured," the job was to make this crew feel like the one you'd actually trust with your stuff.
There were practical constraints too. The old site's URLs had years of search equity behind them and couldn't just disappear. The business runs on callbacks, not email threads, so the site couldn't promise a workflow Gage doesn't use. And the photos had to be real: no stock handshakes, no cartoon trucks.
The Solution
A voice that sounds like the crew. The copy is plain-spoken and short, with no exclamation points or hype, and it's written along the arc a mover's customer actually feels: dread, then relief, then trust, then ready. The hero names the stress outright ("Moving is one of the most stressful things you'll do") before it asks for anything. The owner band says the quiet part out loud: the number on this site is my cell.

Three ways in, all of them easy. The phone number carries as much weight in the hero as the quote button, because on a local-services site a lot of people call before they read. I added a third path, texting: "text me a photo of your move" opens a message on phones. On mobile, a slim sticky bar keeps call and text one thumb away, and it stays pinned to the bottom of the visible screen even while iOS collapses its toolbar. The quote form asks for only what Gage needs to call back with a real number. Email is optional.

Honest expectations. Every form, the thanks page, and the confirmation email say the same thing: we'll give you a call back at the number you gave us. I took out a "same business day" promise the business couldn't always keep. Trust signals are specific: a 5.0★ rating across 123+ Google reviews, fourteen years in business, the same crew from load to unload, and every estimate free, written, and no-obligation.
"They fit me in last minute. Gage and his crew were early, kind, great communicators and efficient workers." Mollie Devlin-McKay, Google review
Nothing lost in the move. Every legacy BlueVoda URL 301-redirects to its new home, down to the right section: the old piano page lands on the piano section of /services, and the old rates page on the fee breakdown. The site ships MovingCompany structured data with hours, service area, and rating, and canonical URLs and the sitemap agree on a single www host.
Ready for the AI assistants, too. A growing share of "who's a good mover in Missoula?" questions go to ChatGPT, Perplexity, or Claude instead of Google. So the site publishes fact-first markdown answer sheets for agents, plus an llms.txt index, and it serves them to any client that asks for markdown.

The Results
Moving On Up now has a site that matches its reputation. It's fast on a phone, it's honest about how the business works, and it covers six services (residential, commercial, piano and specialty, heavy items, long-distance, and senior moves) across a dozen core cities from the Bitterroot to Seattle. A visitor gets three ways to reach the owner without hunting for any of them.

Perfect scores, for people and for agents. The site scores 100 in all four Lighthouse categories (Performance, Accessibility, Best Practices, and SEO) on both mobile and desktop. The largest paint lands in under two seconds on a throttled phone connection, and nothing shifts as it loads. It also scores a perfect 100 on Vercel's Is Agentic, which checks how well AI agents can discover, read, and use a site. All six essential checks pass, eight of nine recommended checks pass, and twelve emerging signals earn bonus credit. An AI assistant asked about movers in Missoula can find the facts, read them, and quote them.

The rebuild kept the search equity the old site had earned: the rankings and the reviews came along, and old links still land somewhere useful. Because the services, reviews, and business details live in typed content collections, a new city, a changed fee policy, or a fresh review updates the pages, the structured data, and the agent answer sheets in one place.
What I Built
- Designed and built a mobile-first Astro 6 site: home, services, reviews, about, quote, and contact
- Wrote the conversion copy and voice, working through the hero, price anxiety, and form friction in focused rounds
- Built call, text, and quote paths, including a sticky mobile call bar
- Built a validated quote form that emails the request to the business and a confirmation to the customer through Resend
- Mapped every legacy URL with 301 redirects and shipped MovingCompany JSON-LD
- Added GEO delivery: markdown answer sheets, llms.txt, llms-full.txt, and Accept-header content negotiation
Under the Hood
The technical tour, for the developers on your team.
Static first, one server route
Astro 6 dropped the old hybrid output mode, so the site builds with output: 'static' and the Vercel adapter. Every page is prerendered. The only server-rendered route is /api/submit-quote, which opts out with export const prerender = false. There's no UI framework on the client: React is only used on the server, to render React Email templates. The browser gets a few small scripts for the mobile menu, the form's progressive enhancement, and the sticky call bar.
One source of truth
Name, address, phone, hours, rating, owner, and service area live in a single business.ts. Services are a glob()-loaded markdown collection and reviews a file()-loaded JSON collection, both with Zod schemas, so pages call getCollection() instead of hardcoding anything. Unknown values (a USDOT number still being confirmed, say) are written as literals starting with TODO:. They stay visible in dev, and the JSON-LD builder strips them so a half-filled schema never ships.
The quote endpoint
Submissions are validated with a Zod discriminated union: a quote needs a name, phone, and from and to locations, while a question needs a message. A honeypot field catches bots, and a per-IP limit of five submissions a minute catches floods, with no reCAPTCHA to cost conversions. Resend then sends two React Email templates, the lead notification and the customer's confirmation.
GEO in Vercel's routing layer
The answer sheets (/index.md, /services.md, /reviews.md, and the rest) are static endpoints built from the same data as the HTML, but their prose is written for agents: fact-first and quotable, ending in Q&A. That choice is recorded in an ADR. A single geoPages registry drives llms.txt, llms-full.txt, and the rel="alternate" links in the layout. Content negotiation lives below Astro: a post-build script patches .vercel/output/config.json so a request with Accept: text/markdown gets the page's markdown twin with Vary: Accept, and an unknown path gets a recovery sheet with a real 404. A Vitest suite keeps that route list in step with the registry.
- Astro 6
- Tailwind CSS 4
- TypeScript
- Vercel
- Resend
- React Email
- Zod
- JSON-LD
- llms.txt / GEO