Do You Really Need a Server? Build Your Minimum Viable Product Entirely Client Side

“Why do you need a server?”

It was the first week of GrowLab and we’d decided to throw out all our code and start from scratch. We were going to build a service that let you send data from your Gmail, Linkedin, Twitter, etc. to databases like Highrise and Salesforce. A browser extension seemed to be the perfect way to do that.

Paul and I were sitting across from David Ascher of the Mozilla Foundation, and I was telling him about my technical plans.

“Why do you need a server? Just put it all in localStorage.”

I didn’t have a good answer. I couldn’t come up with any kind of our users’ data that other users needed to see, or that had to sync across devices. Not for our MVP, at least.

Things started to click immediately. I could write this entirely client side and pretty much get the same effect?

Imagine how much development time that would save us! We could get to paying customers so much sooner that way.

But wait:

  • What about billing?
  • What about measuring what people are doing inside the app?
  • What about OAuth into other APIs?
  • What about reaching out to customers and doing remote support?
  • What about… What about…

Screw all that. The thought of going server-less was irresistible.

I ended up finding solutions to all of those issues without having a full-blown server of any kind. And explicitly not having a server allowed us to brag about our World’s Greatest Privacy Policy.

Here are the solutions we’ve implemented:

  • Billing – iFrame of a hosted payment page (we use Recurly – let me know in the comments if you want me to elaborate). Not perfect and definitely crackable, but who cares? If 1% of people figure it out then that’s the cost of saving development time to prove your product. And until you have enough customers you shouldn’t worry about that since it’s in favor of your users. (if someone for any reason pays and has to have this reset, make it easy to reach you and come up with some kind of promo code regex you give them to set it to paid.)

Breathe deeply. It’s okay. Unless your audience is web developers, this is totally fine for your MVP.

  • Analytics – Mixpanel Javascript library. Simply amazing.

Mixpanel lets you record events on the fly and analyze retention, trends, funnels, and segment by any properties you can think of.

  • OAuth and APIs – Some services can be OAuth’d client side, but for those that give you a client secret, set up a light Heroku instance of any language and framework (don’t even need a database) just for the initial handshake, then store auth and refresh tokens in localStorage for subsequent requests. (Let me know in the comments if you want me to elaborate on this)
  • Reaching out to customers and doing support - We store recent log statements and error stacks, and a user can click a “bug report” button that emails them to us so we can immediately address it. We use a light Heroku instance that just calls the Sendgrid API – done. No database.

So, do you really need a server for your MVP?

It may seem like we got away with no server because we connect extensively to web services where people do have user accounts. But this approach goes way beyond middleware and extensions.

Why can’t you get started entirely using localStorage with static pages? Besides the above solved problems, here are some common objections:

  1. My app needs to work across devices – really? This soon? Get some customers on one version first and let them beg you for it.
  2. What if someone clears their localStorage? – localStorage is harder to clear than cookies and cache, and how often do those things happen? Again, an edge case you shouldn’t worry about this early. You an always put a small warning up.
  3. My app requires I show aggregate data about others – As in you want to show the high score or the total number of votes a question received? No problem – get started with a CRUD database with a nice API like MongoLab and connect to the same database later server-side.
  4. I want to have a server and user accounts down the road, might as well start now – no worries mate, either assign people GUIDs in localStorage and later prompt them to create an account. Or pretend registration right now, with just email address, and ask them to create a password when you get a server set up. Or ask for a password now and store it, hashed. Yes localStorage is vulnerable to XSS attacks, but since you don’t have any dynamic content coming in from a server, you’re safe from that (Would love for someone more experienced to check my math – EDIT: someone did - probably best not to store a password and just procrastinate that prompt for one the day you get a server).
  5. I want to connect to external apis outside of my domain – many APIs support JSONP or CORS – check their docs for it – it could save you so much time.
  6. I need more than 2.5mb of space per user - okay get a server. Make sure you really do (i.e. you’re a photo site) You can be a Chrome-only app that requests unlimited storage permission, but that’s not the solution you probably wanted.

