It’s Y Combinator’s week of Demo Days, and we’re prototyping one YC startup each day. (If you missed it, check out the first in this series, where we prototyped an e-parking service in an hour and a half.)
Magic (YC W15) is an SMS concierge that can do anything. Text them a request, however outlandish, and they will make it happen. Let’s put ourselves into the founders’ shoes, when they were just starting out. We don’t know if anyone wants this service, so we need a working product they can use. What do we need to build?
We need to see and respond to texts from our customers.
We need to charge customers for the things we provide (with a commission, of course). They shouldn’t need to enter their credit card every time.
We need to share this work between several people.
With Anvil, it turns out we can build this all in a couple of hours. Watch me build a fully working product in this time-lapse video, then scroll down for the play-by-play:
Within half an hour, we’ve got the basics: We can receive SMS using an HTTP endpoint from a service like Twilio, display the conversation, and send replies.
Now a customer can ask for something, we need them to pay for it! To make purchases truly frictionless, we’ll take their credit card once, then keep it on file for anything they need in the future.
Anvil’s Stripe support makes this simple. We make an app to collect the customer’s card details, and then we send them a link to open that app on their phone:
After that, the card is on file, and we can charge them at the click of a button. (We also note our profit margin for future reference.)
If this app takes off, we’ll need help. We don’t want any messages to fall through the cracks, so we text all our operators when a new customer arrives. But we don’t want to notify every operator about every message – they’ll get drowned!
Instead, let’s track which customers need attention, and let operators “claim” customers. (We make sure two operators can’t claim the same customer by accident.)
The operator can mark a customer as Done (request resolved, no longer needs attention), or Can’t handle (still needs attention – “un-claim” the customer and text other operators for help).
If we need more information from the customer, the operator can select “Tell me when they reply”. The operator can go do something else: when the customer replies, we send an SMS to this operator only.
We’ve built the infrastructure for an SMS concierge in just a couple of hours. We can help people by text, take payment, and even coordinate a large team of operators if it suddenly gets popular. It’s a fully-working product that can take revenue right away, and scale as we grow.
Here’s how our final app works:
You can grab the source code yourself – click below to open the apps in the Anvil editor:
Want to dig into how these apps work? Our tutorials show you all the pieces these apps are made from, and more.
It’s Y Combinator’s Demo Day this week, when the startup incubator’s graduates show their products to the world. To mark the occasion, we decided to try a challenge: How much time does it take to prototype a startup?
For each Demo Day this week, we’ll build a working prototype of a startup from a recent YC batch. “Working” means more than a landing page – we want enough technology to provide the core service to the customer, and to get paid for it.
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.
We’ll walk you through the design process, show you some screenshots, and give a breakdown of how long each stage took. Today, we start with:
Build time: 1 hour, 30 minutes.
We’re moving to a cashless world, but urban infrastructure is slow to change. Meter Feeder lets you pay for parking with your smartphone, without costly new infrastructure.
Imagine we’re the Meeter Feeder founders: We need to build a working prototype that we can demonstrate to a city government, and deploy as a proof of concept. This means:
The public (customers) need to be able to pay for their parking.
Traffic wardens on patrol need to know whether a car’s parking has expired.
Let’s fire up Anvil, and see what we can do.
We’re going to break up parking into “locations”. We’ll identify a location with a number, which can be entered easily on a phone keypad, and displayed on legacy parking infrastructure (translation: put a sticker on the physical parking meter). Each location has a cost for a given unit of time, and a maximum stay (eg “$0.50 per 15 minutes; max stay 2 hours”).
We then create a table of “bookings”, which represent payment for a car to park in a location. Finally, we add user records (with Anvil’s built-in user authentication), and link each booking to the user who made it.
This is all pretty quick to set up with Anvil’s Data Tables:
Collecting payment is pretty straightforward with Anvil’s Stripe integration. Collecting the registration plate number and parking duration is even simpler. But parking your car is a frequent event, and we don’t want to make the customer re-enter this information every time. What’s more, after a user has paid for parking, they’ll want to check back and see how much time they have left.
So the first thing we do on app load is trigger the login/signup screen. (We use the “Remember me” option, so regular users never have to see it again.) Once we’re logged in, we can find and display your recent bookings. We also offer a quick “park here again” button to repeat an expired booking.
If you choose “New Booking”, we prompt you to enter a location code, or pick from a list of locations you’ve booked recently.
The next screen has big touch-friendly buttons for choosing your time and entering your registration. If there is a Stripe record associated with your account, we show a “pay with the same card as last time” button.
Thanks to the “Park here again” button on the first screen, a returning user can park somewhere they’ve used before with only two touches.
This is the back-end to make all those buttons work. This ends up being a 60-line server module, exposing four functions - “get my recent bookings”, “get a location record for this number”, “get the last licence plate I parked with”, and “pay for parking”.
Wiring these up to the front end didn’t take long, because Anvil lets you return live database rows into client code, and then use data bindings to display them in the UI.
After all that, the enforcement app came together pretty quickly. It’s a private app, so we can skip the user authentication and make the Locations and Bookings tables readable directly by client code.
When a parking warden arrives at a new location, they can enter the location code to display all valid bookings for that location. We also support as-you-type searching by licence plate number, so they can query a single plate in a busy location.
We’ve built a working, deployable prototype of the MeterFeeder service, in an hour and a half. If we were the MeterFeeder founders, we’d be feeling pretty good by now - we’ve got a compelling demo, without spending weeks or months getting this far. This means we can move straight on to the hard part: selling the concept to local government.
You can see the source to these apps yourself – click to open them in the Anvil editor:
Want to dig into how these apps work? Our tutorials show you all the pieces these apps are made from, and more.
In this live-coding video, you will watch me prototype a financial "Software as a Service" (SaaS) application in under an hour. At the end of this video, we will have an application for tracking stock prices. It has user accounts, per-user portfolios, and a monthly credit-card charge for using the service.
Follow along as we start from a single stock chart and build up to a full subscription service. You can also copy the source code and explore it yourself:
When your web app is handling sensitive information — be it API credentials, database passwords, or sensitive personal data — it’s important to keep it protected. It certainly shouldn’t be sitting in your source code, for anyone to see. It should be kept encrypted, until the time it’s needed. This is called encryption at rest.
With Anvil, you can store password or API keys encrypted in your app, with a name – for example, I could store my GitHub password in a secret called
github_password. Then I can use it in my app, like this:
username = "meredydd" password = anvil.secrets.get_secret("github_password") r = anvil.http.request("https://api.github.com/user/repos", json=True, username=username, password=password)
I can also create and store an encryption key, and use it to encrypt and decrypt data. Encrypted-at-rest data storage is this simple:
# This app has an encryption key named 'my_key': @anvil.server.callable def save_secret_data(new_text): encrypted_text = anvil.secrets.encrypt_with_key('my_key', new_text) app_tables.secret_data.add_row(text=encrypted_text)
Watch our video tutorial here, or read our API documentation :
App Secrets are encrypted, and stored with the source code for your Anvil app. Secrets and keys are encrypted with a key unique to that application – making the encrypted value useless outside that app.
All encryption is performed with high quality, industry-standard encryption schemes that avoid the pitfalls of using low-level cryptographic libraries. For more details, see our documentation .
We believe security and privacy are important, and we are proud to empower our users to use cryptography easily and safely. We are grateful to the security and privacy researchers who have helped us develop and validate this feature, and we welcome contact from the security community at firstname.lastname@example.org.
I'd like to start by taking some time to thank the PyCon UK organising committee. This has been our first time sponsoring PyCon UK, and we've been made to feel very welcome.
We make Anvil – it's a tool for building full-stack web apps with nothing but Python. We did this because we think we can make a better developer experience using full Python than using the traditional tools. And autocompletion is part of that.
Having proper code completion gives you discoverability. It lets you explore the APIs, without having to tab to the documentation all the time. It gives you speed, because you go a lot faster when you can hit the Tab key every few characters. It gives you confidence that what you're doing is right, because there are whole classes of bugs you can fix without even hitting the Run button. And it just feels good to use.
We started out thinking we could make a good developer experience without autocomplete. I'm here to tell you that we were wrong.
If you don't use autocomplete yourself, you might not know what you're missing. I really encourage you to try it out. Even if you spend all your days in a terminal with vim or emacs, you can get Jedi as a plugin. Really, just try it for a week. See what happens. You'll be amazed.
Unfortunately, Jedi wasn't quite what we needed. Earlier I said Anvil was "full stack", and that means that it knows about everything from your database tables...
...to your server-side code...
...to your client-side code. And it's got to autocomplete all of them.
What's more, Anvil is web-based, and Jedi is expecting a filesystem. And when you're hitting the Tab key, there's just not enough time to go back to the server to fetch your completions.
So, what do we do?
So we can take your code, insert a random symbol at your cursor position, and then feed it to the Skulpt parser. The parser then produces an abstract syntax tree that represents your module.
And when we hit a
Name node that contains the magic cursor symbol, we can just suggest all the things that are currently in scope.
That's not the only thing we want to autocomplete. For example, you can access Anvil's database rows like dictionaries, using square brackets (aka
__getitem__). So we have to store which items are available on each type.
We also compute and store what you get if you iterate over an object, what its attributes are, what you get if you call it as a function, and so on.
Speaking of function calls, we also need to infer between modules. For example, in Anvil you write your server code in Python, and you call it from the client with a Python function call. And if you pass something into that server code, you want to be able to autocomplete it inside that server function.
So, as well as saving the top-level scope of every module (so it can be used in
import statements from other modules), we also store every outbound call from a module – including calls to the server.
So when we parse this client code, we store this outbound call, along with the types of its arguments. And then when we're parsing the server code for autocomplete, we can just pull out the type information for those arguments, and stick it into the local scope, where it autocompletes.
We can store a lot of information about types. This leads to a rather philosophical discussion about what, exactly, a type is.
You might say, "that's easy, the type of an object is its Python class". But of course, in Python, you can dynamically add attributes to individual object instances. And, arguably, even two dicts aren't really the same type.
So what we actually do is mostly forget the Python class – our autocompleter is duck-typed. As far as we're concerned, these two dictionaries are two separate types, with separate item mappings, and should be treated as such.
There's so much more I could talk about, but this is a short talk. And so, if you remember only one thing, make it this:
Ladies and gentlemen of Pycon UK 2017, use autocomplete!
Thank you very much.