Installing Web Games Without a Store
The Add to Home Screen feature has been available on both Android and iOS for years, but many web game developers do not take advantage of it because the setup seems complicated. It is not. The entire process involves creating two files (a manifest and a service worker), adding a few icons, and writing a small amount of JavaScript to handle the install flow. The result is a game that looks and feels like a native app to the player, without the overhead of app store submission.
Create a Web App Manifest
The Web App Manifest is a JSON file that tells the browser about your game and how it should behave when installed. Create a file called manifest.json in your game's root directory. At minimum, it needs a name, start URL, display mode, and at least one icon.
The name field is the full name shown during installation. The short_name is what appears under the icon on the home screen, limited to about 12 characters. Set display to "standalone" to run without the browser address bar and navigation buttons, which gives your game the full screen. The "fullscreen" display mode hides the status bar as well, but is not supported on all platforms. Standalone is the reliable choice.
Set orientation to "landscape" or "portrait" if your game requires a specific orientation. This locks the orientation when the game is launched from the home screen, even on iOS where the Screen Orientation API does not work in the browser. The start_url should point to your game's entry page, typically "/" or "/index.html". Include a scope field that defines which URLs are considered part of your app, usually "/" for the entire domain.
The theme_color sets the color of the status bar on Android and the window title area on desktop. The background_color is shown on the splash screen while the game loads. Choose colors that match your game's visual identity so the launch experience feels intentional. Link the manifest in your HTML head with <link rel="manifest" href="/manifest.json">.
Register a Service Worker
A service worker is a JavaScript file that runs in the background and can intercept network requests, cache assets, and enable offline functionality. Browsers require a registered service worker before they consider a site installable as a PWA. Even if you do not need offline support, a minimal service worker that caches your core assets is worth implementing.
Create a file called sw.js in your game's root directory. In the install event handler, open a cache and add your essential game files: the HTML page, CSS, JavaScript bundles, sprite sheets, and audio files. In the fetch event handler, check the cache first and fall back to the network. This cache-first strategy means the game loads instantly after the first visit, even on slow connections.
Register the service worker from your main JavaScript file with navigator.serviceWorker.register('/sw.js'). Wrap it in a feature check since some older browsers do not support service workers. The registration is asynchronous and happens in the background without blocking your game's startup.
Versioning your cache is important. When you update game assets, change the cache name (for example, from 'game-v1' to 'game-v2'). In the activate event, delete old caches so players get the updated files. Without this, players running the installed version might be stuck on cached old code indefinitely.
Provide App Icons
The manifest icons array lists the icon files your game provides. Browsers use the closest matching size for different contexts: home screen icon, splash screen, app switcher, and installation dialog. At minimum, provide icons at 192x192 and 512x512 pixels. For the best experience across devices, also include 48x48, 72x72, 96x96, 144x144, and 384x384.
All icons should be PNG format with a transparent or solid background. Set the purpose field to "any" for standard icons. If you want the icon to work with Android's adaptive icon system (where the OS applies its own mask shape), provide a separate icon with purpose set to "maskable". A maskable icon should have the important content within the inner 80 percent of the image, since the outer edges may be cropped into a circle, rounded square, or other shape.
For iOS, the manifest icons are not always used. Safari on iOS reads the <link rel="apple-touch-icon"> tag from your HTML head instead. Add this tag pointing to a 180x180 PNG: <link rel="apple-touch-icon" href="/icons/icon-180.png">. iOS automatically adds rounded corners, so do not round the corners yourself in the image file.
Handle the Install Prompt on Android
Chrome on Android fires a beforeinstallprompt event when it determines that your site meets the installability criteria (HTTPS, valid manifest, registered service worker, user engagement). The default behavior is to show a mini-infobar at the bottom of the screen, but you can intercept this event to show a custom install button at a more appropriate time.
Listen for the beforeinstallprompt event on the window object. Call event.preventDefault() to suppress the default mini-infobar, and store the event object. When the player reaches a natural pause point, such as a game over screen, a level completion screen, or after several play sessions, show your own install button. When the player taps it, call event.prompt() on the stored event to show the browser's install dialog.
Track whether the user accepted or dismissed the prompt by awaiting event.userChoice, which resolves to an object with an outcome property of either "accepted" or "dismissed". If dismissed, do not show the prompt again immediately. Wait for the next session or a different natural pause point. Aggressive install prompts annoy users and can reduce engagement.
Once installed, the beforeinstallprompt event stops firing. You can detect whether your game is running as an installed PWA by checking window.matchMedia('(display-mode: standalone)').matches. Use this to hide install prompts and show any installed-app-specific features.
Guide iOS Users to Add to Home Screen
iOS Safari does not fire a beforeinstallprompt event and does not show automatic install prompts. The only way for an iOS user to add your game to their home screen is through the Share menu: tap the Share button in Safari, scroll down, and tap "Add to Home Screen." This is not discoverable, so you need to guide users through it.
Detect iOS Safari by checking the user agent for "iPhone" or "iPad" combined with "Safari" (excluding Chrome, Firefox, and other in-app browsers that cannot add to home screen). When you detect iOS Safari and the game is not already running in standalone mode, show a visual tooltip or overlay that illustrates the Share button and the "Add to Home Screen" option with a brief text explanation.
Show this guide at a natural pause point, not on first load. After the player has completed a level or played for a few minutes, they are more likely to want the game on their home screen. A dismissible banner at the bottom of the screen works well. Include an illustration of the iOS Share icon (the square with an upward arrow) so the user knows what to look for. Store a flag in localStorage when the user dismisses the guide so it does not reappear every session.
Once added to the home screen on iOS, the game opens in standalone mode with no browser UI, respects the manifest's orientation and theme color settings, and behaves much like a native app. Note that each home screen shortcut on iOS gets its own separate storage partition, so localStorage data from the Safari version does not carry over to the installed version. Consider using a server-side account system if save data continuity between browser and installed modes is important.
Optimize the Standalone Experience
When your game runs as an installed PWA, you have the full screen without browser UI. Take advantage of this by adjusting your layout. The status bar is still visible in standalone mode (though not in fullscreen mode), so account for its height using env(safe-area-inset-top). On iPhones with a notch or Dynamic Island, the status bar area is taller, and your game UI should not place interactive elements there.
Consider adding a minimal navigation header within your game for the installed version, since the browser's back button is gone. A settings icon, a home button to return to the main menu, and any account or save management features should be accessible from within the game UI itself. Users of the installed version expect app-like navigation patterns.
If your game supports multiple pages (for example, separate URLs for the main menu, game screen, and leaderboard), set the manifest scope to include all of them. Navigation within scope stays inside the standalone window. Links outside the scope open in the system browser, which is the correct behavior for external links but surprising if you accidentally link to a page outside your scope.
Push notifications are available in installed PWAs on Android and, as of iOS 16.4, on iOS for home screen web apps. If your game has time-based mechanics (daily rewards, multiplayer match invitations, limited events), push notifications can bring players back. Register for push notifications only after the user explicitly opts in, never on first launch, and provide clear value for enabling them.
Making a web game installable requires a manifest file, a service worker, and properly sized icons. Android handles the install flow automatically through the beforeinstallprompt event, while iOS needs a manual guide pointing users to the Share menu. Once installed, the game runs in standalone mode with full-screen access and native-like behavior.