17

I'm having some troubles with an iOS Smart App Banner, which I'm trying to add through JavaScript.

The actual smartbanner is as simple as adding this little block to the head of the HTML:

<meta name="apple-itunes-app" content="app-id=375380948">

Unfortunately, I'm quite restricted in the way I can upload my script. I can't change the HTML directly, so I'll do it through our Tag Manager, which basically does it through JavaScript. But it turns out that this doesn't work.

I've tried to simplify the case for testing:

  1. Hardcoded tag in the HTML: works (as expected)

     <meta name="apple-itunes-app" content="app-id=375380948">
    
  2. Inserted with JavaScript directly when the document is ready: works

     $(document).ready(function(){
         $("head").append('<meta name="apple-itunes-app" content="app-id=375380948">');
     });
    
  3. Inserted with JavaScript, after a setTimeout delay: DOES NOT WORK

     $(document).ready(function(){
         setTimeout(showBanner, 1);  //after 1 millisecond
     });
    
     function showBanner(){
         $("head").append('<meta name="apple-itunes-app" content="app-id=375380948">');
     }
    

Can anyone confirm or explain why this delayed JavaScript doesn't work?

Important: for testing open the page on an actual iOS device! Desktop Safari/Chrome or iOS emulator won't work. Also, don't close the banner, because it won't show up a second time.

UPDATE:

I've added some examples without jQuery, so plain 'ol JavaScript. But the results are the same. As soon as we wait for a setTimeout() the Smart App Banner fails to load.

  1. Vanilla JavaScript - direct execution. works

    showBanner();
    
    function showBanner() {
        var meta = document.createElement("meta");
        meta.name = "apple-itunes-app";
        meta.content = "app-id=375380948";
        document.head.appendChild(meta);
    }
    
  2. Vanilla JavaScript - delayed execution. DOES NOT WORK

    setTimeout(showBanner, 1);
    
    function showBanner() {
        var meta = document.createElement("meta");
        meta.name = "apple-itunes-app";
        meta.content = "app-id=375380948";
        document.head.appendChild(meta);
    }
    

UPDATE 2:

The exact same unfortunate behavior can be observed when loading the script asynchronously

  1. async loading. DOES NOT WORK

    <script src="async.js" async></script>
    

    Which then calls the same vanilla JavaScript with direct execution showBanner();

    function showBanner() {
        var meta = document.createElement("meta");
        meta.name = "apple-itunes-app";
        meta.content = "app-id=375380948";
        document.head.appendChild(meta);
    }
    

CONCLUSION:

I can only conclude that iOS Safari only looks for the smartbanner the HTML in the primary thread. And that makes me sad :-(

Only the directly available HTML, or HTML that is added synchronously through JavaScript. But no a-sync action is allowed, be it loading the JavaScript asynchronously, or using setTimeout() (or an other construct that uses eval())

Koesper
  • 533
  • 6
  • 19
  • 1
    I'm having this same issue. I have a single page application where I don't want the app download to show on load because there is a form we don't want people to go past. After they fill out the form there is a page with a regular download button already BUT the client wants this banner as well. It would be great if anyone knows an Id or class name for this object that is added so I can hide it on load and then show it later. My safari version is < 7.1 so I can't remote debug. – wali Jul 08 '15 at 19:49
  • Looks like maybe the `app-id` in your examples is stale? Your "Vanilla JavaScript - direct execution." looks like exactly what I need. However, when testing on an iPhone 12 I saw the banner flash blank momentarily in Safari and nothing in Chrome (which is really just Safari under the hood on iOS I've learned). Anyway, if possible maybe you can update to some point to some app unlikely to be removed? – Greg Venech Oct 29 '21 at 13:02
  • 1
    @GregVenech, i just updated all the examples, with a simple find&replace, since that app id is indeed very old. It now links to Apple's Apple Store App. https://apps.apple.com/nl/app/apple-store/id375380948?l=en Havent run any new tests though, let me know how it works out for you. – Koesper Nov 01 '21 at 10:55

3 Answers3

5

Since it is not possible to have safari show the native banner if it is inserted after the page load (As tested above, and confirmed by apple), the only viable workaround is not to use the native smartbanner, but to create your own.

For instance with a javascript plugin like this

Koesper
  • 533
  • 6
  • 19
0

I used your code:

var meta = document.createElement("meta");
meta.name = "apple-itunes-app";
meta.content = "app-id=375380948";
document.head.appendChild(meta);

and inserted before the dom ready event and it worked fine.

Rich
  • 1
-2

As of April 2017, the smart banner will show up if added later via JavaScript.

simbolo
  • 7,279
  • 6
  • 56
  • 96
  • 3
    Do you have any documentation to link to in support of this answer? From my experimentation, this doesn't work. – David V Jul 19 '17 at 19:37
  • @DavidV No, I got it working on a client project I was working on just by trial and error. If it helps with your test, I add the banner during a user click event (basically displaying the banner during a 'next' button click during onboarding flow). This was pre iOS 11 by the way. – simbolo Jul 23 '17 at 22:43
  • 1
    Does not work for me either... I am trying to add the banner based on some routing conditions.. but it does not show up.. – jerry Dec 13 '17 at 00:52
  • 1
    Doesn't work for me. Tried appending meta tag to head element, banner didn't show up.. :( – Dong Feb 06 '18 at 18:08
  • for me it worked after deleting the website and data including cookies, didn't work if i delete only for that website steps-> settings->safari->clear history and website data – rdhaundiyal Dec 13 '18 at 00:53
  • Async or delayed loading of iOS smart apps banner does not work for me in 2022 – Kyle Vassella Jun 24 '22 at 04:59