Florian Rappl Technology enthusiast and solution architect in the IoT space.

The web app checklist

6 min read 1711

In this article, I’ll try to summarize some of the things that seem to be required to launch a web app (presumably in a business context) these days. I cannot give you any guarantee on completeness, so if you see anything missing from the lists below (or have some suggestions) please use the comments.

The list is structured by using different categories for the various bullet points. Inside the categories, two groups of items are used — either they seem to be required or are just recommended from my personal point of view. The classification may be different from your point of view.

Furthermore, I tried to explain my thought process reasoning for the category (specifically, why I think its items should be considered) in the beginning and added one example as illustration.


Before even implementing a web app, you need to think about some organizational and non-technical aspects. If the web app is developed in a team or should help to sustain a business the following list seems reasonable.

An open-source web app follows a similar pattern, even though things like backers and community acceptance are less predictable and in a slightly different ballpark.


  • Team agreed on technology set
  • Licenses, cost of infrastructure etc. covered
  • Operating model (including SLAs) determined
  • Business plan worked out
  • List of supported browsers is available


A list of supported browsers can be specified as simple as a Browserlist rule set, e.g., “last 2 versions, IE 10”. The great thing is that this rule set can be just added to the package.json of our web app and will be picked up automatically.

The addition can be as simple as:

Several tools exist, e.g., to export the rule set to a list of matching browsers.


Infrastructure has never been sexy, but it’s always necessary. You may have noticed that infrastructure complexity in a cloud-first, fully automated setup has increased. Unsurprisingly, so did the tooling. Having the right tooling makes infrastructure not only manageable but also fun and efficient.

Besides a state of the art CI/CD pipeline, we should definitely incorporate full error tracking. In the end, knowing what breaks and why is crucial for improving the web app. Being able to roll out changes rapidly helps us to become less vulnerable.


  • Build process fully automated
  • Error reporting (e.g., LogRocket) included
  • Data backup is in place and securely stored
  • Terraform (or similar) scripts available?
  • Scalability determined
  • Static resources are hosted on a CDN


To include advanced error reporting we usually only need to include a script and call an init function. Sometimes more sophisticated configuration (e.g., providing user-specific metadata) is useful, however, the crucial part of the job is already handled by just calling the init function.

