Case study · alaniformt.com
A Senate campaign site,
built and run by one person
Alani Bankhead ran for the U.S. Senate in Montana in 2026. I replaced her WordPress site with a custom build in under two weeks. Then I ran it every day until the election: new pages, new tools and same-day changes.
- Role
- Design, development, content operations, analytics, deploys
- Timeline
- Planning June 17 · live June 29 · daily through Nov 3
- Scale
- 66 pages and tools · 45 public URLs · 422 files at the end
- Stack
- Custom components · Netlify · Google Apps Script · Python · Stripe · GA4
Before and after
From WordPress to a custom build
This was her WordPress site in early June: a tagline bar, a video filling the first screen, and the bio and sign-up form further down. The custom build went live June 29, and I kept refining the homepage through the election. The final version put who she is, why her and how to vote on the first screen, with separate layouts for desktop and phone.




What I built
The pages, and what's under them
Voter guide, web and print
A sourced side-by-side of all four candidates on 143 propositions, with a scorecard and numbered sources. A matching double-sided handout went out at doors and events.
- The web page, the tally bars and the printed handout all come from one dataset, so they always match.
- Every number fills in automatically from one file, and the site refuses to publish a hand-typed count, so totals never drift out of sync.
- The QR code on the handout points to a link the campaign controls, so a mistake could be fixed online without reprinting a single flyer.


Positions: 52 issues, 12 big enough for their own page
Every stance in one place, filterable by subject and searchable, with "New" and "Updated" badges that clear themselves after a week.
- Every stat and every action item comes from one data file, so a number can't say one thing on the summary and another on the full plan. That's 236 sourced stats and 555 specific actions.
- Search finds words inside the full plan pages too, without slowing the page down for people who never search.
- Reporters, voter-guide sites and AI assistants could pull her positions straight from the site and quote them correctly, through a data export and an
llms.txtfile.


Long-form plan pages
The twelve most complex positions got full plan pages, all built on one shared framework: a jump menu, sections, sourced stat cards, numbered references, and the federal levers behind each commitment.
Each plan's commitments feed back into the positions data, so the summary tile and the full plan can't disagree.


Follow the Money
Five pages showing who funds each campaign and who spends outside money in the race, straight from federal filings, with network diagrams and filing-level sources.
- The pages rebuild themselves from the raw federal filings, recalculating every total and redrawing every diagram.
- Each update is compared with the last one, so no number changes without a reason.


Fact-check pages: truth and rumors
When the mailers and TV ads started, the campaign needed to answer every claim, fast, without sounding defensive or nasty. Two pages do it.
- /truth puts each claim beside the record: what they said, a verdict stamp (False, Cut off, Out of bounds) and the evidence, with timelines, documents and video.
- /rumors tracks 60 claims, sorted into topics in a jump menu so a reader finds theirs in seconds.
- The page builds itself from a list of claims. Sources number themselves in order, and nothing goes public until it's marked ready.
- Each page has its own link-preview card, and the volunteer dashboard links them so canvassers answer questions at the door with sources.


Events, news and a live map
Upcoming events with add-to-calendar links, a news page with video, and a Montana map of every campaign stop. The map here is the one from the site: every public stop from February to Election Day, drawn in the order she made them.
All three read from the team's Google Sheet. Staff publish by ticking a box, and a nightly script keeps the map current. Nobody has to call the developer to post an event.

Store and point of sale
A Stripe store where every purchase is recorded the way federal rules require, plus a phone-based register for event tables.
- Prices are checked on the server, so nobody can tamper with a cart, and every hour the system confirms payments, updates inventory and emails receipts.
- Volunteers join a sales session with a code and sell from their own phones; close-out reconciles the cash box.


Behind the scenes
The public site was half the job. The team ran on internal tools built on the same stack: staff and volunteer launch pads, a fundraising dashboard that fills itself every morning, one intake system behind every form, a phone point of sale, synced calendars and more.
They're private, so they're shown as case studies with sample data.
See the internal tools
Fundraising you can measure
Every print piece, TV spot and share graphic points to its own short link with its own tracking code. The campaign could see what each one raised.
- If someone arrives from an ad and donates three pages later, the ad still gets the credit.
- A short link can be repointed after printing, which once rescued a dead QR code already in the mail.
- A share page previews like an article and lands friends on a $20 donation form in one tap.


Built to hold up
Safeguards most sites skip
Link previews that show up
Many modern sites add their page titles and images with JavaScript, which Facebook, iMessage and search engines never run, so shared links look blank.
Here: every page carries its preview in the page itself, the pages people share most have their own preview image, and a check blocks any update that loses one.
Forms that never drop a submission
A thank-you message that appears too fast can cancel the send, and nobody notices until the entries stop.
Here: every form sends first and confirms second, and each one gets a live test entry before it goes up.
"Live" means live
A change that looks finished on the developer's screen isn't always on the real site.
Here: every page has a checklist of what it must contain, and a script checks the live site against it after each update. Nothing counts as done until the real site passes.
Payments confirmed, never double-counted
Store payments have to match the books exactly, every time.
Here: an hourly check confirms every payment with the processor, updates inventory and sends the receipt, and it's built so running it twice can never count a sale twice.
One source for every number
The same counts appear on many pages and in print, and hand edits drift apart.
Here: every count fills in from one file, and the site refuses to publish a hand-typed number.
Everyday updates without a developer
News, stories and events change daily, and waiting on a developer for each one slows a team down.
Here: staff publish them from a spreadsheet by ticking a box, so the site stays current without a new release.
Timeline
Four months, month by month
June · launch
Planning meeting June 17. Live June 29 with 13 public pages, a donate subdomain, staff and volunteer dashboards, and analytics.
July
Event forms, a live map, news feeds, a custom analytics dashboard, the volunteer register, one front door for all contact, the service record and press kit, and the store.
Aug–Sept
Store live, eleven full plan pages, endorsements, the voter guide, print and TV short links, debates, the ballot explainer, and a machine-readable positions export.
October
A content audit, the homepage relaunch, a new phone menu, supporter stories, Follow the Money, photos, the share-chain page, and search across every plan.