<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ojach</title>
    <description>The latest articles on DEV Community by ojach (@ojach).</description>
    <link>https://dev.to/ojach</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4011795%2F71304528-821e-4b81-a227-c847b167af7d.png</url>
      <title>DEV Community: ojach</title>
      <link>https://dev.to/ojach</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ojach"/>
    <language>en</language>
    <item>
      <title>If You Want User-Specific PWA Home Screen Entries, start_url: "." Is the Best Approach</title>
      <dc:creator>ojach</dc:creator>
      <pubDate>Sat, 11 Jul 2026 03:44:16 +0000</pubDate>
      <link>https://dev.to/ojach/if-you-want-user-specific-pwa-home-screen-entries-starturl-is-the-best-approach-48c5</link>
      <guid>https://dev.to/ojach/if-you-want-user-specific-pwa-home-screen-entries-starturl-is-the-best-approach-48c5</guid>
      <description>&lt;p&gt;Many developers want to add &lt;strong&gt;user-specific profile pages&lt;/strong&gt; or &lt;strong&gt;product pages&lt;/strong&gt; to the home screen as a PWA.&lt;/p&gt;

&lt;p&gt;When implementing this, one of the first ideas that comes to mind is a &lt;code&gt;manifest.json&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/user/123"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I initially planned to implement it this way as well.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Eventually, I settled on a much simpler configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this article, I'll explain why I chose &lt;code&gt;start_url: "."&lt;/code&gt; and what I learned through real-world testing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why You Shouldn't Put User IDs in &lt;code&gt;start_url&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;MDN recommends &lt;strong&gt;not&lt;/strong&gt; including user-identifiable information in &lt;code&gt;start_url&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/user/123"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/product/987"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;In other words, it's safer to avoid embedding information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User IDs&lt;/li&gt;
&lt;li&gt;Session IDs&lt;/li&gt;
&lt;li&gt;Tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;inside &lt;code&gt;start_url&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Fixed URL Isn't Great for UX Either
&lt;/h2&gt;

&lt;p&gt;So what about using a fixed URL like this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While it avoids the privacy concern, it introduces another problem: user experience.&lt;/p&gt;

&lt;p&gt;Imagine adding one of these pages to the home screen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A blog article&lt;/li&gt;
&lt;li&gt;A product page&lt;/li&gt;
&lt;li&gt;A documentation page&lt;/li&gt;
&lt;li&gt;A user profile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though the user added a specific page, launching the app always takes them back to the homepage.&lt;/p&gt;

&lt;p&gt;The user expected to save &lt;strong&gt;that page&lt;/strong&gt;, but instead the entire website becomes the entry point.&lt;/p&gt;




&lt;h2&gt;
  
  
  Trying &lt;code&gt;start_url: "."&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The solution I ended up testing was simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;"."&lt;/code&gt; is treated as a path relative to the current page.&lt;/p&gt;

&lt;p&gt;For example, if the current URL is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/user/alice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;adding it to the home screen will launch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/user/alice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Likewise, if you're viewing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/docs/install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the installed app opens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/docs/install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No special routing logic is required.&lt;/p&gt;




&lt;h2&gt;
  
  
  It Works Extremely Well with Dynamic Manifests
&lt;/h2&gt;

&lt;p&gt;This approach is especially convenient when you're generating &lt;code&gt;manifest.json&lt;/code&gt; dynamically.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"display"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"standalone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all you need.&lt;/p&gt;

&lt;p&gt;There's no need to inject user IDs into the manifest.&lt;/p&gt;

&lt;p&gt;Instead, the currently displayed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;profile page&lt;/li&gt;
&lt;li&gt;product page&lt;/li&gt;
&lt;li&gt;article&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;automatically becomes the app's entry point.&lt;/p&gt;

&lt;p&gt;It also makes future URL structure changes much easier to handle.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Behavior Felt Much More Natural
&lt;/h2&gt;

&lt;p&gt;I tested several different scenarios.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Added From&lt;/th&gt;
&lt;th&gt;Launches To&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Blog article&lt;/td&gt;
&lt;td&gt;Same article&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product page&lt;/td&gt;
&lt;td&gt;Same product&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User profile&lt;/td&gt;
&lt;td&gt;Same profile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documentation&lt;/td&gt;
&lt;td&gt;Same document&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The installed app always opened the page that had originally been added.&lt;/p&gt;

&lt;p&gt;Personally, this feels much closer to how a PWA should behave.&lt;/p&gt;




