Rapid Prototyping: Building Calendly in 3 Hours

Part 1 of this series: Meter Feeder in 1.5 hours >

How long does it take to prototype a startup? When we look at a product like Calendly, it’s hard to imagine scheduling meetings without it. But when Tope Awotona first had the idea, it wasn’t obvious that it would take off. He had to build a prototype.

Prototyping is always a risk – it’s easy to spend months building something that nobody wants. But if you have a prototype, those conversations with initial customers are so much easier. So we’re setting out to see how fast we can get that crucial prototype. If we can get it down to days, or even hours, we’re onto a winner:

Launching a mediocre product as soon as possible, and then talking to customers and iterating, is much better than waiting to build the “perfect” product.

Geoff Ralston and Michael Seibel

in Y Combinator’s Essential Startup Advice

Our secret weapon is Anvil. It’s a platform for building web apps without the fuss: it’s got a visual interface designer, client- and server-side code is all in Python, and it deploys to the cloud with one click.


The Build

I’ll walk you through the design process, show you some screenshots, and give a breakdown of how long each stage took:

1. Google Integration and User Setup (30 minutes)

Calendly connects to your calendar to automatically check availability, so you don’t need those endless back-and-forth emails. Integrating an OAuth flow with Google Calendar could take all day, but Anvil’s Google integration makes it really simple:

anvil.google.auth.login(['https://www.googleapis.com/auth/calendar'])

That gives us a login screen:

Google OAuth Screen

Google OAuth Screen

And now we have the OAuth tokens to use with the Calendar API:

refresh_token = anvil.google.auth.get_user_refresh_token()
access_token  = anvil.google.auth.refresh_access_token(refresh_token)

To keep the refresh token secure from prying eyes, we encrypt it with Anvil’s Secrets Service, then store it in a Data Table:

user['refresh_token'] = anvil.secrets.encrypt_with_key('token_key', refresh_token)

2. Basic Interaction (1 hour 15 minutes)

There are two parties here - the Organiser, who is advertising their availability, and the Attendee, who is picking a meeting time with them.

We make a Settings page, so the Organiser can specify the length of their meeting slots, and give them a unique URL they can provide to their attendees:

The Organiser configures their settings

The Organiser configures their settings

When the Attendee clicks that link, they get the Booking page, where they can choose a meeting (at any time, for now), then provide their details to confirm their slot.

The Attendee enters their details

The Attendee enters their details

We create a calendar event by POSTing to the Google Calendar API, using the Organiser’s OAuth tokens. (Google’s API docs are somewhat confusing, but the Anvil docs show us how.)

Calendar event

Calendar event

We then send an email to tell the Organiser about the new booking:
(Sending email is one line of code with Anvil – it’s all built in!)

Example email

Example email


3. Adjust Availability (55 mins)

Of course, the real magic of Calendly is that the Organiser can specify their availability, and we avoid clashing with existing appointments.

Let’s tackle the first one first: We need a page for the Organiser to set up the times they’re willing to meet:

Booking a meeting

Booking a meeting

The data structure was the tricky part here, but Python’s datetime module simplified this process – especially as we can use Python in the browser too!

I didn’t need to keep translating from Python datetime objects, to JSON, to Javascript Date objects, and back again. This melted my brain a lot less than it might have done.


4. Timezone Awareness (15 minutes)

Timezones are a minefield. Having an Organiser in one timezone and an Attendee in a different timezone is a real headache – we can’t sensibly ask the Attendee to mentally convert the times in their head!

Nobody wants to write their own timezone module, but Python has pytz, which is available on the Anvil server, and we can use Anvil’s timezone library to capture the timezone of the browser:

import anvil.tz
browser_tz = anvil.tz.tzlocal()

So if the Organiser is in the UK, and available from 12pm-3pm on Thursdays, and I’m in Malaysia…

Pick a slot – in my timezone!

Pick a slot – in my timezone!


5. Avoiding Calendar Clashes (20 minutes)

A booking system would be useless if it allowed two bookings at the same time! So we use the Google Calendar API to get a list of events when the Organiser is ‘busy’, and only offer Attendees slots when the Organiser is available:

Prior engagement

Prior engagement

No slots due to prior engagement

No slots due to prior engagement


Total Time: 3 hours 15 minutes

And that’s it! We’ve prototyped a fully functioning booking system, and it’s not even lunchtime.

We can spend the afternoon showing it to potential users, and watching them interact with it. If they get stuck on something, we can rebuild it tomorrow!


Want to see the source code and explore it yourself? Click this fine link:

To run the app yourself, you’ll need your own client_id and client_secret for the Google API. Following the steps in the Anvil docs: Linking Google to Anvil.


More Rapid Prototypes

Want to see more rapid prototyping? We’ve rebuilt a few famous startups in record time.

Here’s another one: