Create a PWA app manifest dynamically
Tags: pwa, javascript, beginners, web
Published: 2021-12-28 06:51:07

Every Progressive Web App has an [app manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest), a simple JSON file that contains the basic information of your app, i.e. name, icon, description, etc.

If you just want to add PWA functionality to your existing web app, [Progressier](https://progressier.com) has everything you need (including [dynamic app icons options](https://progressier.com/features/programmatic-pwa-creation)). But if you want to create your own web app manifest dynamically, please read on.

## How it's traditionally done

When building your first PWA, the simplest way to proceed is adding a link to your app manifest directly in the `<head>` section of your HTML template.

`<link rel="manifest" href="/manifest.json">`

Host `manifest.json` anywhere on your site. The resulting JSON file should look like this:

```
{
   "short_name":"Coronavirus",
   "name":"The Coronavirus App",
   "background_color":"#ffffff",
   "theme_color":"#ffffff",
   "display":"standalone",
   "orientation":"any",
   "start_url":"https://coronavirus.app",
   "scope":"https://coronavirus.app",
   "icons":[
      {"src":"/icon512.png","sizes":"512x512","type":"image/png"},
      {"src":"/icon192.png","sizes":"192x192","type":"image/png"},
      {"src":"/icon196.png","sizes":"196x196","type":"image/png"}
   ]
}
```

## Why you might want to do it differently
While the method above is a perfectly valid way of dealing with web app manifests, there are legitimate cases when a static file won't do and you'll want to generate it dynamically instead:
- You need completely different icons on desktop and mobile
- You want to host multiple distinct PWAs on the same domain
- The PWA should look different for each logged-in user

And there are probably many more valid examples. To generate your app manifest dynamically, you have two options: build it on your server when it's requested by users. Or automatically generate it right in the browser (our preferred method).

## Server-side dynamic app manifest generation
Rather than hosting the file as a static file on you site, make the path to `/manifest.json` an API, which will allow you to generate the content of the JSON file programmatically based on whatever your needs are. Here is an example using Node/Express:

```
app.get('/manifest.json', async function(req, res){
    //for brevity, we're not including the isDesktop function here
    let iconUrl = isDesktop() ? '/desktop.png' : '/mobile.png';
    let manifest = { 
       name: "App name",
       icons: [{
         src: iconUrl, 
         sizes: "512x512", 
         type:"image/png"
       }]
    }
    res.header('content-type', 'application/json');
    return res.status(200).send(JSON.stringify(manifest));
});
```

## Client-side dynamic app manifest creation
Most people don't know that `/manifest.json` doesn't have to be an actual file. In fact, it works just fine with a [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs). 

I would even argue that a Data URL is a better way to go about this — even if you don't need to generate that particular asset dynamically. 

No additional file to download from your server means faster load times and reduced server costs. And since the Data URL will be different every time you modify the content of your web app manifest, you don't have to worry about the browser not updating its content accordingly.

In your client-side code, here is how you can create it:

```
//for brevity, we're not including the isDesktop function here
let iconUrl = isDesktop() ? '/desktop.png' : '/mobile.png';
let manifest = { 
  name: "App name",
  icons: [{
    src: iconUrl, 
    sizes: "512x512", 
    type:"image/png"
  }]
};
let content = encodeURIComponent(JSON.stringify(manifest));
let url = "data:application/manifest+json,"+content;
let element = document.createElement('link');
element.setAttribute('rel', 'manifest');
element.setAttribute('href', url);
document.querySelector('head').appendChild(element);
```

At [Progressier](https://progressier.com), we came across quite a few complex use cases of users needing completely different logos on their Android home screen, on their Android splash screen, on their iPhone splash screen and on their Windows/Mac installed PWA, so we've designed our dashboard accordingly. 

![Progressier dynamic app manifest toggles and inputs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bja80wx246627auuhf4e.JPG)

Behind the scenes, we use these user settings to generate their app manifest dynamically with the methods above.

Questions or feedback? Leave a comment below!