Case Studies¶
A PWA case study is only useful if you can see what was built, how it was measured and where the numbers come from. This page collects published Progressive Web App case studies from Twitter, Pinterest, Tinder, Nikkei, Flipkart, Uber, Starbucks, Google Search, Adobe Photoshop, Clipchamp, Kiwix, Excalidraw, Microsoft Teams and others. For each, it summarizes the context, the technical approach and the reported results, and links the primary source. Every number on this page links to a public source that states it; numbers that circulate online but can't be traced to a surviving primary source are left out, and the section on sources that no longer hold up says which ones.
Key takeaways
- Almost every headline result comes from shrinking the critical path: Pinterest cut its core bundle from 650 KB to 150 KB, Nikkei from over 300 KB to 60 KB, Tokopedia from 320 KB to 37 KB, and Uber built a 50 KB core app.
- Service workers were adopted incrementally: Twitter went from an offline page to static-asset caching to app-shell caching, and Pinterest from runtime-caching lazy chunks to precaching per locale.
- Big platforms gate the service worker: Google Search registered it only where navigation preload existed, the device had at least 2 GB of RAM and there was enough storage, and later retired that worker after reevaluating its trade-offs.
- Multi-page apps make good PWAs: Nikkei and Ele.me kept an MPA and still reported large gains.
- Many companies kept their native apps and used the PWA for reach: Ola, OYO (as a Trusted Web Activity) and X all run both. Others replaced a desktop wrapper with a PWA: Excalidraw dropped Electron, and Microsoft moved Teams on Linux to a PWA.
- Recent case studies are about capabilities, not speed: WebAssembly, the Origin Private File System, file handling and store distribution (Photoshop, Clipchamp, Kiwix, Goodnotes, Excalidraw).
- Most results are self-reported before/after comparisons published with Google, often confounded with a redesign. Treat them as evidence of what's possible, not as a forecast for your app.
How to read PWA case studies¶
Most of the famous numbers were published between 2016 and 2018, largely as Google Developers "showcase" pages that now live on web.dev/case-studies. Keep these caveats in mind:
- What was compared. Most compare a new PWA with the company's previous mobile website, not with its native app and not with a well-optimized non-PWA website. A rewrite that removes megabytes of JavaScript improves conversion whether or not it adds a service worker.
- What "PWA" means in each study. The label covers everything from a full rewrite with an app shell and push (Twitter Lite) to a performance project with a service worker added (Rakuten 24, Tokopedia). The service worker is rarely isolated as a variable.
- Measurement method. Only a few studies describe a controlled experiment. Rakuten 24 ran an A/B test; Google's I/O web app compared cohorts with and without a controlling service worker. Most report year-over-year or before/after changes.
- Survivorship and publication bias. Companies publish successes. There are no published studies of PWAs that didn't move metrics.
- Age. Many studies predate service worker support in Safari (2018), Core Web Vitals (2020) and web push on iOS (2023). Their technical details, such as
sw-toolbox, webpack'sCommonsChunkPluginor HTTP/2 server push, are historical. The lessons behind them still hold. - Attribution. "X reported" on this page means the number appears in the linked source, which is either the company's own engineering blog or a case study published with the company.
At a glance¶
| Company | Published | Type of app | Techniques | Headline result as reported | Source |
|---|---|---|---|---|---|
| Twitter Lite | 2017 | Social | PRPL, app shell, push, data saver | 65% more pages per session, 75% more Tweets sent | web.dev |
| 2017–2018 | Social | Route-based splitting, Workbox, app shell | Core engagements up 60% vs old mobile web | Dev Channel | |
| Tinder Online | 2017 | Social | Code splitting, budgets, Workbox | Main bundle 166 KB → 101 KB | Addy Osmani |
| Nikkei | 2018 | News (MPA) | Prefetch, SW cache-first, vanilla JS | 2.3× organic traffic, 58% more subscriptions | web.dev |
| The Weather Channel | 2016 | News | Push first, then PWA | 80% faster load time | web.dev |
| Flipkart Lite | 2016 | Commerce | Offline browsing, add to home screen | 3× time on site, 40% higher re-engagement | web.dev |
| AliExpress | 2016 | Commerce | Cross-browser PWA | 104% higher conversion for new users | web.dev |
| Starbucks | ~2017 | Ordering | React SSR, GraphQL | PWA 233 KB vs 148 MB iOS app | Nearform |
| Rakuten 24 | 2022 | Commerce | Core Web Vitals work, Workbox | A/B: 33.13% higher conversion rate | web.dev |
| Uber (m.uber) | 2017 | Mobility | Preact, SSR, 50 KB core | Interactive in ~3 s on 2G | Uber Engineering |
| Ola | 2017 | Mobility | 200 KB PWA | 68% more mobile traffic in Tier 2 and 3 cities | web.dev |
| OYO Lite | 2019 | Travel (TWA) | Trusted Web Activity | 850 KB download, 3× PWA conversion | web.dev |
| Google Search | 2019 (retired 2021) | Search | Navigation preload, gated registration | Half as much new JS on repeat visits | web.dev |
| Photoshop on the web | 2021 | Creative tool | Wasm, OPFS, Workbox precache | 75% less code initialization time | web.dev |
| Clipchamp | 2020 | Video editor | Wasm SIMD, install promotion | 97% monthly growth in installs | web.dev |
| Kiwix | 2023 | Offline reader | OPFS, File System Access | Multi-gigabyte archives offline | web.dev |
| Goodnotes | 2024 | Note-taking | SwiftWasm, TWA, PWABuilder | One Swift codebase on web, Android, Windows | web.dev |
Dates are the publication or "last updated" dates shown on the source pages.
Social and content platforms¶
Twitter Lite (now X)¶
Context. Twitter built Twitter Lite for instant loading, engagement and lower data consumption; it became the default mobile web experience for all users globally in April 2017. Google's case study was published in May 2017 (web.dev).
Technical approach. According to the case study:
- An application shell architecture following the PRPL pattern (push critical resources, render the initial route, pre-cache remaining routes, lazy-load the rest).
- Service worker adoption in stages: first a custom offline page, then caching of static resources, then caching of the application shell. Each stage shipped and was measured before the next.
- Web push notifications and an add-to-home-screen prompt.
- A data saver mode in which the user chooses which media to download, plus smaller images.
Reported results. Twitter reported a 65% increase in pages per session, a 75% increase in Tweets sent and a 20% decrease in bounce rate. The PWA was 600 KB over the wire, compared with 23.5 MB for the native Android app. It reported first loads under 5 seconds on 3G, boots under 3 seconds on repeat visits, a 30% reduction in average load time for logged-in users, a 50% reduction in 99th-percentile time-to-interactive, up to 70% less data consumed through image optimization, 250,000 unique daily users launching from the home screen about 4 times a day, and more than 10 million push notifications delivered daily. All figures: web.dev case study.
What you can observe today. The manifest served at x.com/manifest.json (fetched September 2026) shows how the app evolved: display: "standalone", a share_target that accepts files (multipart/form-data to compose/tweet), four shortcuts (compose, explore, notifications, messages) with utm_source=jumplist markers, a start_url with utm_source=homescreen, and related_applications pointing to the Android app with prefer_related_applications: true. That last flag tells Chromium to promote the native app instead of the PWA where the native app is available. See App Shortcuts, Web Share Target and Launch attribution.
Lessons.
- Roll the service worker out in layers that each deliver value on their own. An offline page is useful and nearly risk-free; app-shell caching needs an update strategy.
- Measure tail latency (the 99th percentile), not only averages. The users on the worst networks are the ones a PWA helps most.
- Give users control of data cost. A data saver is a product feature, not only an engineering optimization.
Pinterest¶
Context. Pinterest's old mobile website converted poorly. Addy Osmani's case study, written with Pinterest (Dev Channel, November 29, 2017), says that only 1% of unauthenticated mobile web users converted into sign-ups, logins or native app installs. Pinterest rebuilt the mobile web experience in about three months ("Project Duplo") with React, Redux and webpack. The team's own retrospective (Pinterest Engineering, July 20, 2018) describes the timeline: rewrite started July 2017, logged-in users moved in August–September 2017, logged-out users in January–February 2018.
Technical approach.
- Route-based chunking. A vendor chunk (~73 KB), an entry chunk with the app shell and Redux store (~72 KB) and async route chunks (~13–18 KB each), with content hashes in file names for long-term caching.
- Duplicate-code consolidation. Moving code duplicated across async chunks into the entry chunk grew it by 20% but shrank lazily loaded chunks by up to 90%.
- Service worker with Workbox, rolled out in steps: runtime caching of lazily loaded scripts first (to benefit from V8's code cache on repeat views), then precaching the vendor and entry chunks, then precaching the most-used routes, then a separate service worker build per locale to precache locale bundles and support basic offline rendering.
- A cached, user-specific app shell. The shell contained user and experiment data to avoid a render-blocking request. Each API response carried an
appVersion; when it changed, the app unregistered the service worker, registered the new one and did a full reload on the next route change. - Normalized Redux state (normalizr, reselect), so a tap on a Pin in a feed could render immediately with the data already in the store while details loaded.
- Bundle-size alerts and a custom ESLint rule that blocks imports from dependency-heavy code, reported in the retrospective.
Reported results. From the performance case study: time spent up 40% compared with the old mobile web experience and core engagements up 60%. The core bundle went from 650 KB to 150 KB, First Meaningful Paint from 4.2 s to 1.8 s and Time to Interactive from 23 s to 5.6 s on average Android hardware over slow 3G, and to 3.9 s on repeat visits with service worker caching. The home feed cost about 150 KB minified and gzipped on the web, versus 9.6 MB to install the Android app and 56 MB for iOS, which the article notes is not an apples-to-apples comparison. From the retrospective, one year on: weekly active users on mobile web up 103% year over year, session length up 296%, logins up 370% and new signups up 843%, with 800,000 weekly users using the PWA from the home screen less than six months after full launch.
What you can observe today. www.pinterest.com/manifest.json (fetched September 2026) is served per device class: a desktop user agent gets display: "minimal-ui" and an Android one gets display: "standalone". Both use a start_url with utm_source=homescreen_icon and several related_applications entries: Google Play packages (including one named com.pinterest.twa) and a webapp entry pointing at the manifest itself, which is what getInstalledRelatedApps() needs to detect the installed PWA (Detecting Installed Apps).
Lessons.
- Put performance guardrails in CI, not in a one-time project. With about 600 JavaScript files a year later, "all it takes is one ill-chosen import to bloat your bundle", as the retrospective puts it.
- Caching a personalized app shell is powerful but needs explicit invalidation: logout, settings changes and version changes.
- Precache per locale if you serve many languages; one global precache either misses locale bundles or downloads all of them.
Tinder Online¶
Context. Tinder launched Tinder Online, a responsive PWA for desktop and mobile, to reach new markets. Addy Osmani's case study (December 24, 2017, also published on the Web Performance Calendar) says the MVP took three months with React and Redux, and delivers the core Tinder experience in 10% of the data-investment cost (2.8 MB) for someone in a data-costly or data-scarce market.
Technical approach.
- Route-level code splitting with React Router and React Loadable, plus preloading of the likely next route's chunk.
- Performance budgets: about 155 KB for main and vendor chunks, about 55 KB for asynchronous (lazily loaded) chunks, about 35 KB for other chunks and 20 KB for CSS.
<link rel="preload">for critical bundles, atomic CSS with critical styles inlined (under 20 KB gzipped, recent builds under 11 KB).requestIdleCallback()to defer instrumentation beacons during swiping, which is a good pattern for analytics on interaction-heavy screens.- The Workbox webpack plugin to cache the application shell and core static assets.
- Replacing localForage with direct IndexedDB use to cut library weight.
Reported results. On WebPageTest with a Galaxy S7 over 4G, the PWA loaded and became interactive in 5.9 seconds. After route-based code splitting, the main bundle went from 166 KB to 101 KB and DOMContentLoaded from 5.46 s to 4.69 s. Preloading critical bundles cut load time by about 1 second and first paint from about 1000 ms to about 500 ms. With Atomic CSS, average page load times measured in Google Analytics went from about 6.75 s to about 5.75 s. Upgrading to React 16 cut the vendor chunk by about 6.7%, and webpack 3's scope hoisting cut the vendor bundle's initial parse time by 8%. Qualitatively, the article reports that users swiped, messaged and edited profiles more on the web than in the native apps, and purchased on par with them.
Lessons.
- Budgets per chunk type are easier to enforce than a single total.
- Third-party SDKs dominate once your own code is lean: the article identifies a 200 KB Facebook SDK script in the critical path, which could be lazy-loaded, as a remaining one-second opportunity.
Nikkei¶
Context. Nikkei, a major Japanese business newspaper with over 450 million monthly visits to its digital properties, rebuilt its site as a multi-page PWA, launched in November 2017. Five core engineers worked on it for a year (web.dev, last updated November 2018).
Technical approach.
- A multi-page app in vanilla JavaScript, not a single-page app framework.
- JavaScript reduced from over 300 KB to 60 KB (80% less), bundled with Rollup.
- Critical CSS inlined, which reduced First Meaningful Paint by more than a second.
<link rel="preconnect">to third-party origins and dynamic<link rel="prefetch">of the likely next page, which made loading 75% faster.- A service worker with a cache-first strategy, a web app manifest, compression through a CDN, an image CDN, and lazy loading with
IntersectionObserver.
Reported results. Lighthouse performance score from 23 to 82, Time to Interactive 14 seconds faster, 2.3× organic traffic, 58% more subscriptions, 49% more daily active users and 2× page views per session.
Lessons. You don't need an SPA to build a PWA. An MPA with prefetching, a small script budget and a service worker gets most of the benefit, and server-rendered pages are the best case for SEO. SPA vs MPA PWAs covers the trade-offs.
The Weather Channel¶
Context and approach. The Weather Channel started with push notifications for severe weather on Android and desktop Chrome, then built a full PWA for its international sites before the complex US site (web.dev, last updated November 2016).
Reported results. Almost 1 million users opted in to web push within three months, 52% of them on mobile. The PWA shipped in 62 languages to 178 countries from one codebase, with an 80% improvement in load time.
Lessons. Push can be the first PWA feature you ship, if the notifications are genuinely time-critical. Launch where the risk is lowest (international sites here), then expand.
Commerce and marketplaces¶
Flipkart Lite¶
Context. In 2015, Flipkart, India's largest e-commerce site, adopted an app-only strategy and temporarily shut down its mobile website. It then came back to the mobile web with Flipkart Lite, a PWA. Google's case study was last updated in March 2016 (web.dev).
Technical approach. A service worker for offline browsing of categories, search history and product pages; a streamlined design for fast loading; and add to home screen for re-engagement.
Reported results. Time on site of 3.5 minutes versus 70 seconds before (3× more), a 40% higher re-engagement rate, and a 70% higher conversion rate among users arriving through Add to Home Screen. Flipkart reported 3× lower data usage than its native app, that 63% of Flipkart Lite users were on 2G networks, and that 60% of visits came from the home screen icon.
Lessons. For markets dominated by slow networks and low-storage devices, the web can win back users an app-only strategy lost. Home screen users are a self-selected, high-intent segment; compare them to similar users, not to all visitors.
AliExpress and Alibaba.com¶
AliExpress built a cross-browser PWA at m.aliexpress.com. It reported a 104% increase in conversion rate for new users across all browsers, an 82% increase in conversion rate on Safari, 2× more pages per session and 74% more time per session (web.dev, last updated May 2016). At the time, Safari didn't support service workers, so the Safari gains came from speed and design, not offline support.
Alibaba.com, the B2B marketplace, reported 76% higher conversions across browsers (a conversion being direct contact with a supplier), 14% more monthly active users on iOS and 30% on Android, and a 4× higher interaction rate from users who added the site to the home screen. It also reported push notification open rates on the mobile web equal to those of its native app (web.dev, last updated November 2016).
Lesson. The biggest wins on iOS came before iOS supported the PWA-specific APIs: they came from speed. That is still the lesson for iOS and iPadOS today.
Konga and Jumia: data cost in African markets¶
Konga, a Nigerian e-commerce site, measured data usage as its primary metric. Compared with its native app, the PWA used 92% less data for the initial load and 82% less to complete the first transaction; compared with its previous mobile website, 63% less for the initial load and 84% less to complete the first transaction. Users could browse categories and previous searches offline (web.dev, last updated May 2016).
Jumia reported for Jumia Travel a 33% higher conversion rate and 50% lower bounce rate than its previous mobile website, 12× more users on the PWA than on its native apps, and 25× less device storage needed. It describes the PWA as offline-first (web.dev, last updated May 2017). The page's summary and body give different data-savings figures for the first transaction, so those are omitted.
Lesson. Pick metrics that match your users' constraints. For users paying per megabyte, bytes to first transaction are a better success metric than Lighthouse scores.
Lancôme¶
Lancôme rebuilt its mobile site as a PWA with Mobify after mobile traffic overtook desktop but mobile conversion (15% of carts) lagged far behind desktop (38%) (web.dev, last updated May 2017). It reported an 84% decrease in time until interactive, a 17% increase in conversions, a 15% decrease in bounce rate and a 51% increase in mobile sessions. On iPhones, 65% of its PWA users, it reported a 53% increase in session length and a 10% bounce-rate decrease, even though add to home screen, push and offline caching weren't available on iOS then. On Android, over 18,000 shoppers subscribed to push; 8% of those who tapped a notification made a purchase, and push reminders for abandoned carts reached an 18% open rate. The page reports two different figures for the conversion uplift on recovered carts (8% in its summary, 12% in its results list), so that number is omitted here.
Starbucks¶
Context and approach. Starbucks worked with Formidable (now part of Nearform) on a PWA for ordering on the web, built with React using server-side rendering and a GraphQL API that handles the complex validation rules of drink customization and pricing (Nearform).
Reported results. The PWA was 233 KB, compared with 148 MB for the iOS app: 99.84% smaller, as the agency reports.
Lessons. Ordering flows with complex business rules benefit from keeping the rules in one API (GraphQL here) shared by web and native clients. The size comparison is the argument for a web entry point, not a replacement for the app.
Rakuten 24¶
Context. Rakuten 24, an online store run by Rakuten in Japan, invested in Core Web Vitals and measured the business effect with an A/B test (web.dev, last updated August 2022).
Technical approach. JavaScript optimization and code splitting, image optimization and lazy loading, layout stability with CSS aspect-ratio and min-height, field measurement with the web-vitals library, and service worker caching with Workbox.
Reported results. In the A/B test between the optimized and the original landing page: revenue per visitor up 53.37%, conversion rate up 33.13%, average order value up 15.20%, time spent up 9.99% and exit rate down 35.12%.
Lessons. This is one of the few studies with a controlled experiment. If you want to know what performance work is worth for your business, run one. Core Web Vitals and Measuring Performance cover the instrumentation.
Tokopedia¶
Tokopedia, an Indonesian marketplace, built a lightweight homepage for first-time visitors with Svelte while a service worker cached the full app's assets in the background (web.dev, last updated October 2020). It reported app JavaScript cut from 320 KB to 37 KB (88% less), Time to Interactive improved by 4 seconds, First Contentful Paint under 1 second, a 35% higher click-through rate and 8% more conversions. Budgets were enforced in CI with a Lighthouse-based dashboard, Resource Timing, Server-Timing headers and the PageSpeed Insights API.
Lesson. A "lite" first-visit experience plus background precaching of the full app is a clean way to optimize for both search landings and returning users. See Precaching & Runtime Caching.
Mobility and travel¶
Uber (m.uber)¶
Context. Uber rebuilt m.uber.com as a PWA to make ride requests work on low-end devices and 2G networks in new markets. Angus Croll described the work on Uber's engineering blog on June 27, 2017 (m.uber: Building a Superfast Web App).
Technical approach.
- Preact instead of React: 3 KB gzipped and minified versus about 45 KB, as reported in the article.
- Server-side rendering of the initial view with inlined state, then code splitting so ancillary features load later.
- A service worker caching HTML and JavaScript bundles, and
localStoragefor volatile ride-status data so the app re-renders instantly when the user returns. - Styletron for atomic CSS-in-JS, inline SVG icons (the logo went from 7.4 KB as PNG to 500 bytes as tuned SVG), no custom fonts, and heavy data transformations kept on the server.
Reported results. A core app of 50 KB gzipped and minified, interactive in about 3 seconds on 2G networks (the article's test assumed 250 kB/s and 300 ms latency).
Lessons. Set the budget from the worst network you want to support, then choose libraries to fit it. Keep computation on the server when the client is the constraint.
Ola¶
Ola, the Indian ride-hailing company, built a PWA for Tier 2 and Tier 3 cities where users had intermittent connectivity and low-end phones (web.dev, last updated May 2017). Ola's native apps were a 60 MB (Android) and 100 MB (iOS) download; the PWA needed 200 KB, and repeat visits as little as 10 KB, with a 3.4-second first visit on 2G and 3G. Ola reported a 68% increase in mobile traffic from Tier 2 and 3 cities, PWA conversion equal to the native app in Tier 2 cities and 30% higher in Tier 3 cities, and that 20% of users booking through the PWA had previously uninstalled the app. Ola's CTO is quoted saying the company intended to keep both the app and the PWA.
Lesson. The PWA reached people the app had lost: users who uninstalled it for storage reasons. Measure that segment explicitly.
OYO Lite: a Trusted Web Activity¶
OYO Rooms had both a PWA and an Android app. The app converted three times as often, but users uninstalled it over time because of storage concerns. OYO built OYO Lite, a Trusted Web Activity wrapping its existing PWA, verified with Digital Asset Links and published on Google Play (web.dev, last updated November 2019). By keeping most assets in Chrome's cache, the download was 850 KB, 7% of the size of its Android app. OYO reported a conversion rate three times higher than the PWA's, three times more logged-in users than the PWA, and a 4.1 rating on Google Play.
Lessons. Store presence can be worth more than the technology difference. A TWA lets you get it from the same codebase; Publishing to App Stores covers the other stores.
Productivity, media and creative tools¶
Case studies after 2020 shift from load times on 2G to desktop-class capabilities: WebAssembly, large local files, file handling and store distribution.
Photoshop on the web¶
Adobe brought Photoshop to the browser by compiling its C++ codebase to WebAssembly with Emscripten (Photoshop's journey to the web, October 2021). The article describes:
- WebAssembly threads, exception handling and SIMD. For Halide, which the article calls essential to Adobe's performance, SIMD provides a 3–4× speedup on average and 80–160× in some cases.
- Origin private file system access handles, developed for Photoshop's need to page data in and out like an OS virtual memory system, and first shipped as an origin trial. Today they're the synchronous access handles of the Origin Private File System.
- Display P3 color in canvas.
- A Workbox-generated service worker that precaches JavaScript and WebAssembly. When a service worker serves a cached WebAssembly response, Chrome generates and stores an optimized version of the compiled code. Adobe estimated that the service worker and V8's code caching together cut the time spent on code initialization by 75%.
- A UI built from Lit-based Web Components.
Lesson. For large Wasm apps, a precaching service worker isn't only an offline feature: it's the mechanism that unlocks compiled-code caching.
Clipchamp¶
Clipchamp, an in-browser video editor now owned by Microsoft, does all video processing locally to avoid uploading gigabyte-scale files (web.dev, last updated December 2020). The team moved from Portable Native Client to WebAssembly, used Wasm SIMD (then in an origin trial) to speed up 4K decoding and encoding, and integrated WebCodecs (also in an origin trial at the time). They promoted installation with a toolbar button and a notice in the menu.
Reported results. A 2.3× performance improvement from Wasm SIMD, achieved by one engineer in under a month; 9% higher retention for PWA users than for standard desktop users; and installations growing 97% a month for the five months after launch.
Lesson. Promote installation where users work (a toolbar), not in a modal on arrival. Install Prompts & Custom UI has the patterns.
Excalidraw: replacing Electron with a PWA¶
The Excalidraw project deprecated its Electron wrapper, Excalidraw Desktop, in favor of the installable web app (web.dev, January 2021, cross-posted from the Excalidraw blog). The article's reasons: the Electron app was essentially the web app in an .asar bundle; auto-update, installers, code signing and file associations needed per-platform work (file associations didn't reliably work on Windows 10); and the web platform's capabilities (installation, file handling, the File System Access API) covered what the project needed.
What you can observe today. The manifest at excalidraw.com/manifest.webmanifest (fetched September 2026) declares an explicit id, file_handlers for .excalidraw files with the MIME type application/vnd.excalidraw+json, and a POST share_target that accepts those files. See File Handling and File System Access.
Lesson. If your desktop app is your web app in a wrapper, compare the wrapper's maintenance cost with what Desktop Platforms now offer PWAs directly.
Microsoft Teams on Linux: a PWA instead of a desktop client¶
Microsoft's Teams desktop client for Linux, an Electron app, lagged behind the Windows and macOS clients. In November 2022 Microsoft announced general availability of the Teams PWA for Linux as a feature of its existing web client (Microsoft Teams Blog), and the Linux desktop client was retired in December 2022 (Microsoft Community Hub, September 2022). Microsoft's stated reasons were that the PWA "enables us to ship the latest Microsoft Teams features faster to our Linux customers" and closes the gap with the Windows client. The announcement lists:
- Availability in both Microsoft Edge and Google Chrome on Linux.
- Meeting features the old client lacked: custom backgrounds, gallery view, reactions, raise hand, large gallery and Together mode.
- Desktop-like integration: system notifications for chats and channels, a dock icon with controls, application auto-start, and easy access to system app permissions.
- Conditional Access policies applied through Endpoint Manager, so administrators can allow Linux users into Teams while requiring Edge.
Microsoft's admin documentation for the Teams PWA, which now covers Teams on the web on any desktop OS, shows how an enterprise deploys a PWA without asking users to click an install button:
| Group policy (Edge and Chrome) | Purpose |
|---|---|
WebAppInstallForceList | Force-installs the PWA. Users can't uninstall it, and removing the policy uninstalls it. |
WebAppSettings | Further per-app management settings. |
SleepingTabsBlockedForUrls | Keeps Teams tabs from being put to sleep (Edge). |
NotificationsAllowedForURLs | Grants notification permission up front. |
ScreenCaptureAllowedByOrigins, AudioCaptureAllowedUrls, VideoCaptureAllowedUrls | Pre-approve screen sharing, microphone and camera. |
CookiesAllowedForUrls | Unblocks cookies, including third-party cookies used by line-of-business apps. |
Microsoft hasn't published usage metrics for the change, so none are given here.
Lesson. For a platform with a small share of your users, a PWA built on the web client you already ship can be better maintained than a dedicated native or Electron client. The desktop integration users expect (notifications, dock or taskbar presence, launch on login) is part of the installed PWA experience in Chromium browsers, and managed browsers let administrators install the app and pre-grant its permissions by policy; see Desktop Platforms and Permissions.
Kiwix: gigabytes offline in the browser¶
Kiwix makes web content such as Wikipedia available offline as compressed ZIM archives. Its PWA lets users download and read archives entirely in the browser (web.dev, November 2023). English Wikipedia with images is 97 GB as a ZIM file; a themed archive such as WikiProject Medicine is 1.7 GB. The PWA first used the File System Access API to open archives the user picked, then added the Origin Private File System so archives can be downloaded or imported into browser-managed storage and opened with no permission prompts. The article describes using navigator.storage.estimate() to check space before a download, streaming files into the OPFS, and the gaps between engines at the time of writing: Firefox supports the OPFS but not the File System Access pickers, so the app must not depend on showOpenFilePicker(); Firefox capped the OPFS quota at 10 GB regardless of free disk space; and without showSaveFilePicker() on mobile browsers and desktop Firefox, large files can't be exported from the OPFS, leaving them "effectively trapped" there.
Lessons. The OPFS turns multi-gigabyte offline content into a realistic web use case. Check quota first and handle storage pressure; Storage Quotas & Persistence explains eviction and persist().
Goodnotes: one Swift codebase everywhere¶
Goodnotes, an iPad note-taking app, brought its existing Swift code to the web with WebAssembly via the SwiftWasm toolchain, rather than rewriting it (web.dev, February 2024). The result is a PWA available on the web, ChromeOS, Android and Windows. The article describes distribution through app stores with Trusted Web Activities on Android and PWABuilder for the Microsoft Store, offline support built on IndexedDB and the storage available to browsers, and a Wasm binary download of about 40 MB that made service worker caching essential. The team's advice: even if you don't want users to install the app, include a service worker so the Wasm binary is cached and served locally.
Lesson. Large Wasm payloads change the economics of caching: the first download is expensive, so repeat visits must never pay it again. Precaching & Runtime Caching and Workbox Fundamentals cover how.
Squoosh¶
Squoosh is Google Chrome Labs' image compression app, built as a showcase PWA and open-sourced on GitHub. Its README describes it as an image compression web app in which "all image compression processes locally", and the repository's codecs directory contains the WebAssembly builds of encoders and decoders such as MozJPEG, WebP, AVIF, JPEG XL, OxiPNG and libimagequant. The README also documents that the app reports, "if Squoosh PWA, the type of Squoosh installation" and the installation time, which is exactly the install analytics described in Analytics for PWAs.
The manifest at squoosh.app/manifest.json (fetched September 2026) shows two attribution markers: start_url is /?utm_medium=PWA&utm_source=launcher, and the share_target posts images (multipart/form-data, image/*) to /?utm_medium=PWA&utm_source=share-target&share-target.
Lesson. Mark every entry point in the manifest so launches from the icon and from the share sheet are distinguishable in analytics.
SVGcode¶
SVGcode, a raster-to-vector converter by Thomas Steiner, is a compact example of a desktop-style PWA (web.dev, November 2021). It uses Potrace compiled to WebAssembly, is fully offline after installation, registers as a file handler for image files, opens and saves with the File System Access API, copies with the Async Clipboard API, shares with the Web Share API and customizes the title bar with Window Controls Overlay.
Spotify¶
Spotify's web player at open.spotify.com and its desktop client share one UI. Spotify's engineering blog (Building the Future of Our Desktop Apps, April 7, 2021) explains that the desktop client is a native Windows and macOS application that uses the Chromium Embedded Framework (CEF) to display a web-based UI, and that Spotify chose the web player's React codebase as the foundation for both. TypeScript platform APIs abstract the different data sources and playback stacks, so the same UI runs on the web and on desktop infrastructure.
The web player is also installable: its manifest (fetched September 2026) sets display: "standalone", a start_url with utm_source=pwa_install, and an edge_side_panel member for Microsoft Edge's sidebar. Spotify hasn't published PWA-specific metrics, so none are given here.
Lesson. A platform abstraction layer lets one web UI serve a browser tab, an installed PWA and a native shell. The same idea applies if you ship a PWA alongside a wrapper app.
Platform-scale service worker deployments¶
Google Search¶
Jeff Posnick's account of bringing service workers to Google Search (web.dev, June 20, 2019) is the most detailed public description of a service worker deployment at scale.
Goals. Limited local caching of repeated searches with fine-grained freshness control; a meaningful offline experience in which a search can be entered offline and sent later with Background Sync; and smarter JavaScript caching that "unbundles" requests for multi-module bundles and fulfills them from locally cached modules.
The blocker: service worker startup cost. Google Search had previously blocked launches that added even tens of milliseconds of latency for a user population. Search result HTML is dynamic and must come from the network, so a worker can at best pass navigations through. Without navigation preload, starting the service worker and running its fetch handler is pure overhead before that network request. Real-device measurements showed a wide distribution of startup times, with some low-end mobile devices taking almost as long to start the worker as to fetch the results page's HTML.
Solutions described in the article.
- Navigation preload, which starts the navigation request in parallel with worker startup. The article calls it "the single, most crucial feature that allowed the Google Search team to move ahead" with the launch: as long as startup is faster than the network response, the worker adds no latency.
- Gated registration. The worker was registered only if the browser supported navigation preload, the device had at least 2 GB of RAM, and
navigator.storageshowed enough free space for caches that could run to several megabytes. Targeting only modern browsers also removed transpilation and polyfills, cutting about 8 KB of uncompressed JavaScript from the worker. - A dispatch and routing framework inside the worker. Scope is a path prefix, and
/searchis shared by result types built from different codebases (Image Search and Shopping Search use the same path with different query parameters). The worker checks criteria such as the client page's query parameters to decide which code path runs, so other teams can add their own logic later. - Cookies sent with
postMessage(). Signed-in state lives in cookies, which the worker couldn't read. Each controlled page reads the relevant cookies and posts them to the worker; on a mismatch, the worker purges user-specific data and reloads the page without the wrong personalization. The Cookie Store API now covers this need in service workers in browsers that support it. - A dynamically generated service worker script per user, carrying the experiment configuration. It doubles as a kill switch: the server can return a no-op worker to disable the service worker for some or all users (see Updating Service Workers).
- Controlled update checks. The script is served with
Cache-Control: private, max-age=1500(25 minutes) and registered withupdateViaCache: 'all', so the browser honors that header during update checks, and anETaglets the server answer later checks with304. Because backends are updated in a rolling fashion, a shorter check interval would make users flip-flop between worker versions.
A gate in the same spirit, with thresholds you choose for your own app:
const MIN_DEVICE_MEMORY_GB = 2; // the threshold Google Search used for "low-end"
const REQUIRED_FREE_BYTES = 20 * 1024 * 1024; // what your caches need
async function deviceQualifies() {
if (!("serviceWorker" in navigator)) return false;
// Without navigation preload, a pass-through worker delays every navigation.
if (!("navigationPreload" in ServiceWorkerRegistration.prototype)) return false;
// Device Memory API: Chromium only, rounded to a power of two and capped.
// Other engines return undefined; decide explicitly how to treat "unknown".
const memory = navigator.deviceMemory;
if (typeof memory === "number" && memory < MIN_DEVICE_MEMORY_GB) return false;
if (navigator.storage?.estimate) {
try {
const { quota = 0, usage = 0 } = await navigator.storage.estimate();
if (quota - usage < REQUIRED_FREE_BYTES) return false;
} catch {
return false; // estimate() can reject in restricted contexts
}
}
return true;
}
addEventListener("load", async () => {
try {
if (!(await deviceQualifies())) return; // the site works fully without it
await navigator.serviceWorker.register("/sw.js", {
// Let the HTTP cache (for example max-age=1500) throttle update checks.
updateViaCache: "all",
});
} catch (error) {
console.warn("Service worker registration skipped:", error);
}
});
The worker itself must still call self.registration.navigationPreload.enable() in its activate handler and use event.preloadResponse; see Navigation Preload. Note that updateViaCache: "all" is a deliberate trade-off: a bad worker can stay installed for up to the max-age, which is why Google Search paired it with a server-side kill switch.
Reported results. On average, repeat visits handled by the service worker downloaded half as much new JavaScript, which the article says directly led to 6% fewer delayed user interactions.
The Google Search service worker was retired
An update added to the article in October 2021 says that the Google Search team "reevaluated the benefits and tradeoffs" of its service worker architecture, that the service worker described "is being retired", and that the team may revisit the design as its infrastructure evolves. The article remains the best public description of the engineering, but it isn't evidence that google.com runs a service worker today.
Lessons. A service worker that only passes navigations through to the network makes pages slower unless you use navigation preload or the newer Static Routing API. Registration can be conditional; users without the worker still get the full site. And a service worker is an ongoing operational commitment: when the costs outweigh the benefits for your traffic, retiring it (with a no-op or self-unregistering worker) is a legitimate outcome.
The Google I/O 2016 web app¶
Philip Walton's analysis (Measuring the Real-world Performance Impact of Service Workers, 2016) instrumented the I/O conference PWA with a custom analytics dimension recording whether a service worker controlled the page (controlled), was supported but not yet controlling (supported), or wasn't supported (unsupported). Almost 85% of page views came from browsers that supported service workers. The median time to first paint for pages not yet controlled by a service worker (supported) versus controlled pages was 912 ms versus 583 ms on desktop, and 1,933 ms versus 1,634 ms on mobile. The data covers May 16 to 22, 2016. The distribution for controlled pages had a second peak, which the author traced to service workers whose thread was inactive and had to be started.
Lesson. Compare cohorts rather than before/after, and look at distributions, not just medians. The same dimension is part of the instrumentation in Analytics for PWAs.
Ele.me¶
Ele.me, China's largest food-ordering platform at the time, kept a multi-page architecture because separate business units ran separate services on one domain (web.dev, last updated September 2017). It applied the PRPL pattern per page: <link rel="preload"> for critical resources, skeleton screens pre-rendered with Vue.js server-side rendering so each navigation paints immediately, and a service worker that precached the JavaScript, CSS and images of critical routes (collected by a webpack plugin) while caching less critical routes at runtime. It reported loading time down 6.35% on average across all pages and 11.6% across precached pages, with time to consistently interactive at 4.93 seconds on 3G on first load.
Case studies whose numbers can't be verified¶
Some of the most-quoted PWA statistics no longer have a working primary source, or the primary source doesn't contain the quoted number. They're excluded from this page:
- Trivago. The widely quoted engagement and click-out figures came from a Google marketing article and a Google Developers showcase page that now redirect to generic landing pages.
- Forbes. Google's Forbes case study page still exists but no longer contains any results.
- Starbucks daily active users. Commonly cited alongside the 233 KB figure, but the source usually given is a social media post, not a Starbucks or agency publication.
- Tinder load times. Summaries often quote total load-time figures that don't appear in the text of the case study they cite; the figures reported in the article's text are used above instead.
- Twitter/X, Microsoft Outlook and Office, Photopea and many others have installable PWAs today, but haven't published recent, sourced metrics about them. Where a company has published technical details without metrics (Spotify, Microsoft Teams on Linux), this page describes the approach only.
If you cite PWA statistics in a proposal, link the primary source and check it still says what you're quoting.
Patterns across the case studies¶
The critical path is the product¶
Reported JavaScript reductions across the studies:
| Company | Before | After | Source |
|---|---|---|---|
| Pinterest (core bundle) | 650 KB | 150 KB | Dev Channel |
| Nikkei (JavaScript) | 300 KB+ | 60 KB | web.dev |
| Tokopedia (app JavaScript) | 320 KB | 37 KB | web.dev |
| Tinder (main bundle) | 166 KB | 101 KB | Addy Osmani |
| Uber (core app) | n/a | 50 KB | Uber Engineering |
None of these reductions required a service worker. They made the first visit fast, and the service worker made repeat visits fast. See Loading Performance.
Service workers were rolled out incrementally and conditionally¶
- Twitter: offline page → static resources → app shell.
- Pinterest: runtime caching of lazy chunks → precache vendor and entry → precache top routes → per-locale workers.
- Google Search: registration only on capable devices, navigation preload mandatory, a server-generated worker that could be replaced with a no-op, and eventually retirement.
- Tokopedia: a lite first-visit page, then background precaching of the full app.
A staged rollout lets you measure each step and limits the damage of a caching bug. Migrating an Existing Site turns this into a plan, and Updating Service Workers covers the version management that Pinterest's appVersion scheme implemented by hand.
MPAs and SPAs both work¶
Nikkei and Ele.me (MPAs) reported gains comparable to Pinterest and Twitter (SPAs). The architecture should follow your content and team structure; SPA vs MPA PWAs compares them.
The PWA often complements the native app¶
Ola kept both. OYO wrapped its PWA for Google Play. X's manifest still prefers the native app on Android. Pinterest lists its Android apps in related_applications. For most of these companies the PWA was about reaching users the app couldn't: first-time visitors from search and links, users on low-storage devices, and users who had uninstalled the app. When to Build a PWA discusses when that's the right framing.
Installation is promoted in context and measured by launches¶
Clipchamp promoted installation in the toolbar and menu. Squoosh, Pinterest, X and Spotify all put markers in start_url (utm_source=launcher, homescreen_icon, homescreen, pwa_install), which is how you measure installed usage in every browser. Analytics for PWAs shows the full setup.
Measurement quality varies; yours shouldn't¶
Only Rakuten 24 (A/B test) and the Google I/O web app (cohort comparison) describe controlled measurements. If you run your own PWA project, decide the success metrics and the comparison before you ship:
- Instrument cohorts (service worker status, display mode, launch source) from day one.
- Use field data (Core Web Vitals), not only Lighthouse.
- Hold back a control group where you can, for example by registering the service worker for a random 90% of sessions.
- Report distributions and percentiles, not just averages.
Further reading¶
On this site
- When to Build a PWA
- Migrating an Existing Site
- Analytics for PWAs
- App Shell Model
- Trusted Web Activity
- Origin Private File System
- Desktop Platforms
- Production Checklist
External references
- web.dev case studies
- web.dev: Bringing service workers to Google Search
- web.dev: Measuring the real-world performance impact of service workers
- web.dev: Photoshop's journey to the web
- Pinterest Engineering: A one year PWA retrospective
- Uber Engineering: m.uber: Building a Superfast Web App
- Spotify Engineering: Building the Future of Our Desktop Apps
- Microsoft Learn: Teams Progressive Web Apps (PWAs)
- Web Performance Calendar: A Tinder Progressive Web App Performance Case Study
- GitHub: GoogleChromeLabs/squoosh