No framework, no build step required. Import directly from a CDN for quick prototypes or install via npm for production builds.
<!-- No build tools needed — import directly in a module script -->
<script type="module">
import {
sigilRequest,
createConnectRequest,
} from 'https://esm.sh/@sigil-oss/connect@latest';
document.getElementById('connect-btn').addEventListener('click', async () => {
const result = await sigilRequest(
createConnectRequest({
type: 'connect',
dapp: { name: 'My App', origin: 'https://myapp.example' },
permissions: ['transfer', 'sign_message'],
})
);
if (result.status === 'connected') {
console.log('identity:', result.identity);
}
});
</script>npm install @sigil-oss/connectCreate a page at /__sigil__ on your origin. It calls handleRedirect(), which reads ?result=, signals the waiting sigilRequest() Promise via BroadcastChannel, then closes the tab.
<!-- public/__sigil__/index.html (or route /__sigil__ in your server) -->
<!doctype html>
<html>
<head><title>Sigil callback</title></head>
<body>
<script type="module">
import { handleRedirect } from 'https://esm.sh/@sigil-oss/connect@latest';
handleRedirect(); // reads ?result=, broadcasts, closes tab
</script>
</body>
</html>For static hosting (Netlify, Vercel, GitHub Pages), create public/__sigil__/index.html. For server-rendered apps, add a route that serves the handler script at /__sigil__.
import {
sigilRequest,
createConnectRequest,
} from '@sigil-oss/connect';
const btn = document.getElementById('connect-btn');
if (!btn) throw new Error('connect-btn not found');
btn.addEventListener('click', async () => {
btn.disabled = true;
btn.textContent = 'Opening Sigil…';
try {
const result = await sigilRequest(
createConnectRequest({
type: 'connect',
dapp: { name: 'My App', origin: 'https://myapp.example' },
permissions: ['transfer', 'sign_message'],
})
);
if (result.status === 'connected') {
const el = document.getElementById('identity');
if (el) el.textContent = result.identity;
} else {
btn.textContent = 'Rejected';
}
} catch {
btn.textContent = 'Timed out';
} finally {
btn.disabled = false;
}
});import {
sigilRequest,
createSignMessageRequest,
} from '@sigil-oss/connect';
async function signIn() {
const nonce = crypto.randomUUID();
const result = await sigilRequest(
createSignMessageRequest({
type: 'sign_message',
dapp: { name: 'My App', origin: 'https://myapp.example' },
message: [
'Sign in to My App',
`nonce: ${nonce}`,
`issuedAt: ${new Date().toISOString()}`,
].join('\n'),
})
);
if (result.status !== 'signed' || result.type !== 'sign_message') return;
const res = await fetch('/api/auth/qubic', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
identity: result.identity,
signature: result.signature,
public_key: result.public_key,
nonce,
}),
});
if (res.ok) {
const { token } = await res.json();
sessionStorage.setItem('token', token);
window.location.href = '/dashboard';
}
}
document.getElementById('signin-btn').addEventListener('click', signIn);import {
sigilRequest,
createTransferRequest,
} from '@sigil-oss/connect';
async function sendPayment(to, amount) {
const result = await sigilRequest(
createTransferRequest({
type: 'transfer',
dapp: { name: 'My App', origin: 'https://myapp.example' },
to,
amount,
})
);
if (result.status === 'signed' && (result.type === 'transfer' || result.type === 'sc_call')) {
console.log('tx hash:', result.tx_hash);
console.log('target tick:', result.target_tick);
}
}