As an example, we look at LogRocket:

  "browserslist": [
    "last 2 versions",
    "IE 10"

This is pretty much it! The rest is a (custom) mix of using the official tools to access the gathered data and the API for integration in our own tooling.

Technical Foundation

Obviously, having a solid architecture, sound business logic, and sufficient tests are required for any application to be considered stable and well-maintainable. Nevertheless, for web apps, some special rules apply.

Not only do we need to look for the smallest possible bundles of code and assets to serve (yet delivering a unique or even outstanding user experience), we also need to test our code against a variety of different browsers and screen sizes.

To make matters worse available APIs, ECMAScript specifications, and styling edge cases may be handled differently.


  • End-to-end tests for all supported browsers available
  • Emitted JS is bundled and minified
  • Emitted CSS is bundled and minified
  • Emitted CSS is auto-prefixed
  • Bundle structure encourages cache reuse
  • Emitted HTML is minified
  • All emitted resources can be cached (e.g., use hashed name)
  • Emitted HTML is minified
  • All emitted resources can be cached (e.g., use hashed name)


How we end up from plain sources with a minified, polyfilled, intelligently split bundle that can be easily cached and contains all kinds of wanted features depends strongly on our technology set. Some frameworks already come with a bundler out of the box.

A quite generic, yet easy to understand solution is Parcel. It also works against the previously defined browserlist and is framework agnostic. Out of the box (pun intended), it delivers TypeScript support, polyfills, production (minified etc.) builds, as well as hot module reloading.

Using it is as simple as running:

import LogRocket from 'logrocket';


The default output directory is usually the wanted one (“dist”).

Accessibility and mobile

When developing a web app we face a multitude of different target platforms. A website may be consumed in a non-graphical form. A website may be consumed by large devices with very odd inputs (e.g., only being able to go forward, backward, and into) or very small screens.

Furthermore, a website may be consumed by a variety connection types — fast, slow, limited, unlimited, and so on. If our app is to be successful, we need to find a balance that allows for most users to have a great experience.

More great articles from LogRocket:


  • A mobile-friendly view exists
  • Unnecessary resources are not downloaded
  • PWA enhancements are included (e.g. advanced caching)
  • Include noscript section(s)
  • Optimize link texts, image descriptions, and tab orders
  • Verify the color palette and background to foreground color ratio
  • A printer-friendly view exists


If we run, for example, Google Lighthouse on an SPA without any noscript element we will get a logical warning. Letting users know that the reason for not seeing anything (or not going beyond some loading spinner) can be found in missing JavaScript support is crucial for progressive web apps.

Google Lighthouse audit on a SPA without noscript.

Luckily, correcting this is as simple as adding a simple noscript message to the body such as:


One of our primary concerns should be to create a secure and trustful app that does not offer any vulnerability neither to access sensitive data of our users nor entering our system.

This obviously starts with an encrypted connection but also includes a reliable authentication and authorization scheme, as well as proper validation for any input.

Ideally, regular penetration tests against our application are performed.


  • No secrets, keys, or tokens are transmitted to the client
  • HTTPS is required and active for every call
  • The HSTS header is used
  • Upload fields are protected by a virus scanner service
  • Place, e.g., rel="noopener" on external links


Placing a noopener (or even nofollow) relation on anchor tags is straightforward.


Potentially, my background as a German (i.e., European) renders me especially sensitive to this topic, however, there is more to GDPR than just annoying “we use cookies” messages.

Understanding and valuing a user’s need for sufficient privacy and data protection is necessary to build a trustful environment.

Keep in mind that quite often the devil is not directly in our code, but in some component that we use for convenience.


  • A privacy consent notification is displayed once
  • Links for imprint, data protection, and further legal information available
  • Includes information about tracking, third-party integrations, use of data, etc.
  • Fine-grained control over used cookies and third-party integrations are possible


A simple option for integrating a compliant cookie disclaimer is to use a handy plugin like Cookie Consent.


Web apps today are anything but lightweight. We need to transport scripts, styling, fonts, images, and potentially even audio or video. Complicated logic created for multi-target purposes with multimedia background will never be lightweight, however, that does not mean it has to be slow.

Using proper caching, lazy loading, and efficient bundle splitting can help. Only loading what the user needs and wants is desired.


  • Lighthouse speed test (incl. different connection speeds) was conducted
  • Use HTTP/2 for all resources
  • Pre-load secondary resources (via <link>)
  • Place script as async at bottom


Preloading resources can be crucial for smooth user experiences. As an example using the preload for our style and script we get (taken from MDN):

Place it in the head before any of the mentioned resources appear. Depending on the position in the document the effect may be rather small, however, especially for resources loaded via JavaScript the effect can be pretty drastic.

Web analytics

Personally, I always have strong doubts about this one. Nevertheless, we need to learn from the (average) user somehow, hence the need for some anonymous tracking.

Even more significant may be the search ranking, which encourages us to follow some guidelines for search engine optimization.


  • A meaningful robots.txt is provided
  • Production tracking code supplied and right events tracked
  • Page transitions (SPA) tracked properly
  • Metadata (e.g. user properties) set up correctly


Providing a correct robots.txt can be as simple as supplying the following text file (served with text/plain as content-type) in the root directory:

This file will allow any robot (e.g., the Google search crawler) to access (i.e., index) all files. Additionally, we could place rules to disallow certain files or whole directories if wanted.

Fancy additions

Fancy additions give our app the extra touch that is needed to hook ordinary customers and fascinate tech-savvy people. They may appear in various forms, e.g., keyboard shortcuts, fancy loading spinners, useful recommendations, etc. These additions show that we actually care about our app and try to go the extra mile to make it super enjoyable.



  • In-app tutorials and useful help messages
  • Keyboard shortcuts


Things like QuestionMark.js are easy to set up yet give pro users even faster input possibilities.

QuestionMark.js integrated help dialog.


As mentioned already the given list does not try to be complete. It should rather be understood as a guideline to think in the right direction. Being prepared for the legal challenges, and potential problems is at least as crucial as having a sound and useful web app out there.

These links contain audits and checklists that are more complete and interactive. They certainly provide helpful checks to form a solid technical basis.


Get setup with LogRocket's modern error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to get an app ID.
  2. Install LogRocket via NPM or script tag. LogRocket.init() must be called client-side, not server-side.
  3. $ npm i --save logrocket 

    // Code:

    import LogRocket from 'logrocket';
    Add to your HTML:

    <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
  4. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • ngrx middleware
    • Vuex plugin
Get started now
Florian Rappl Technology enthusiast and solution architect in the IoT space.

Leave a Reply