PWA Development Services: Offline-Ready Web Apps

PWA development turns a website into a progressive web app: an application that loads instantly, keeps working on a bad connection, can be installed on the home screen and sends push notifications – all from one web codebase, without an app store standing between you and your users. For many businesses it is the shortest path to an “app” that customers actually use, at a fraction of the cost of building and maintaining separate iOS and Android apps.

At CodeWiz we build progressive web apps from scratch and retrofit PWA capabilities into existing websites, online stores and internal tools. We design the caching strategy, write and test the service worker, wire up web push on the backend, polish the installed experience and make sure everything behaves correctly on Android, iOS and desktop browsers – including the parts where those platforms still differ.

This service is for e-commerce shops whose mobile visitors abandon slow pages, field teams and warehouses that work with patchy connectivity, publishers and SaaS products that want re-engagement without an app store listing, and companies that need an internal app on every employee’s phone without device management headaches.

PWA: Hand holding a smartphone with a media player app open on screen

Offline Functionality with Service Workers and Smart Caching

The heart of every PWA is the service worker – a script the browser runs in the background, between your app and the network. It intercepts requests and decides, request by request, whether to answer from a local cache, from the network or from both. Done well, repeat visits load in milliseconds and the app stays usable on a train or in a warehouse with one bar of signal. Done badly, users get stuck on stale versions of your site.

Choosing a caching strategy per type of content

StrategyHow it worksBest forTrade-off
PrecacheFiles are downloaded when the service worker installsApp shell: core HTML, CSS, JavaScript, fonts, offline pageEvery change needs a new build manifest and update flow
Cache firstServe from cache, fall back to the networkVersioned assets, images, iconsNeeds expiration rules or the cache grows without limit
Network firstTry the network, fall back to cache after a timeoutHTML pages, account data, pricesSlower than cache on flaky networks
Stale-while-revalidateServe the cached copy instantly, refresh it in the backgroundCatalogue data, blog lists, settingsUsers may see slightly outdated data for one visit
Network only + background syncSend to the server; queue and retry if offlineForm submissions, orders, field reportsRequires idempotent endpoints on the backend

What a production service worker looks like

We usually build service workers with Workbox, either through vite-plugin-pwa, the Angular service worker or a custom build step. A condensed example of the routing we use:

import { precacheAndRoute } from 'workbox-precaching'; import { registerRoute } from 'workbox-routing'; import { NetworkFirst, CacheFirst, NetworkOnly } from 'workbox-strategies'; import { ExpirationPlugin } from 'workbox-expiration'; import { BackgroundSyncPlugin } from 'workbox-background-sync'; precacheAndRoute(self.__WB_MANIFEST); registerRoute(({ request }) => request.mode === 'navigate', new NetworkFirst({ cacheName: 'pages', networkTimeoutSeconds: 3 })); registerRoute(({ request }) => request.destination === 'image', new CacheFirst({ cacheName: 'images', plugins: [ new ExpirationPlugin({ maxEntries: 200, maxAgeSeconds: 30 * 86400 })] })); registerRoute(({ url }) => url.pathname === '/api/orders', new NetworkOnly({ plugins: [new BackgroundSyncPlugin('orders')] }), 'POST');

Offline data, not just offline pages

For apps that must create data offline – inspection checklists, delivery confirmations, draft orders – we store records in IndexedDB (through a small wrapper such as Dexie), mark them as pending and sync them when the connection returns. Background Sync handles this in Chromium browsers; on Safari and Firefox we sync on the next launch or online event. Client-generated IDs ensure a retried request never creates a duplicate. It is the same principle we described in our article on zero data loss e-commerce: every customer action is captured and recoverable.

Web Push Notifications That Users Actually Want

Push notifications bring users back without email or an app store. A PWA subscribes through the Push API, your server signs messages with VAPID keys, and the browser vendor’s push service delivers them even when the app is closed. Web push works on Android, on desktop Chrome, Edge, Firefox and Safari, and on iPhone and iPad from iOS 16.4 – but on iOS only after the user has added the app to the home screen.

Permission strategy matters more than the code

The fastest way to lose the push channel is to ask for permission on the first page load. Browsers increasingly hide or auto-block such prompts, and a “Block” decision is very hard to reverse. We ask in context instead: after a user places an order (“Notify me when it ships”), saves a search or subscribes to a topic. A soft prompt in your own UI explains the value first, and only a “Yes” triggers the browser dialog.

Backend and delivery

