Embed widget.

One script tag and a button. The flow opens in a modal on your page, the user signs in their own wallet, and the tokens never touch your site or ours.

Updated 2026-09-15 · HoodLock Team

Install#

Include the script once, then mark any button with data-hoodlock. Everything except that attribute is optional, so a lock-only integration is a button with nothing else on it.

html
<script src="https://hoodlock.tech/embed.js" data-key="pk_YOUR_KEY"></script>

<!-- lock is the default mode, so this is the whole integration -->
<button data-hoodlock>Lock tokens</button>

<!-- pre-fill the token so the user cannot pick a different one -->
<button data-hoodlock data-token="0xYourTokenAddress">Lock tokens</button>

<button data-hoodlock data-mode="burn" data-token="0xYourTokenAddress">Burn tokens</button>

<button data-hoodlock data-mode="vesting"
        data-token="0xYourTokenAddress"
        data-beneficiary="0xTeamWallet">Create vesting</button>
Note

0xYourTokenAddress is a placeholder. Insert the real address from your own data when you render the page. It is different on every token page, so it is not a literal string to paste.

Your button keeps your styling#

The widget never touches how your button looks. It attaches a click handler and marks the element as wired; it sets no classes, no inline styles and no attributes that affect appearance. Style the button however you like, with Tailwind, CSS modules, a design system component or anything else.

This is worth stating plainly because it is the usual objection to embedded widgets: most teams want the functionality and their own design. Here you get both, because the only things we render are the modal and one small attribution line.

Attributes#

On the script tag#

AttributeRequiredWhat it does
data-keyyesYour public API key. Without it, clicking a button only logs an error to the browser console.
data-attributionnoSet to off to leave out the “Secured by HoodLock” line.

On a button#

AttributeRequiredWhat it does
data-hoodlockyesMarks the button. Nothing else is needed for a lock.
data-modenolock (default), burn or vesting. An unrecognised value falls back to lock.
data-tokennoPre-fills the token and makes the field read-only when it is a valid address. Without it, the user pastes a token address into the form.
data-beneficiarynoVesting only. Pre-fills the recipient; the user can still edit it.
data-unlocknoPre-fills the date from Unix seconds. For a lock this is the unlock date, and for vesting it is the date the schedule is fully vested. Only the day is kept, not the time.

JavaScript API#

window.HoodLock is available once the script has loaded. open also accepts a key option if you did not set data-key.

javascript
// open programmatically
HoodLock.open({ token: "0x…", unlockTime: 1790000000 });
HoodLock.open({ mode: "burn", token: "0x…" });
HoodLock.open({ mode: "vesting", token: "0x…", beneficiary: "0x…" });

// one handler for every product
HoodLock.on("done", ({ type, txHash, id, token, amount }) => {
  console.log(type, id, txHash);   // type: "locked" | "burned" | "vested"
});

// or listen per product
HoodLock.on("locked", ({ txHash, id }) => refreshMyUi(id));

HoodLock.close();   // close the modal
HoodLock.wire();    // re-scan the DOM after rendering new buttons
Note

Call HoodLock.wire() after any client-side render that adds buttons. It only picks up elements it has not already wired, so calling it more than once is safe.

Events#

EventPayloadWhen
readyNoneThe widget accepted your key and is showing the wallet choices. It does not fire when the key is rejected.
connected{ account }The user connected a wallet.
locked / burned / vested{ txHash, id, lockId, token, amount }The action was submitted and confirmed, or submitted with unconfirmed: true.
donethe same payload plus typeFires alongside each of the three above.
error{ message }Something failed. The message is already human-readable.
closeNoneThe modal was dismissed, closed with HoodLock.close(), or replaced by another open call.
Careful

A payload can carry unconfirmed: true. That means the transaction was broadcast but the receipt could not be fetched. It has most likely landed. Treat it as provisional and confirm against the chain rather than telling the user it failed.

id is read from the contract's record counter after the transaction confirms. It is null if that read fails, and if another user's action lands at the same moment it can point at their record instead, so check it against txHash before relying on it. lockId is an alias kept for older integrations.

The attribution line#

The widget adds one small line after the last HoodLock button it finds the first time it wires the page:

html
<div class="hoodlock-attribution">
  <a href="https://hoodlock.tech" target="_blank" rel="noopener">Secured by HoodLock</a>
</div>

It inherits your text colour, appears once per page however many buttons you have, and is a plain followable link that opens in a new tab. Turn it off with data-attribution="off" on the script tag if it does not suit the design.

Framing and CSP#

The modal is an iframe from hoodlock.tech/embed. If your site sends a Content-Security-Policy, allow it:

text
frame-src https://hoodlock.tech;
script-src https://hoodlock.tech;

When the user has no browser wallet#

The widget always offers WalletConnect next to any browser wallets it finds. A user without one, which is common in in-app browsers, can scan a QR code with a mobile wallet and sign there. You do not need to handle it.

Earnings#

You earn 50% of the fee on every lock, burn and vesting schedule made through your widget, whether or not the wallet has used HoodLock before. Just before the user signs, the widget tells our server what is about to be submitted, and the fee share is credited to you when that action appears on chain.

When a user connects, their wallet also asks them to sign a short message. If the wallet has never used HoodLock, that signature credits its later actions to you as well, wherever they happen. Declining the signature does not block anything. Actions from the wallet that owns your key do not count. Claim to your wallet from the developer dashboard once the balance is at least $10.

Prefer to build the interface yourself? The REST API exposes the same three products as prepared transactions.