DEV Community

Cover image for If You Want User-Specific PWA Home Screen Entries, start_url: "." Is the Best Approach
ojach
ojach

Posted on • Originally published at tips.ojapp.app

If You Want User-Specific PWA Home Screen Entries, start_url: "." Is the Best Approach

Many developers want to add user-specific profile pages or product pages to the home screen as a PWA.

When implementing this, one of the first ideas that comes to mind is a manifest.json like this:

{
  "start_url": "/user/123"
}
Enter fullscreen mode Exit fullscreen mode

I initially planned to implement it this way as well.

However, after spending quite a bit of time experimenting with PWAs, I found that this approach has drawbacks—not only from a privacy perspective, but also in terms of overall design.

Eventually, I settled on a much simpler configuration:

{
  "start_url": "."
}
Enter fullscreen mode Exit fullscreen mode

In this article, I'll explain why I chose start_url: "." and what I learned through real-world testing.


Why You Shouldn't Put User IDs in start_url

MDN recommends not including user-identifiable information in start_url.

For example:

{
  "start_url": "/user/123"
}
Enter fullscreen mode Exit fullscreen mode

or

{
  "start_url": "/product/987"
}
Enter fullscreen mode Exit fullscreen mode

The reason is that even after browser data is cleared, information associated with an installed Web App may still be used to identify a user.

In other words, it's safer to avoid embedding information such as:

  • User IDs
  • Session IDs
  • Tokens

inside start_url.


A Fixed URL Isn't Great for UX Either

So what about using a fixed URL like this?

{
  "start_url": "/"
}
Enter fullscreen mode Exit fullscreen mode

While it avoids the privacy concern, it introduces another problem: user experience.

Imagine adding one of these pages to the home screen:

  • A blog article
  • A product page
  • A documentation page
  • A user profile

Even though the user added a specific page, launching the app always takes them back to the homepage.

The user expected to save that page, but instead the entire website becomes the entry point.


Trying start_url: "."

The solution I ended up testing was simply:

{
  "start_url": "."
}
Enter fullscreen mode Exit fullscreen mode

The "." is treated as a path relative to the current page.

For example, if the current URL is:

/user/alice
Enter fullscreen mode Exit fullscreen mode

adding it to the home screen will launch:

/user/alice
Enter fullscreen mode Exit fullscreen mode

Likewise, if you're viewing:

/docs/install
Enter fullscreen mode Exit fullscreen mode

the installed app opens:

/docs/install
Enter fullscreen mode Exit fullscreen mode

No special routing logic is required.


It Works Extremely Well with Dynamic Manifests

This approach is especially convenient when you're generating manifest.json dynamically.

For example:

{
  "name": "Example",
  "display": "standalone",
  "start_url": "."
}
Enter fullscreen mode Exit fullscreen mode

That's all you need.

There's no need to inject user IDs into the manifest.

Instead, the currently displayed:

  • profile page
  • product page
  • article

automatically becomes the app's entry point.

It also makes future URL structure changes much easier to handle.


The Behavior Felt Much More Natural

I tested several different scenarios.

Added From Launches To
Blog article Same article
Product page Same product
User profile Same profile
Documentation Same document

The installed app always opened the page that had originally been added.

Personally, this feels much closer to how a PWA should behave.


But That's Not the Whole Story on Android

There is one important caveat.

While start_url: "." solves the launch URL problem, Android introduces another challenge when you want to install multiple pages.

For example, suppose users install:

  • User A
  • User B

If your manifest looks like this:

{
    "scope": "/",
    "id": "/"
}
Enter fullscreen mode Exit fullscreen mode

Chrome may decide they're actually the same Web App.

As a result, I observed behavior such as:

  • The second installation is treated as already installed.
  • A second icon cannot be added.
  • Different pages are merged into the same app.

Simply changing start_url does not solve this problem.


You Need to Design the Entire Manifest

One thing became very clear during my experiments:

Thinking only about start_url isn't enough.

You also need to consider:

  • start_url
  • id
  • scope
  • icons

and how each operating system interprets them.

On Android in particular, both id and scope affect app identity, so they're critical when building dynamic PWAs.


Conclusion

You don't need to include user IDs inside start_url.

Simply using:

{
    "start_url": "."
}
Enter fullscreen mode Exit fullscreen mode

lets the currently displayed page become the app's entry point.

Advantages include:

  • Follows MDN's privacy recommendations.
  • Provides a much more natural user experience.
  • Works well with dynamically generated manifests.
  • Remains flexible even if your URL structure changes.

However, on Android you'll also need to carefully design id and scope. In my case, the solution was to serve different manifest.json files for Android and iOS.

Using the following two manifests makes the behavior much more consistent across platforms.

Android

{
  "name": "OJapp | PWA LAB",
  "start_url": ".",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#2dd7ff"
}
Enter fullscreen mode Exit fullscreen mode

iOS

{
  "name": "OJapp | PWA LAB",
  "start_url": ".",
  "scope": "/lab",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#2dd7ff"
}
Enter fullscreen mode Exit fullscreen mode

Actual Manifest Generation Used in Petal

const isIOS = /iPhone|iPad|iPod/i.test(ua);

const manifest = {
  name: `${shortName} | Petal`,
  short_name: shortName,
  display: "standalone",
  start_url: ".",

  ...(isIOS ? { scope: "/" } : {}),

  background_color: "#ffffff",
  theme_color: "#2dd7ff",

  icons: [
    {
      src: app.icon_url,
      sizes: "192x192",
      type: "image/png"
    },
    {
      src: app.icon_url,
      sizes: "512x512",
      type: "image/png"
    }
  ]
};
Enter fullscreen mode Exit fullscreen mode

Petal is a project that I develop and maintain.

By setting app.icon_url as the app icon and using the user's name as short_name, each person's business card becomes its own home screen icon. Launching that icon opens the corresponding profile page.

Add to home screen

I also wrote another article explaining why Android and iOS require different scope settings, and how to work around those differences:

https://zenn.dev/ojapp_tips/articles/1e477228185158

This article is also an English rewrite of my original Tips blog post:

"PWAs Can Do This: How to Add User-Specific Pages to the Home Screen"

https://tips.ojapp.app/pwa-start-url-dot-best-practice-2/

Top comments (0)