Back to Blog

How We Made Our Parking Payments App 2.3x Faster With Svelte

At AirGarage, we partner with real estate owners to manage parking properties, handling everything from payments to enforcement. We quickly learned that mobile payments solve a lot of problems when it comes to parking - putting an end to traffic jams at the exit, pay machines that break down, and hiring lot attendants.

We built our first payment website using the popular framework React, which felt ahead of its time relative to many clunky parking websites. It was designed with the bare minimum number of form fields to allow drivers to pay as fast as possible. It still however, wasn’t the lightning-fast experience we wanted to deliver to drivers who were trying to get on with their days. We also realized we needed to handle challenging situations, from an underground garage with poor cell reception to a surface lot near a stadium during a game night’s evening rush.

We visited parking garages around the country to observe and talk to drivers, and we realized that  for a performance-sensitive app like Web Pay, React (or at least Create React App) wasn't going to take us where we needed to go. We migrated our payment site to SvelteKit, an up-and-coming web application framework.

Results

The results make it clear that Svelte and SvelteKit dramatically improved the speed and performance of the application and the driver experience. We saw:

  • 38% - 54% improvement for page load times. Page load time was measured by “performance tier”, and we saw massive gains across the board. This has made a huge difference with drivers. For example, take an area with poor cellular reception where the average driver used to wait 7-10 seconds for their page to load. Those same drivers now see load times of 3.3-4 seconds. At other locations with better reception, the new page loads almost instantaneously.
  • 20% reduction in driver bounce rate. Driver bounce rate is measured as drivers who load the parking form but never start their session. Sometimes they decide not to park at that lot, but often they bounce because they get stuck. A 20% reduction means the redesign addressed a lot of the biggest areas of confusion that drivers encountered.
  • 38s faster funnel speed. Funnel speed asks how quickly can drivers fill out the form and start their session. If drivers take a long time, it usually means the form isn’t simple enough. Before the rewrite, it took 1 minute and 29 seconds on average to pay for parking. With our Svelte redesign, the average driver can now pay for parking in just 51 seconds.

We also conducted extensive user research on the old and new experiences, to make sure what we were observing matched up with the metrics we were collecting. We did this by going onsite to parking garages and observing drivers trying to pay to park before/after, and by leveraging LogRocket to monitor sessions online.

After making some key improvements based on these qualitative observations, it was very clear that drivers had a much easier time with the new experience - which matched up with the metrics we were seeing! Now that we shared the results, the rest of this post will dive into the technical details to our process of evaluating different frameworks.

Picking a framework -  Next.js or SvelteKit

The main consideration when we evaluated frameworks was webpage load time, since we wanted to create a great experience for drivers connected to slow cellular internet. We use Sentry to track First Contentful Paint (FCP) and time-to-interactive (TTI) metrics and identify the bottlenecks. The majority of the team was convinced that backend improvements were the primary factor in page load time; however, tracing performance in a full-stack fashion showed that our API responded with decent performance (834ms P50, 2.93s P95). When we measured end-to-end load time which includes Javascript, we saw our P95 at 16s, so we concluded that we should focus more on frontend.

To pay for parking, drivers text “pay” to a phone number on our signs in the parking garage. With our old React setup, they receive a response with a link, and once they click it, they see a blank screen until the initial HTML document response. Then the HTML downloads some JavaScript (React). Our React application then shows a spinner as it makes API calls and tries to initialize our payment processor. Finally, once the API responses are available, it shows the form asking the user to pay for parking.

In order to improve FCP, we decided to use server-side rendering (SSR). With this pattern, we can make API calls from a fast, cloud-hosted server instead of throttled mobile devices. In addition to these hardware and network gains, we would also reduce the browser’s roundtrip calls from four to one. Moreover, instead of an HTML response with a spinner, we could show the intended experience already rendered in the initial response.

When it came to choosing a tech stack we considered adapting our React application to Next.js because it was the most popular full-stack web application framework when we were deciding (October 2022). Next.js offered great benefits such as isomorphic JavaScript, intuitive page organization, easy data loading and out-of-the-box tooling. This meant that we could keep writing React code and take advantage of its flourishing community.

In addition to improving FCP through SSR we were also eager to improve TTI. Since our payment processor could only be initialized on the browser, we wanted browsers to download assets as quickly as possible so that it could finish that process. This pushed us to care about how much JavaScript we were shipping. One drawback of Next.js is that the large React package (and ReactDOM) have to be bundled into the assets. Some in the community have tried replacing React with Preact which helped the overhead bundle size to decrease. We still decided to look around to see if there was a better solution to our bundle concerns.

That’s when we came across SvelteKit, which is based on Svelte. Svelte acts as a compiler, converting developed code into plain JavaScript and does not need to include any significant “library” code into its own bundle. The final asset collection ends up being much smaller than that of a project written in React.