&lt;h2&gt;
  
  
  But That's Not the Whole Story on Android
&lt;/h2&gt;

&lt;p&gt;There is one important caveat.&lt;/p&gt;

&lt;p&gt;While &lt;code&gt;start_url: "."&lt;/code&gt; solves the launch URL problem, Android introduces another challenge when you want to install multiple pages.&lt;/p&gt;

&lt;p&gt;For example, suppose users install:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User A&lt;/li&gt;
&lt;li&gt;User B&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your manifest looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chrome may decide they're actually the &lt;strong&gt;same Web App&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As a result, I observed behavior such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The second installation is treated as already installed.&lt;/li&gt;
&lt;li&gt;A second icon cannot be added.&lt;/li&gt;
&lt;li&gt;Different pages are merged into the same app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simply changing &lt;code&gt;start_url&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; solve this problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  You Need to Design the Entire Manifest
&lt;/h2&gt;

&lt;p&gt;One thing became very clear during my experiments:&lt;/p&gt;

&lt;p&gt;Thinking only about &lt;code&gt;start_url&lt;/code&gt; isn't enough.&lt;/p&gt;

&lt;p&gt;You also need to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;start_url&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scope&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;icons&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and how each operating system interprets them.&lt;/p&gt;

&lt;p&gt;On Android in particular, both &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;scope&lt;/code&gt; affect app identity, so they're critical when building dynamic PWAs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You don't need to include user IDs inside &lt;code&gt;start_url&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Simply using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;lets the currently displayed page become the app's entry point.&lt;/p&gt;

