[Ethereum] Check if Metamask was just installed after asking the user to do so

browsersdapp-developmentmetamaskuser-experience

In an effort to make my dApp more user-friendly, especially for onboarding, I'm trying to guide new users into installing Metamask.

If no web3 provider is present, I show the user a "Create your wallet" button. When they click on it, they are headed to Metamask.io in a new tab.

The trouble arises when they install Metamask and go back to my dApp. There doesn't seem to be a way of detecting if a web3 provider is installed without reloading. I can't just programmatically reload the whole page, and asking my disengaged potential user to reload feels like very bad UX.

I created the following code snippet taken from Metamask's documentation to illustrate this behaviour.

<html>
<body>
  <script language="javascript">
  function checkProvider () {
    if (typeof window.ethereum !== 'undefined') {
      console.log('you already have a web3 provider');
    } else {
      console.log('please install Metamask');
    }
  }
  var interval = setInterval(checkProvider, 1000);
  </script>
</body>
</html>

Basically it checks every second if you have a web3 provider. Since it can't run without a webserver, I put it online so you can quickly test it.

If I don't have Metamask installed, I get the expected message:

please install metamask

But after I install it and go back to this page, the same message keeps appearing:

metamask isn't detected without a refresh

Only after a refresh does my snippet detect metamask:

metamask is detected after a refresh

I can't be the only one facing onboarding issues with web3 providers. What workarounds have you thought of?

Best Answer

You need to programmatically refresh the page to get web3 injected by metamask. You can write a recurisve function which will not run indefinetly and will refresh if metamask was not installed and installed later:

function checkWeb3ProviderRecursively(firstCall = true) {
    if (typeof window.ethereum !== 'undefined') {
        console.log("web3 provide detected")
        // reload the page
        if(!firstCall) document.location.reload()
    } else {
        console.log("Please install metamask")
        // add a delay here as you want
        checkWeb3ProviderRecursively(false)
    }
}