SvelteKit draws inspiration from and offers a similar suite of features as Next.js since it was acquired by Next.js’ parent company, Vercel. Because of its similar patterns and its improved bundle size, SvelteKit looked like a better fit for an application that is as performance-sensitive as Web Pay. What followed was a series of debates about Next.js and SvelteKit. After making a couple proof-of-concept apps and diving into each framework, we all agreed that SvelteKit is both easy to learn and was highly likely to improve our performance over our current React implmementation and Next.js.

Our Svelte Experience

For the next two months, we got to work and built our application’s MVP in SvelteKit. There were a few core parts of our development that we will evaluate: UI components, application state, user interactions, API calls and page load, and finally, monitoring and observability. We had great learnings with respect to each:

UI Components: We found that developing reusable components was quite easy with Svelte. Styles are scoped within the component module (similar to that of CSS Modules or CSS in JS in the React ecosystem) simplified module development. In the rare occasion where we needed styles to expand beyond the component module, doing that was easy and did not reduce any confidence in having unexpected side effects. In order to keep our bundle size small, we didn’t use any UI or design system libraries. That meant we had to build a lot of responsive elements ourselves. An unexpected resource in this regard was the Svelte REPL (https://svelte.dev/repl/hello-world).

Application State: Svelte has a few tools to help with application-level state management. Svelte stores are reactive by design; therefore, engineers like most of us who started their journey with unidirectional data flow especially with React Context or Redux were pleasantly surprised by this refreshing paradigm shift. After using it a couple of times, it became clear to us how the Svelte compiler works, how variable assignments impact your state. We’ve also employed Svelte contexts a few times just to understand the difference between them and stores.

User Interactions: We have struggled with this in the beginning. Our application requires a complex form for users to fill out; and even though we found a form library (we went with Felte), we encountered some issues when we needed to customize some behavior. Our struggle was to determine exactly what was causing the odd behavior: Svelte, Felte, or our custom input component? In the end, we realized that Felte propagated events to communicate changes to the form’s store and we had missed that. Once we also started to raise events, our form worked as intended.

API Calls and Page Load: SvelteKit offers extensive documentation on how data is obtained during page load. Differences between SSR and client-side-rendering (CSR) are simplified through SvelteKit’s runtime stores. Authentication in SSR is handled by a customized “fetch” function that mimics the browser’s fetch functionality so common abstractions (such as a generic HTTP Client) are easy to develop in an isomorphic fashion. When we struggled and needed guidance, we found many answers on SvelteKit’s Github Issues. The maintainers are very responsive.

Monitoring and Observability: AirGarage’s monitoring-systems-of-choice are Sentry.io and DataDog. We also use Amplitude and LogRocket for analytics and user statistics. As our initial step, we decided to integrate Sentry.io. This has been the single most frustrating part of our journey because SvelteKit is still a new web application framework and still needs more open source community-driven contribution. We were able to find an official Sentry SDK written for Svelte; however, it wasn’t as helpful as we needed it to be because of a few reasons: sourcemaps, SSR and all navigation-related instrumentations are different from Svelte. As a team we have decided to write some of our own instrumentation and contribute to the open source development effort.

Designing the New Product Experience

We began the design process by auditing other parking apps to get a feel for what was out there. We were shocked to find out some parking products had over 20 steps, requiring users to download an app while standing in a dimly-lit parking garage while rushing to get to their appointment. In many cases, the UI was very difficult to navigate, with several pages and colors and form fields that all blended together.

We engaged members across operations, customer support, and product to understand what issues and pain points they are hearing from customers and seeing in the field. We diagrammed out the many different flows to Webpay (i.e. hourly, flat rate, multi-day, monthly…). We also experimented with different visual design, as many users are using their phones under the bright sun, for example our users in Los Angeles. We wanted to ensure that users are able to view their phones clearly, and that the contrast ratio of the UI is suitable for a majority of the users.

Once we agreed on the user experience for the different flows, we made high fidelity designs focusing on perfecting the details. For example, as our goal is to optimize for speed, we decided to use a skeleton loading page design, rather than the loading indicator that users currently see. This would reduce the feeling of users feeling as if the page were taking too long to load. This project was extremely rewarding as it brought together closely the product, design and engineering team, in addition to learning valuable input from the stakeholders.

Conclusion

You can see what our final Web Pay Svelte payment flow looks like here. If you get a chance to park in a property managed by AirGarage, we hope you find it fast and easy so you can get more time back in your day. Overall, moving to Svelte has proved to be a great decision - saving time for drivers, creating a better parking experience for garage owners, and empowering our engineering team to iterate faster and work with the latest technology. We saw an average speed improvement of 2.3x compared with our old React-based system, and have heard great feedback from both our customers and engineers.

Get a Proposal

Let us show you how we can increase your net revenue with a
custom proposal for your parking facility.