Did you hear about smart banners? Smart banners are ios native banners. They show up when user navigates to a page on Safari, from a real iOS device, that has this meta tag:

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

App id can be found in App Store Connect under App Information.

When user clicks on the banner, it navigates to the App Store. Banner will not show up on ios emulator, just on a real device from Safari.

I think smart banners are nice. Looking from my analytics, I managed to get a couple of direct downloads, so I guess they do their job.

For Android, there’s no built-in meta tag. I didn't want to add extra dependency to my website landing page, so I made a simple smart banner with a little bit of CSS and vanilla JavaScript:

CSS:

#smartbanner {
  display: block;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  background: #f7f7f7;
  border-bottom: 1px solid #ccc;
  z-index: 9999;
  cursor: pointer;
  font-family: sans-serif;
  box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}

#smartbanner .content {
  display: flex;
  flex-direction: row;
  gap: 8px;
  padding: 12px;
  align-items: flex-end;
  flex: 1;
}

#smartbanner img {
  height: 48px;
  border-radius: 4px;
}

#smartbanner .text {
  flex: 1;
}

#smartbanner a {
  text-decoration: none;
  color: #007aff;
  font-weight: bold;
  margin-left: 8px;
}

#smartbanner .close {
  background: none;
  border: none;
  font-size: 16px;
  position: absolute;
  right: 12px;
  top: 12px;
  cursor: pointer;
  padding: 0;
}

And Js:

(function() {
  function smartBanner() {
    const title = '##-fill-app-name';
    const subtitle = '##fill-subtitle';
    const appId = '##fill-app-id';
    const appIcon = '##-fill-app-icon-url';

    const ua = navigator.userAgent || '';
    const uaData = navigator.userAgentData;
    const isAndroid =
      (uaData && (uaData.platform || '').toLowerCase().includes('android')) ||
      /Android/i.test(ua);

    const cacheKey = 'smDismissed';
    if (!isAndroid || localStorage.getItem(cacheKey)) return;
    const goToStore = () => {
      const market = `market://details?id=${appId}`;
      const https = `https://play.google.com/store/apps/details?id=${appId}`;

      window.location.replace(market);
      setTimeout(() => {
        window.location.replace(https);
      }, 1000);
    };
    const template = `
    <div id="smartbanner">
      <div class="content">
       <img src="${appIcon}" alt="smartbanner img"/>
          <div class="text">
            <div class="title">${title}</div>
            <div class="subtitle">${subtitle}</div>
          </div>
          <button class="go" target="_blank">View</button>
      </div>
      <button aria-label="close" class="close">&times;</button>
    </div>`;

    document.body.insertAdjacentHTML('beforeend', template);
    const banner = document.getElementById('smartbanner');

    function hide() {
      banner.remove();
      localStorage.setItem(cacheKey, '1');
    }

    banner.querySelector('.close').addEventListener('click', (e) => {
      hide();
    });
    banner.querySelector('.go').addEventListener('click', (e) => {
      goToStore();
      hide();
    })
  }

  if (document.readyState !== 'loading') {
    smartBanner();
  } else {
    document.addEventListener('DOMContentLoaded', smartBanner);
  }
})();

This smart banner just shows up on Android devices, with the user agent check. I don't show the smart banner again if the user dismisses it. This is how it looks like:

android smart banner