Casa Tookan · documentation

Test your app on the web

Casa Tookan's web build, devapp.casatookan.com, opens your app in a browser the way the phone's dApp browser does: same providers, same approval sheets, same CEID and Tookans — without a phone in the loop.

Developer tool — test wallets only
In one sentenceAdd one script to your page's <head>, serve your manifest with CORS, let devapp frame your page, and keep your session cookie when framed: your app then runs in devapp as it does in the phone.

How it works

On a phone, Casa Tookan injects its providers — window.ethereum, the Bitcoin providers, window.unisat, window.webXCP, window.casaTookan — into your page's WebView. A browser cannot inject a script into a page of another origin, so devapp opens your app in an iframe, and a small script your page loads, the bridge, asks devapp for those providers over postMessage. Every call then goes through Casa Tookan's approval sheets, and signatures are made by its web signer.

At once

Detected at load

The bridge sets window.casaTookan.isCasaTookan and window.ethereum.isCasaTookan as soon as it runs — over the window.ethereum a wallet extension such as MetaMask put in the frame. Calls made before the providers arrive wait for them.

Ethereum

Find it by EIP-6963

Some extensions (MetaMask) lock window.ethereum in every frame: nobody can replace it, and it stays theirs. Casa Tookan announces itself through EIP-6963 with the rdns com.everdreamsoft.casatookan: pick that provider when it is announced, window.ethereum only otherwise.

Outside devapp

Nothing changes

Your page loads the bridge only when devapp frames it. In the phone, in a plain tab or framed by any other site, it loads nothing.

What to add

  1. The bridge, first thing in <head>Before your own scripts, so it runs before them. It loads casa-tookan-web.js from devapp only when devapp is the page framing yours.
    <script>
      (function () {
        if (window.parent === window || window.ReactNativeWebView) return;
        var o = (location.ancestorOrigins && location.ancestorOrigins[0]) || '';
        if (!o && document.referrer) try { o = new URL(document.referrer).origin; } catch (e) {}
        if (o === 'https://devapp.casatookan.com')
          document.write('<script src="' + o + '/casa-tookan-web.js"><\/script>');
      })();
    </script>
    A page with a strict Content-Security-Policy needs https://devapp.casatookan.com in script-src, and 'unsafe-eval' while devapp frames it.
  2. Your manifest, readable from devappdevapp reads /.well-known/wallet-app.json (or casatookan.json) from its own origin: serve it with Access-Control-Allow-Origin: * — it is public. Without it the browser blocks the read, Casa Tookan sees no declared capability and refuses casaTookan.ceid and tookans calls. A phone applies no CORS: this only shows on the web. Best: give every /.well-known/ answer that header, the 404s included, so devapp can tell a file you don't serve from a network failure (it assumes a missing file when the browser is online).
  3. Let devapp frame youContent-Security-Policy: frame-ancestors 'self' https://devapp.casatookan.com on your pages: devapp may frame them, other sites may not. A page sent with X-Frame-Options or a stricter frame-ancestors stays blank in devapp.
  4. Keep your session when framedFramed by devapp, your page is a third party: a SameSite=Lax cookie is not sent, and your server answers 401 right after a sign-in that worked. Over https, set it SameSite=None; Secure; Partitioned — partitioned, the cookie is kept per top-level site, so a session opened in devapp is not the one a player has elsewhere, and browsers that block third-party cookies still keep it.
    Then refuse the requests another site sends with it: a POST whose Sec-Fetch-Site is neither same-origin nor none, or one that is not application/json (another site cannot send JSON without a CORS preflight you never grant).

For Ethereum, keep listening for Casa Tookan's announcement — in devapp it arrives a few milliseconds after your scripts; in the phone it answers your request:

let casaEthereum = null;
window.addEventListener('eip6963:announceProvider', (e) => {
  if (e.detail?.info?.rdns === 'com.everdreamsoft.casatookan') casaEthereum = e.detail.provider;
});
window.dispatchEvent(new Event('eip6963:requestProvider'));
const ethereum = () => casaEthereum ?? window.ethereum;   // at the moment you call it

Then open devapp, create a test wallet, and type your app's URL in Browse. A page without the bridge shows a notice with the line to add.

Your app on localhost

Serve your app on http://localhost and open that URL in devapp: browsers treat localhost as a secure origin, so an https page may frame it, and your page loads the bridge from devapp like any other. Chrome may ask devapp for access to your local network the first time: accept it. On http://localhost, Chrome accepts Secure cookies too.

Safety

RuleWhy
Trust devapp's origin onlyThe bridge evaluates the providers' code devapp sends: an origin you trust there can run code in your page. Never add localhost or a wildcard to the check in production.
Test wallets onlyThe web signer keeps its keys in the browser's storage, encrypted with a password, where an extension or a script on devapp's origin could reach them. Never type a recovery phrase that holds value; create a wallet for testing.
devapp is never framedIt is served with frame-ancestors 'none': no site can lay the wallet under a click.
Tokens, not pagesCEID tokens and Tookans receipts are signed by Casa Tookan: verify them on your server as in the phone. A page — or a fake devapp — cannot forge them.

Limits

No in-app purchases of Tookans, no WalletConnect pairing by camera, no App Attest or Play Integrity: those are phone features. Back and forward follow what the bridge reports.