Captured with Tiff Availability checker
The quote writes itself as you answer, so nothing's hidden
Couples want to know if their date's free and what it'll cost. Most photographers make them email and wait. This one just tells them.
- Role
- Designer and builder
- Timeline
- Built August 2026, live 6 September
- What I owned
- Product design, Interaction design, Front end, Pricing engine
- Status
- Live
1The quote, written as you answer2Travel gets added in, not left for later3Her own published prices- 1The quote, written as you answer
- 2Travel gets added in, not left for later
- 3Her own published prices
Every card has its own button, and it picks the package and moves you on in one go. There's about 1,800 pixels of cards here, so a single Next button at the bottom would've sat two screens below the card you'd just decided on.
The problem
When a couple's planning a wedding, they want two answers from a supplier before anything else: is my date free, and what's it going to cost? Most suppliers make them send an email and wait for a brochure.
- My role
- I designed and built the whole thing myself, including the pricing engine and the link to Tiff's calendar.
- The team
- Tiff owns the business and sets the prices. It was just the two of us, with nobody in between.
The result
How this was measured
I ran real road routing for the two venues on her published price list. Ashridge came out at £35.50 against her £35, and Wasing came out at £77.20 against her £75.
Checked against her own published prices, August 2026
How this was measured
The calendar function reads the event titles, times and names on the server, and all it sends back is a list of dates. The feed URL lives in an environment variable, so it never shows up in client code.
api/availability.mjs
How this was measured
These are the worked examples from the price list Tiff approved, plus both mileage band boundaries, the anchor price, and the one package that has to switch off its own add-ons.
The test runs in the console and has to come back with an empty array
Context
The two questions nobody answers
When a couple's planning a wedding, there are two things they want to know about a supplier before anything else. Is my date free, and roughly what's this going to cost? Hardly anyone in the industry answers either of them. You fill in a form, you wait, and then a brochure turns up with a "starts at" price.
Tiff's whole pitch is that she doesn't do that. So her site couldn't do it either, and the booking funnel is the place where that promise either holds up or falls over.
The ledger
The quote writes itself in front of you
The whole funnel is built around a ledger. It's a dark panel down the right-hand side, and every time you answer a question it picks up a new line. The questions change on the left and the ledger stays put.
So by the time a couple gets to the last step, they've watched their own price being written. The estimate isn't a number that appears at the end. It's what they've been reading the whole way down. Tiff's promise is that nothing's hidden, and this is how the page keeps it.



Decision 01 of 03
No calendar of free Saturdays
The bind
The obvious way to check a date is a month grid with the free days highlighted. It's what couples expect, and it's what nearly every booking tool does.
What I chose
I went with three typed fields instead, for day, month and year. Your wedding date is the one date you know off by heart, so typing it is quicker than hunting for it in a grid. But the real reason is commercial. Tiff only takes on a limited number of weddings a year, and a calendar full of open Saturdays would show everyone exactly how few. So you type your date and you get an answer.
What it cost
If a couple hasn't fixed a date yet, they can't browse for one. They need to turn up with a date in mind, and some of them won't have one.


Decision 02 of 03
If the calendar's slow, it uses the last good read
The bind
The checker reads Tiff's real calendar, and that read can be slow, or it can fail. There are two bad ways to deal with that. You can treat a diary you can't read as an empty one, and then every date looks free. Or you can tell the couple to email instead, and that turns them away when there's nothing wrong with the diary.
What I chose
So it keeps the last good read of her calendar, and goes back for a fresh one every five minutes. If that fresh read is slow or it fails, it just carries on with the last one that worked. A bad read never replaces a good one, so a couple always gets a straight answer from her real diary.
What it was based on
I measured it on 14 September, eight days after launch. Four live reads out of eight had failed, and every one of those was a couple being told to email when the diary was fine.
What it cost
A date that's been booked in the last few minutes can briefly show as free. Tiff confirms every booking on a call anyway, so that's the right way round.
Decision 03 of 03
I made the ledger the way back
The bind
Originally, the funnel saved your progress as you went. So if you left on the extras step and came back five days later, it picked up right where you'd left off, on extras. The problem was you couldn't get back to anything before that. There was no way to change your date or your package, and the browser's back button just took you off the site.
What I chose
What I did was make every answered line in the ledger clickable. Press your date or your package and that question opens back up, with everything else you've answered still in place. The ledger already showed what you'd told it, so it made sense for it to be the place you go to change it. I also stopped saving progress between visits. A check only takes a minute, and a price is only good for the answers you give today.
What it cost
A couple who gets halfway through and comes back later has to start again. I'd take that over dropping them back into the funnel somewhere they couldn't get out of.

Travel
The travel number had to be real
Travel is the number couples brace themselves for, so it's the one the funnel has to get right. I tried straight-line distance first, because all it needs is two sets of coordinates. It came in twenty to thirty-five per cent under the real road distance, which meant £13 where her price list says £35, and £46 where it says £75.
Quoting low and then correcting upwards on the call is exactly what her testimonials praise her for never doing. So the funnel works out a real driving distance from the venue's postcode instead. That got within about £3 of her published figures.

The calendar
I couldn't read the calendar the way I'd planned
I built the endpoint to read a secret iCal address from Tiff's Google Calendar. But her calendar is on Google Workspace, and Workspace only lets you share free and busy outside the organisation, which hides the one setting my whole design depended on. Her admin console didn't offer a switch to turn it back on.
So in the end the feed became a small script running inside her own account, publishing the same format. Once I could see her real diary, it turned out to be simple. That calendar's only for her bookings, and every wedding goes in as an all-day event. Google leaves all-day events marked as free, so the checker ignores that and blocks the date like it should.
After launch
What changed after launch
Eight days after launch, Tiff was using the travel step herself. She typed in a postcode, pressed See your price, and nothing happened. There was a little Check button next to the field that you had to press first, and nothing on the page told you that.
That was my mistake, not hers. The field looks finished the moment the postcode is in, so anyone would've missed it. We fixed it by getting rid of the Check button altogether. Now a full postcode looks itself up as soon as you've typed it, and See your price is never disabled. If you press it early, it finishes the lookup and carries on. If there's nothing it can use, it tells you why.


The second fix was one I couldn't see from my desk. The site moved from Vercel to Cloudflare at launch. Vercel had been holding on to the calendar's answer for fifteen minutes at a time. Cloudflare doesn't cache a function's response, so every single visit was reading Tiff's calendar live, and that read can take longer than the function is willing to wait. When I measured it on 14 September, four reads out of eight failed. Couples were being told to email when the diary was fine.
Now the function keeps the last good answer and serves it for five minutes, then reads the calendar again behind the next visitor. A slow or failed read never replaces a good one.
While I was digging into it, I also found a bug of my own. The page started out with an empty list of booked dates, so if you checked a date while the calendar was still loading, it could come back as free. Now it waits for the calendar before it answers.
What I'd measure
What I'd measure
It went live on 6 September 2026. I don't have conversion numbers yet, and I'm not going to make any up.
What I'd watch is how many couples drop off between the date step and the estimate, how many get to a price and then book a call, and how the enquiries Tiff gets start to change. My bet is that fewer people email just to ask what things cost, and the ones who do email already know.
Where AI sat
What I used it for, and what I didn’t trust it with
I designed and built this with Claude Code, but I didn't just trust it. The pricing engine checks itself against twelve cases from Tiff's approved price list, the copy gets checked against a contract file, and I captured and reviewed every screen before it went live. Getting the failure paths right took me longer than the happy path did.
See it live
Open it yourself