Benefits of a totally client side static app

  • Get to paying customers ASAP
  • Incredibly fast page loads and response times
  • Instant scalability – if five million people started using your site tomorrow, you could still sleep in, make breakfast, then crack open your computer, and nothing bad would happen.
  • Peace of mind – a tiny mistake won’t crash the server and you know that any problems are a direct result of your app code, nothing else like Amazon EC2 being down.

Totally happy without the cloud.

Of course, my favorite benefit: Bragging rights when you’ve actually built a company around your product. I was the butt of a few jokes and that made me want to prove the untraditional path we chose would work. (The GrowLab tech founders were all awesome and being around them made me a much better developer). Ignore those people who say things like “I don’t understand how you can build a company without a server” – even if they mean well.

In just four months, coming out of GrowLab we had customers, revenue, and a real business model. And that’s all I care about.

 

Posted by on July 20, 2012


I can send you my next post by email

  • Jon

    I for a long time was completly enthralled with the idea of having most if not all logic on the client, glad to see im not the only one who gets excited about the non-cloud :D

    • http://www.facebook.com/vibhor86 Vibhor Mahajan

      I’m very excited about this too buddy…

      Actually the weather is pretty cloudy here too… You might use facebook for authentication and maybe MongoLab for your cloud database and much more…

  • Pingback: Mentoring isn’t worthless after all! « david ascher

  • http://twitter.com/paulitex Paul Lambert

    here, let me fix that for you.. “Today we are the only company with customers, revenue, and a real business model, and named ecquire{1}”. There ya go.
    {1} https://www.thesunnytrail.com/pricing ;)

    • talsraviv

      Fixed. I drafted this before they launched three days ago.

  • http://twitter.com/jchris J Chris Anderson

    You can use PouchDB which is a wrapper on localStorage or IndexedDB, depending on your browser. So you write your app 100% client with PouchDB, and then you can sync all that data to Apache CouchDB when you feel like it. (Free Apache CouchDB available from more than one hosting provider.)

    http://pouchdb.com/

    • talsraviv

      That’s awesome – I was not aware of that.

    • http://twitter.com/fstephany francois stephany

      Wow !

  • David Bruant

    “localStorage is harder to clear than cookies …” no it’s not. The article you link to says it. It is actually recommanded by the webstorage page that “clear cookie” clears both storages.

  • David Bruant

    “Or ask for a password now and store it, hashed. Yes localStorage is vulnerable to XSS attacks,
    but since you don’t have any dynamic content coming in from a server,
    you’re safe from that (Would love for someone more experienced to check
    my math).”
    => It’s almost true. You’re in danger when any untrusted code reaches your user and run.
    This can happen if you have ads on your website (though the threat is small). This can also happen if your user is in a place where DNS is controlled by someone evil which serves different JavaScript than the one from your server. In that case too, the user can have its data stolen (but for the DNS, it’s so low-level that it’s hard to protect your app from it). For that matter both cases happen also when you have login/password.

    Also, I’m working on a project where localStorage would have a completely different security model which I think would suit your needs well https://github.com/DavidBruant/Extorage/tree/draft (it would also remove the 5Mo limitation). I don’t even have a working prototype yet, but contact me if you’re interested.

    • talsraviv

      Ok cool. Thanks for pointing that out. In that case, a client-side prototype shouldn’t go so far as to save a password, only upon switching to a real server should a password be created. I’ve edited the post to link to your comment.

      • David Bruant

        If on your account creation page and login page, you have no third-party code, I think you’re good, especially if you store the password hashed (so that untrusted code can only see the hashed version)
        As for DNS, it’s a very rare threat. Your decision really depends on what is to be won/lost against the probability and damage of the threat. You’ve done such an analysis with the has_paid and I think you’re in an equivalent situation. If I were you, I would still store the password hashed on the client-side. I was just trying to give you a taste of any attack that can exists. It doesn’t necessarily mean their probability is high enough to prevent you from doing storing the password hashed.

        Regarding security of client-side hashed password storage, you can use a “global” salt, but since it’s everything is on the client side, so is the salt, so view-source reveals it. Maybe you can still salt with a user-specific information like the generated GUID. It makes each user vulnerable to dictionary attacks, but not all users vulnerable to rainbow-table-based “attacks”.

        Send me an email if you want to discuss more in details about client-side security