import webpush from 'web-push'; webpush.setVapidDetails('mailto:hello@example.com', process.env.VAPID_PUBLIC_KEY, process.env.VAPID_PRIVATE_KEY); await webpush.sendNotification(subscription, JSON.stringify({ title: 'Your order has shipped', url: '/account/orders/1042' }), { TTL: 3600, urgency: 'high' });
  • Subscriptions are stored per user and device in your database; responses with status 404 or 410 remove expired ones automatically.
  • Laravel projects use the laravel-notification-channels/webpush package, Node.js projects the web-push library; Firebase Cloud Messaging is an option when you also have native apps.
  • Sending goes through a queue, so a campaign to many subscribers never blocks your web requests.
  • Payloads carry a deep link, a tag to replace outdated notifications, and the service worker opens or focuses the right screen on click.
Person checking a smartphone at a cafe table next to cups of coffee

App-Like Experience: Installability, Manifest and Native Feel

An app-like experience is what separates a PWA from a website with a service worker. Users should be able to install it, launch it from the home screen without browser chrome, and feel no difference from a native app in day-to-day use.

The web app manifest

{ "name": "Example Store", "short_name": "Store", "id": "/", "start_url": "/?source=pwa", "display": "standalone", "theme_color": "#0f172a", "background_color": "#ffffff", "icons": [ { "src": "/icons/192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/icons/512.png", "sizes": "512x512", "type": "image/png" }, { "src": "/icons/maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" } ], "shortcuts": [{ "name": "My orders", "url": "/account/orders" }] }

Details that make it feel native

  • An app shell that renders immediately from cache, with skeleton screens instead of blank pages while data loads.
  • A custom install button driven by the beforeinstallprompt event on Chromium, and a short visual guide for “Add to Home Screen” on iOS, where no install prompt exists.
  • Maskable icons, a matching theme colour, safe-area handling for notched screens and a proper splash screen.
  • Smooth navigation with the View Transitions API, touch targets of at least 44–48 px and no hover-only interactions.
  • App shortcuts, the Badging API for unread counts and the Web Share API where they add real value.
  • A clear update flow: when a new version is deployed, users see “New version available – refresh” instead of silently running old code.

Cross-Platform Compatibility: Android, iOS and Desktop

One codebase is the main economic argument for a PWA, but “works everywhere” needs testing, because platforms support different parts of the PWA stack. We build with progressive enhancement: the core experience works in every modern browser, and extra capabilities switch on where they are available.

CapabilityAndroid (Chrome, Edge, Samsung Internet)iOS and iPadOS (Safari)Desktop Chrome and EdgeDesktop Firefox
Offline via service workerYesYesYesYes
Install to home screen or desktopYes, with install promptManually via Share menuYes, with install promptLimited
Web pushYesiOS 16.4+, installed apps onlyYesYes
Background SyncYesNoYesNo
Store distributionGoogle Play via Trusted Web ActivityApp Store only with a native wrapperMicrosoft Store via PWABuilder–

We test on real Android and iOS devices, not only emulators, and keep an eye on storage limits: Safari can evict data of sites that are not used for a while, so anything important is always synced to the server. If you need a Google Play listing, we package the PWA as a Trusted Web Activity with Bubblewrap and Digital Asset Links; for the Apple App Store, a thin Capacitor wrapper with genuine native features is usually required to pass review.

PWA vs Native App vs Responsive Website

A PWA is not always the right answer, and we will say so. The table below is the starting point we use with clients:

CriterionResponsive websiteProgressive web appNative or cross-platform app
Codebases to maintainOneOneOne to three, plus the web
Discoverable in search enginesYesYesOnly the store listing
Offline use and installNoYesYes
UpdatesInstantInstant, no store reviewThrough store review
Deep hardware access (Bluetooth on iOS, NFC, background location)NoPartial, mostly on AndroidFull
Typical budgetLowestModerateHighest

If your users need heavy background processing or deep integration with iOS hardware, a native or cross-platform app is the better tool. For catalogues, booking, ordering, dashboards and most internal tools, a PWA covers the requirements at a much lower total cost.

Performance, Security and SEO for Progressive Web Apps

A PWA must be served over HTTPS, and it only feels like an app if it is fast. We treat performance as a requirement from the first sprint: server-side rendering or static generation for the first view, code split by route, optimized images and a strict performance budget checked in CI. The techniques overlap with how we approach 100/100 page vitals, and an edge layer such as a well-configured Cloudflare setup keeps the first load fast for visitors far from your server.

  • SEO: content is rendered on the server or at build time, so search engines index real HTML instead of an empty JavaScript shell. Each screen keeps its own URL.
  • Security: a strict Content-Security-Policy, the service worker scope limited to what it needs, and authenticated API responses never cached in shared caches.
  • Auditing: Lighthouse dropped its dedicated PWA category in version 12, so we verify installability and the service worker in Chrome DevTools, and test offline behaviour with network throttling and airplane mode on real devices.