&lt;p&gt;Advantages include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follows MDN's privacy recommendations.&lt;/li&gt;
&lt;li&gt;Provides a much more natural user experience.&lt;/li&gt;
&lt;li&gt;Works well with dynamically generated manifests.&lt;/li&gt;
&lt;li&gt;Remains flexible even if your URL structure changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, on Android you'll also need to carefully design &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;scope&lt;/code&gt;. In my case, the solution was to serve &lt;strong&gt;different &lt;code&gt;manifest.json&lt;/code&gt; files for Android and iOS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Using the following two manifests makes the behavior much more consistent across platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  Android
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OJapp | PWA LAB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"display"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"standalone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"background_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#ffffff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"theme_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#2dd7ff"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  iOS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OJapp | PWA LAB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/lab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"display"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"standalone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"background_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#ffffff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"theme_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#2dd7ff"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Actual Manifest Generation Used in Petal
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isIOS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/iPhone|iPad|iPod/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;manifest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;shortName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | Petal`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;short_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;shortName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;start_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="p"&gt;...(&lt;/span&gt;&lt;span class="nx"&gt;isIOS&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}),&lt;/span&gt;

  &lt;span class="na"&gt;background_color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ffffff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;theme_color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#2dd7ff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;icons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;icon_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sizes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;192x192&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;icon_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sizes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;512x512&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://ojapp.app/petal" rel="noopener noreferrer"&gt;Petal&lt;/a&gt; is a project that I develop and maintain.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fms4fc9lajtp1w61s91bd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fms4fc9lajtp1w61s91bd.jpg" alt="Add to home screen" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also wrote another article explaining &lt;strong&gt;why Android and iOS require different &lt;code&gt;scope&lt;/code&gt; settings&lt;/strong&gt;, and how to work around those differences:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://zenn.dev/ojapp_tips/articles/1e477228185158" rel="noopener noreferrer"&gt;https://zenn.dev/ojapp_tips/articles/1e477228185158&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article is also an English rewrite of my original Tips blog post:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"PWAs Can Do This: How to Add User-Specific Pages to the Home Screen"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tips.ojapp.app/pwa-start-url-dot-best-practice-2/" rel="noopener noreferrer"&gt;https://tips.ojapp.app/pwa-start-url-dot-best-practice-2/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>android</category>
      <category>ios</category>
      <category>manifest</category>
    </item>
    <item>
      <title>What I Learned by Using a Nonexistent URL: iPhone’s Hidden Home Screen Icon Behavior</title>
      <dc:creator>ojach</dc:creator>
      <pubDate>Sat, 04 Jul 2026 10:02:25 +0000</pubDate>
      <link>https://dev.to/ojach/what-i-learned-by-using-a-nonexistent-url-iphones-hidden-home-screen-icon-behavior-18fm</link>
      <guid>https://dev.to/ojach/what-i-learned-by-using-a-nonexistent-url-iphones-hidden-home-screen-icon-behavior-18fm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is a reprint from my tips blog. You can find the original article here: &lt;a href="https://tips.ojapp.app/iphone-home-icon-auto-generated-theme-color-2/" rel="noopener noreferrer"&gt;https://tips.ojapp.app/iphone-home-icon-auto-generated-theme-color/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hi, I'm Ojach.&lt;/p&gt;

&lt;p&gt;I built a feature in my test lab, "PWA LAB," that allows me to freely change the installation URL. The goal was simple: &lt;strong&gt;I wanted a place to try out, in real-time, how a PWA actually looks when added to the home screen.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Validating PWAs often comes down to these small, gritty experiments. Especially with &lt;code&gt;maskable&lt;/code&gt; icons, where the differences in how Android and iOS handle cropping can change everything.&lt;/p&gt;

&lt;p&gt;Reading the spec sheet 100 times can't compare to the moment you break your own code on a real device and finally "get it." Every developer has been there.&lt;/p&gt;

&lt;p&gt;That's exactly what happened this time.&lt;/p&gt;

&lt;p&gt;To be honest, it was just a simple URL typo. But that "oops" moment led me to discover some fascinating, undocumented behaviors regarding iPhone home screen icons. I just had to share this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validating the "Broken State"
&lt;/h2&gt;

&lt;p&gt;The setup was incredibly simple. I used my PWA LAB to intentionally set an "invalid, non-existent URL" as the installation target. Then, I hit "Add to Home Screen" on both Android (Chrome) and iPhone (Safari) to see what would happen.&lt;/p&gt;

&lt;p&gt;I was curious about a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can you even add a non-existent URL to the home screen?&lt;/li&gt;
&lt;li&gt;How does the OS handle it when the icon image returns a 404?&lt;/li&gt;
&lt;li&gt;How much of &lt;code&gt;manifest.json&lt;/code&gt; is ignored versus respected?&lt;/li&gt;
&lt;li&gt;What does this reveal about the underlying philosophy of each OS?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you intentionally break things, the OS's fallback mechanisms—usually hidden behind the scenes—are laid bare.&lt;/p&gt;

&lt;h2&gt;
  
  
  【Android】 Chrome: The Strict Disciplinarian
&lt;/h2&gt;

&lt;p&gt;As expected, Android (Chrome) completely shut me out. It wouldn't even let me press the "Install" button. It essentially said, "This isn't a valid app, so beat it."&lt;/p&gt;

&lt;p&gt;It's a perfectly sound and correct behavior. If it's going to be a PWA on the home screen, the launch URL &lt;em&gt;must&lt;/em&gt; work. Android Chrome's validation is rigorous.&lt;/p&gt;

&lt;p&gt;In Android's "mind," it’s a simple logic: &lt;strong&gt;"This URL won't launch as an app, so it doesn't deserve PWA status. Rejected."&lt;/strong&gt; It’s a very Google-like approach—treating the Web as a foundation to be elevated into "real" native-like experiences.&lt;/p&gt;

&lt;h2&gt;
  
  
  【iPhone】 Safari: The Over-the-Top Concierge
&lt;/h2&gt;

&lt;p&gt;Now, the iPhone (Safari). This is where things got really interesting.&lt;/p&gt;

&lt;p&gt;To my surprise, &lt;strong&gt;the iPhone let me "Add to Home Screen" without a hitch, even with an invalid URL.&lt;/strong&gt; It didn't have any of the cold refusal you see on Android.&lt;/p&gt;

&lt;p&gt;Of course, the icon image (PNG) returned a 404. But here’s the kicker: The iPhone immediately &lt;strong&gt;auto-generated a "placeholder icon" on the fly&lt;/strong&gt; and made it look like a real app.&lt;/p&gt;

&lt;p&gt;Observing this logic led to three surprising discoveries:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;theme_color&lt;/code&gt; was actually alive
&lt;/h3&gt;

&lt;p&gt;Frontend developers know the pain: &lt;code&gt;theme_color&lt;/code&gt; in &lt;code&gt;manifest.json&lt;/code&gt; often feels like a "dead" property on iOS. On Android, it smoothly paints the toolbar and headers, which is satisfying. But on iOS, it’s rarely felt.&lt;/p&gt;

&lt;p&gt;However, since my icon image was missing, I saw the "backdoor" Apple prepared. &lt;strong&gt;The background color of the auto-generated icon was dyed in the color I specified in &lt;code&gt;theme_color&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Red &lt;code&gt;theme_color&lt;/code&gt; -&amp;gt; Reddish background.&lt;/li&gt;
&lt;li&gt;Blue &lt;code&gt;theme_color&lt;/code&gt; -&amp;gt; Bluish background.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because we usually set 100% custom icons, we never notice this. When the icon is lost, iPhone digs up the &lt;code&gt;theme_color&lt;/code&gt; and uses it as a "seat cushion" for the background. I was honestly impressed: "So that's where you were working!"&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Apple-style "Initial Character" Fallback
&lt;/h3&gt;

&lt;p&gt;Next is how it handles text. When there's no icon, the iPhone &lt;strong&gt;automatically extracts the first character of the site title and centers it in the icon.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the title is "Ojach's Blog," it displays a beautifully rendered character in the center, like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;お&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It actually looks quite stylish—like a minimalist app logo. It shows Apple’s pride (or obsession) to not let the home screen be cluttered with ugly "NO IMAGE" icons.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The "Emoji-as-an-App-Icon" Hack
&lt;/h3&gt;

&lt;p&gt;Experimenting further, I found something even better. If you put an emoji at the beginning of your site title, the iPhone will use &lt;em&gt;that&lt;/em&gt; as the app icon.&lt;/p&gt;

&lt;p&gt;If you name your site:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;😀 PWA LAB&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The home screen icon becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;😀&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It works flawlessly with transparency and looks great. I spent way too much time trying to figure out which emoji made the best app icon. You get these unexpected gems when you mess around with real devices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Futxua0vwu2wck1ei2lom.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Futxua0vwu2wck1ei2lom.jpg" alt="Add to Home Screen on iPhone" width="300" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Philosophy Clash: Android Builds Apps, iPhone Places Objects
&lt;/h2&gt;

&lt;p&gt;Looking at these differences, the contrast in philosophy is striking:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OS&lt;/th&gt;
&lt;th&gt;Handling Invalid URLs&lt;/th&gt;
&lt;th&gt;Icon Missing&lt;/th&gt;
&lt;th&gt;Core Philosophy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Android&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Blocks addition (Error)&lt;/td&gt;
&lt;td&gt;Cannot install&lt;/td&gt;
&lt;td&gt;"Elevate Web to a strict App."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;iPhone&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Forces it onto home screen&lt;/td&gt;
&lt;td&gt;Auto-generates nicely&lt;/td&gt;
&lt;td&gt;"Decorate Web pages as home screen pieces."&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Android is logical; if the structure is broken, it's not an app.&lt;br&gt;
iPhone is emotional; even if the link is dead, it prioritizes keeping the user's home screen beautiful and forced it into a usable object.&lt;/p&gt;

&lt;h2&gt;
  
  
  【Note】 Don't skip your icons just yet! (lol)
&lt;/h2&gt;

&lt;p&gt;While this was a fascinating discovery, please don't use this as an excuse to stop designing icons! In production, you absolutely should provide your own assets.&lt;/p&gt;

&lt;p&gt;Especially on iOS, &lt;code&gt;apple-touch-icon&lt;/code&gt; caching is aggressive, so you need to stick to the standard implementation. On Android, providing a 512x512 PNG with &lt;code&gt;any maskable&lt;/code&gt; support in &lt;code&gt;manifest.json&lt;/code&gt; is still the gold standard.&lt;/p&gt;

&lt;p&gt;This auto-generation is just an "insurance policy" from Apple to keep things looking good in case of an emergency. Don't rely on it as your primary strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary: There's a world you can only see by "breaking" things
&lt;/h2&gt;

&lt;p&gt;It's easy to stick to the textbook implementations. But by seeing how the OS desperately tries to "take care" of your broken code, you catch glimpses of the hidden polish and thoughtfulness put in by the engineers at Apple and Google.&lt;/p&gt;

&lt;p&gt;This experiment, born from a simple typo, taught me two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;iPhone will go to great lengths to ensure your home screen looks clean, even without an icon.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;theme_color&lt;/code&gt;, which I thought was dead on iOS, is actually doing heavy lifting in the background.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;"PWA LAB" is incredibly fun precisely because it lets me run these "buggy experiments" without consequences.&lt;/p&gt;

&lt;p&gt;If you're tired of implementing by the book, try deleting your PWA icon settings and see what kind of "hospitality icon" your iPhone generates for you. You'll likely be pleasantly surprised.&lt;/p&gt;




&lt;p&gt;※ This article is a reprint from my tech blog: &lt;a href="https://tips.ojapp.app/iphone-home-icon-auto-generated-theme-color-2/" rel="noopener noreferrer"&gt;OJapp Tips｜What I Learned by Using a Nonexistent URL: iPhone’s Hidden Home Screen Icon Behavior&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>pwa</category>
      <category>ios</category>
      <category>android</category>
    </item>
    <item>
      <title>iOS and Android Have Different Goals for PWAs: The Real Difference Beyond Support or No Support</title>
      <dc:creator>ojach</dc:creator>
      <pubDate>Fri, 03 Jul 2026 15:52:00 +0000</pubDate>
      <link>https://dev.to/ojach/ios-and-android-have-different-goals-for-pwas-the-real-difference-beyond-support-or-no-support-2am0</link>
      <guid>https://dev.to/ojach/ios-and-android-have-different-goals-for-pwas-the-real-difference-beyond-support-or-no-support-2am0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is a reprint from my tips blog. You can find the original article here: [&lt;a href="https://tips.ojapp.app/en/ios-android-pwa-goal-difference-3/" rel="noopener noreferrer"&gt;https://tips.ojapp.app/en/ios-android-pwa-goal-difference-3/&lt;/a&gt;]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Android vs. iPhone: Different Goals for PWAs
&lt;/h1&gt;

&lt;p&gt;When people talk about PWAs, the explanation often sounds like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android supports PWAs.&lt;/li&gt;
&lt;li&gt;iPhone does not support PWAs very well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you only look at the PWA specifications, this explanation is easy to understand.&lt;/p&gt;

&lt;p&gt;Android Chrome supports manifest.json, Service Worker, installation, notifications, shortcuts, and many other PWA features quite strongly.&lt;/p&gt;

&lt;p&gt;iPhone Safari, on the other hand, does not behave the same way as Android.&lt;/p&gt;

&lt;p&gt;But after testing PWAs on both iPhone and Android many times, I started to see the difference in another way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More accurately, Android and iPhone have different goals for PWAs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is the biggest difference I noticed while testing repeatedly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android tries to turn web pages into apps
&lt;/h2&gt;

&lt;p&gt;Android PWAs are clearly designed in the direction of making web pages feel closer to native apps.&lt;/p&gt;

&lt;p&gt;The idea is to take a website opened in the browser and move it toward a native-app-like experience.&lt;/p&gt;

&lt;p&gt;This direction is very strong on Android.&lt;/p&gt;

&lt;p&gt;That is why many PWA-related features are well supported.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;manifest.json&lt;/li&gt;
&lt;li&gt;Service Worker&lt;/li&gt;
&lt;li&gt;Push notifications&lt;/li&gt;
&lt;li&gt;Install Prompt&lt;/li&gt;
&lt;li&gt;Shortcuts&lt;/li&gt;
&lt;li&gt;theme_color&lt;/li&gt;
&lt;li&gt;background_color&lt;/li&gt;
&lt;li&gt;maskable icons&lt;/li&gt;
&lt;li&gt;display modes&lt;/li&gt;
&lt;li&gt;orientation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, it is not perfect.&lt;/p&gt;

&lt;p&gt;Manifest cache can be stubborn, multiple PWAs on the same domain can become confusing, and real-device testing can still create plenty of traps.&lt;/p&gt;

&lt;p&gt;Even so, when you build according to the PWA specification, Android usually responds in a fairly straightforward way.&lt;/p&gt;

&lt;p&gt;For example, if you set &lt;code&gt;display: fullscreen&lt;/code&gt;, the app feels much more full-screen.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;theme_color&lt;/code&gt; is often reflected in the toolbar color.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;orientation&lt;/code&gt; also works quite strongly on Android.&lt;/p&gt;

&lt;p&gt;In other words, for Android, a PWA is &lt;strong&gt;an app made from the Web&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  iPhone starts from the experience of placing web pages on the home screen
&lt;/h2&gt;

&lt;p&gt;iPhone is different.&lt;/p&gt;

&lt;p&gt;Even before the word PWA became common, iOS already had a culture of adding web pages to the home screen.&lt;/p&gt;

&lt;p&gt;This is close to the WebClip idea.&lt;/p&gt;

&lt;p&gt;You open a page in Safari and place it on the home screen as an icon.&lt;/p&gt;

&lt;p&gt;Next time, you tap that icon and open the page directly.&lt;/p&gt;

&lt;p&gt;This is not exactly “turning the Web into an app.”&lt;/p&gt;

&lt;p&gt;It is more like &lt;strong&gt;making a frequently used web page part of the home screen&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is why iPhone PWAs appear to have a different goal from Android PWAs.&lt;/p&gt;

&lt;p&gt;Android tries to move the Web closer to native apps.&lt;/p&gt;

&lt;p&gt;iPhone tries to let web pages live naturally on the home screen.&lt;/p&gt;

&lt;p&gt;Once you understand this difference, iOS PWA behavior starts to look a little different.&lt;/p&gt;

&lt;h2&gt;
  
  
  iPhone is not ignoring PWAs
&lt;/h2&gt;

&lt;p&gt;People often say that iPhone does not support PWAs properly.&lt;/p&gt;

&lt;p&gt;But in reality, it is not true that nothing works.&lt;/p&gt;

&lt;p&gt;On iPhone, Add to Home Screen, app-like standalone display, &lt;code&gt;short_name&lt;/code&gt;, &lt;code&gt;start_url&lt;/code&gt;, &lt;code&gt;scope&lt;/code&gt;, and icon settings all matter.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;scope&lt;/code&gt; is especially important when you actually test it.&lt;/p&gt;

&lt;p&gt;While the user stays inside the scope, the app-like appearance is easier to maintain. When the user moves outside the scope, Safari may show a small browser UI.&lt;/p&gt;

&lt;p&gt;This would be unlikely if iOS were completely ignoring PWA behavior.&lt;/p&gt;

&lt;p&gt;However, these settings do not work in the same way as Android.&lt;/p&gt;

&lt;p&gt;Even if you set &lt;code&gt;display: fullscreen&lt;/code&gt; or &lt;code&gt;orientation&lt;/code&gt;, iPhone does not reflect them as directly as Android.&lt;/p&gt;

&lt;p&gt;Maskable icons are also not as important on iPhone as they are on Android.&lt;/p&gt;

&lt;p&gt;Instead, &lt;code&gt;apple-touch-icon&lt;/code&gt; has a very strong presence.&lt;/p&gt;

&lt;p&gt;This is where you can feel iPhone’s own home screen culture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why iPhone PWA behavior feels unique
&lt;/h2&gt;

&lt;p&gt;There are several points where PWA developers often get confused on iPhone.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;start_url&lt;/code&gt; does not always feel like it behaves as expected&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scope&lt;/code&gt; behaves differently from Android&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apple-touch-icon&lt;/code&gt; can feel stronger than manifest icons&lt;/li&gt;
&lt;li&gt;Some parts of manifest.json seem to have little effect&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;display&lt;/code&gt; and &lt;code&gt;orientation&lt;/code&gt;, which work on Android, barely change anything on iPhone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is easy to summarize all of this by saying, “iPhone does not support PWAs.”&lt;/p&gt;

&lt;p&gt;But I think the reality is a little more complicated.&lt;/p&gt;

&lt;p&gt;Apple seems to treat PWAs less like “apps made from the Web” and more like web pages placed on the home screen.&lt;/p&gt;

&lt;p&gt;In other words, Apple may care less about how much of the PWA specification is implemented, and more about what the user intended to place on the home screen.&lt;/p&gt;

&lt;p&gt;That is why &lt;code&gt;apple-touch-icon&lt;/code&gt; is strong on iPhone.&lt;/p&gt;

&lt;p&gt;The home screen icon has to look natural.&lt;/p&gt;

&lt;p&gt;That is also why moving outside the scope can show Safari’s mini UI.&lt;/p&gt;

&lt;p&gt;The user needs to understand that they have left the thing they placed on the home screen.&lt;/p&gt;

&lt;p&gt;When viewed this way, iOS behavior does not look like simple lack of support.&lt;/p&gt;

&lt;p&gt;It starts to look like a very Apple-like design choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you care about PWA specification support, Android is stronger
&lt;/h2&gt;

&lt;p&gt;If you judge PWAs purely by specification support, Android is much easier to understand.&lt;/p&gt;

&lt;p&gt;You write manifest.json, register a Service Worker, prepare icons, and set display and theme color.&lt;/p&gt;

&lt;p&gt;Then the result is usually close to what you expected.&lt;/p&gt;

&lt;p&gt;It is also easier for developers to predict.&lt;/p&gt;

&lt;p&gt;Chrome DevTools and Lighthouse make it easier to check, and Android follows the textbook PWA flow more clearly.&lt;/p&gt;

&lt;p&gt;If you want to make a web app feel truly close to a native app, Android is very strong.&lt;/p&gt;

&lt;p&gt;Android PWAs are especially useful for things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Offline tools&lt;/li&gt;
&lt;li&gt;Business apps&lt;/li&gt;
&lt;li&gt;Dashboards&lt;/li&gt;
&lt;li&gt;Input forms&lt;/li&gt;
&lt;li&gt;Web apps that use notifications&lt;/li&gt;
&lt;li&gt;Game-like full-screen experiences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Android is strong at moving the Web toward an app experience.&lt;/p&gt;

&lt;p&gt;I think that is clearly true.&lt;/p&gt;

&lt;h2&gt;
  
  
  As a home screen experience, iPhone is also very polished
&lt;/h2&gt;

&lt;p&gt;However, if you look at PWAs as a home screen experience, iPhone is also very polished.&lt;/p&gt;

&lt;p&gt;You open a page in Safari and add it to the home screen from the Share menu.&lt;/p&gt;

&lt;p&gt;An icon appears on the home screen.&lt;/p&gt;

&lt;p&gt;When you open it, it launches in an app-like view without the URL bar.&lt;/p&gt;

&lt;p&gt;This experience feels very natural.&lt;/p&gt;

&lt;p&gt;For ordinary users, the question is not whether the manifest is perfectly reflected.&lt;/p&gt;

&lt;p&gt;What matters more is whether the thing they placed on the home screen opens naturally.&lt;/p&gt;

&lt;p&gt;iPhone feels like it has been polishing that experience for a long time.&lt;/p&gt;

&lt;p&gt;Including the rounded icon shape, home screen alignment, and the way a web page blends into the home screen, the experience is very strong.&lt;/p&gt;

&lt;p&gt;So iPhone PWAs are not simply worse than Android PWAs.&lt;/p&gt;

&lt;p&gt;The goal is different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android turns the Web into apps, iPhone turns web pages into home screen entries
&lt;/h2&gt;

&lt;p&gt;To summarize the difference simply:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Android&lt;/th&gt;
&lt;th&gt;iPhone&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Core idea&lt;/td&gt;
&lt;td&gt;Turn the Web into apps&lt;/td&gt;
&lt;td&gt;Place web pages on the home screen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strong point&lt;/td&gt;
&lt;td&gt;PWA specification support&lt;/td&gt;
&lt;td&gt;Home screen experience&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;manifest&lt;/td&gt;
&lt;td&gt;Works fairly directly&lt;/td&gt;
&lt;td&gt;Partly works, but with strong iOS-specific behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Icons&lt;/td&gt;
&lt;td&gt;manifest icons and maskable icons matter&lt;/td&gt;
&lt;td&gt;apple-touch-icon is strong&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;display&lt;/td&gt;
&lt;td&gt;fullscreen and standalone are easy to see&lt;/td&gt;
&lt;td&gt;standalone is the realistic default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;Apps made from the Web&lt;/td&gt;
&lt;td&gt;Web pages placed on the home screen&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Android wants to turn the Web into an app.&lt;/p&gt;

&lt;p&gt;iPhone wants to make web pages first-class citizens on the home screen.&lt;/p&gt;

&lt;p&gt;When you look at it this way, the behavior differences become much easier to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  For services like Petal, the iPhone way feels very natural
&lt;/h2&gt;

&lt;p&gt;When I think about this difference, the iPhone way feels very natural for a service like Petal.&lt;/p&gt;

&lt;p&gt;Petal is not mainly about placing the service app itself on the home screen.&lt;/p&gt;

&lt;p&gt;It is about placing a person’s digital card or personal page on the home screen.&lt;/p&gt;

&lt;p&gt;In other words, it is not “launching an app.”&lt;/p&gt;

&lt;p&gt;It is closer to “opening a person.”&lt;/p&gt;

&lt;p&gt;This idea is closer to the iPhone-style “place a web page on the home screen” than the Android-style “turn the Web into an app.”&lt;/p&gt;

&lt;p&gt;You quietly place someone’s page on your own home screen.&lt;/p&gt;

&lt;p&gt;You open it with one tap when you need it.&lt;/p&gt;

&lt;p&gt;You are not called back by notifications. You remember it yourself and open it.&lt;/p&gt;

&lt;p&gt;For this kind of weak-connection design, iPhone’s home screen culture fits surprisingly well.&lt;/p&gt;

&lt;p&gt;This is something I would not have noticed just by building a PWA.&lt;/p&gt;

&lt;p&gt;I saw it because I built Petal and thought seriously about the experience of placing a person on the home screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  OJapp is also more about home screen entrances than PWA itself
&lt;/h2&gt;

&lt;p&gt;OJapp is similar.&lt;/p&gt;

&lt;p&gt;OJapp is not a service that wants to show off PWA technology itself.&lt;/p&gt;

&lt;p&gt;What it wants to do is place URLs on the smartphone home screen and turn websites into app-like entrances.&lt;/p&gt;

&lt;p&gt;In other words, it is less about turning the Web into apps and more about creating entrances that can live on the home screen.&lt;/p&gt;

&lt;p&gt;This idea is also close to the iPhone way of thinking.&lt;/p&gt;

&lt;p&gt;Of course, on Android, it behaves more strongly as a PWA.&lt;/p&gt;

&lt;p&gt;But the essence of OJapp is not only whether something can be installed.&lt;/p&gt;

&lt;p&gt;It is the culture of placing URLs on the home screen.&lt;/p&gt;

&lt;p&gt;From that point of view, the difference between iOS and Android is not just about superiority.&lt;/p&gt;

&lt;p&gt;It becomes a difference in what each platform is good at.&lt;/p&gt;

&lt;h2&gt;
  
  
  In PWA development, the point is not choosing which one is correct
&lt;/h2&gt;

&lt;p&gt;When building a PWA, trying to decide whether Android or iPhone is “correct” usually makes things harder.&lt;/p&gt;

&lt;p&gt;If you design only for Android, some settings will not work on iPhone.&lt;/p&gt;

&lt;p&gt;If you design only for iPhone, Android may create problems around scope or install detection.&lt;/p&gt;

&lt;p&gt;I ran into exactly this issue.&lt;/p&gt;

&lt;p&gt;On iPhone, I wanted a wider scope.&lt;/p&gt;

&lt;p&gt;On Android, if the scope is too wide, multiple PWA boundaries can become messy.&lt;/p&gt;

&lt;p&gt;It is not that one is right and the other is wrong.&lt;/p&gt;

&lt;p&gt;The goals are different.&lt;/p&gt;

&lt;p&gt;So what matters is designing separately based on the experience you want to create.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Android’s strong PWA behavior for app-like experiences&lt;/li&gt;
&lt;li&gt;Carefully design the home screen placement experience for iPhone&lt;/li&gt;
&lt;li&gt;Check manifest and scope behavior separately by OS&lt;/li&gt;
&lt;li&gt;Think about icons differently on Android and iPhone&lt;/li&gt;
&lt;li&gt;Always test on real devices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you start from this premise, it becomes much harder to make the wrong design choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;People often say that Android supports PWAs and iPhone does not.&lt;/p&gt;

&lt;p&gt;But after testing both, the reality looks a little different.&lt;/p&gt;

&lt;p&gt;Android is strong at turning the Web into apps.&lt;/p&gt;

&lt;p&gt;iPhone is strong at placing web pages on the home screen.&lt;/p&gt;

&lt;p&gt;For Android, a PWA is an app made from the Web.&lt;/p&gt;

&lt;p&gt;For iPhone, a PWA is closer to a web page placed on the home screen.&lt;/p&gt;

&lt;p&gt;That is why they behave differently.&lt;/p&gt;

&lt;p&gt;That is why the same manifest.json does not produce the same result.&lt;/p&gt;

&lt;p&gt;What I felt after testing many times is that iPhone does not fail to understand PWAs.&lt;/p&gt;

&lt;p&gt;Apple is giving a different answer from Google.&lt;/p&gt;

&lt;p&gt;When viewed that way, iOS-specific behavior becomes much easier to accept.&lt;/p&gt;

&lt;p&gt;And when you think about use cases like Petal, where someone’s page is placed on the home screen, the iPhone way can sometimes feel even more natural.&lt;/p&gt;

&lt;p&gt;If you judge PWAs only by support or non-support, you miss the real difference.&lt;/p&gt;

&lt;p&gt;Android and iPhone have different goals for PWAs.&lt;/p&gt;

&lt;p&gt;Starting from that idea makes web app design much more interesting.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>pwa</category>
      <category>android</category>
      <category>ios</category>
    </item>
  </channel>
</rss>