Turning an Existing Website or Store into a PWA

You rarely need a rewrite. Most frameworks have mature PWA tooling, and we add PWA capabilities incrementally:

  • Vue, React, Svelte and Vite projects: vite-plugin-pwa with a custom Workbox service worker.
  • Next.js and Nuxt: Serwist or the Nuxt PWA module, with careful handling of server-rendered routes.
  • Angular: the built-in @angular/service-worker and its data group configuration.
  • Laravel and plain PHP: a manifest, a hand-written or Workbox-built service worker and web push through Laravel notifications.
  • WordPress and WooCommerce: a lightweight service worker that caches assets and an offline page, while cart, checkout and account pages always go to the network.

Common PWA Mistakes We Fix

  • Caching HTML with cache first, so users stay on an old version for days after a deployment.
  • Calling skipWaiting() unconditionally, which swaps code under an open tab and breaks lazily loaded chunks.
  • Caching personalised API responses, so one user can see another user’s data on a shared device.
  • Asking for notification permission on the first visit, and losing the channel for good.
  • No expiration rules, so caches of images and opaque cross-origin responses fill the storage quota.
  • Testing only in Chrome on desktop and discovering on launch day that iOS behaves differently.

What Drives the Cost of PWA Development

We estimate after a short discovery rather than quoting blindly. The biggest cost drivers are:

  • Whether we build a new application or add PWA features to an existing site.
  • The depth of offline support: cached reading is simple, offline data entry with conflict resolution is not.
  • Push notification logic, segmentation and the admin interface for sending campaigns.
  • The number of platforms and devices to test, and whether store packaging is required.
  • Integrations with your backend, ERP, CRM or payment provider.
Top view of a desk with a smartphone in hand, a laptop and notebooks

How We Work

  1. Discovery: we map your users, devices and connectivity, and agree which screens must work offline and which events deserve a notification.
  2. Plan: we define the caching strategy per route, the data sync model, the push architecture and the browser support matrix.
  3. Build: we develop the app shell, service worker, manifest, offline storage and push backend, with a performance budget enforced in CI.
  4. Test: we test on real Android and iOS devices and desktop browsers, offline and on throttled networks, including update and rollback scenarios.
  5. Launch: we deploy behind HTTPS and a CDN, roll out the service worker carefully and monitor errors and install rates.
  6. Support: we keep dependencies and browser compatibility up to date and evolve the app with you.

Why CodeWiz

  • Full-stack ownership: we build the frontend, service worker, APIs, push backend and servers, so offline sync and notifications work end to end.
  • Performance specialists: fast loading is our everyday work, from code to Varnish and Cloudflare.
  • Honest recommendations: if a responsive website is enough, or you truly need a native app, we will tell you.
  • Open-source first: Workbox, Vite, Dexie and open web standards keep you free of vendor lock-in.
  • Fair pricing: premium development without premium prices, from Banja Luka, working remotely with clients locally and internationally – read more about CodeWiz.

Frequently Asked Questions

How much does PWA development cost?

It depends on whether we start from scratch or extend an existing site, how much has to work offline and how complex the notification logic is. Adding installability and offline caching to an existing website is a modest project; a full offline-first application with data sync is considerably larger. You get a clear estimate after discovery.

Do progressive web apps work on iPhone?

Yes. Offline support, installation via “Add to Home Screen” and, from iOS 16.4, web push for installed apps all work on iPhone and iPad. Some APIs, such as Background Sync, are not available in Safari, so we design fallbacks for them.

Can a PWA be published on Google Play or the App Store?

Google Play accepts PWAs packaged as a Trusted Web Activity, and the Microsoft Store accepts them too. The Apple App Store requires a native wrapper and features that go beyond a website, so we evaluate that case individually.

Will a PWA hurt my SEO?

Not when it is built correctly. With server-side rendering or static generation, every page is indexable and fast, which helps rankings. Problems only appear with client-only rendering that shows search engines an empty page.

How long does it take to build a PWA?

Adding PWA features to an existing website usually takes a few weeks including testing. A new application with offline data entry and push notifications typically takes a few months, depending on scope and integrations.

Ready to Build Your Progressive Web App?

Tell us who your users are and where your current website or app falls short, and we will propose a PWA plan that fits your goals and budget. Contact us to discuss your project, or see the full scope of our PWA development services.