Extension API
The extension exposes window.nostr for identity, event signing, and NIP-04/NIP-44 message encryption.
Install the extension, select an account, and connect your site when prompted. Signing and encryption require a signing-capable account and may prompt you to unlock the vault. Reading a known public key does not require unlocking it.
Setup
Check for the method you need before calling it. An injected provider does not mean the site is connected or a request has been approved.
// Feature detection
function hasNostr() {
return typeof window !== "undefined" &&
typeof window.nostr?.getPublicKey === "function";
}
// Wait for the extension to load
async function waitForNostr(timeout = 3000) {
const start = Date.now();
while (!hasNostr() && Date.now() - start < timeout) {
await new Promise(r => setTimeout(r, 100));
}
return hasNostr();
}NIP-07 Signer API
The extension implements the NIP-07 signer API exposed through window.nostr.
getPublicKey()
Returns the active account's hex-encoded public key. Requires site connection and identity access.
Returns
Promise<string>
Example
const pubkey = await window.nostr.getPublicKey();
console.log(pubkey); // "3bf0c63f..."signEvent(event)
Signs the event and adds id, pubkey and sig. Supply created_at yourself; the signer preserves your timestamp. If you supply pubkey, it must match the active account. Signing does not publish the event.
Parameters
| Name | Type | Description |
|---|---|---|
event | UnsignedEvent | Event containing kind, content, tags and created_at (Unix time in seconds) |
Returns
Promise<SignedEvent>
Example
const signed = await window.nostr.signEvent({
kind: 1,
content: "Hello Nostr!",
tags: [],
created_at: Math.floor(Date.now() / 1000),
});
console.log(signed.sig); // schnorr signaturenip04.encrypt(pubkey, plaintext)
Encrypts a message using NIP-04, the legacy direct-message encryption format.
Parameters
| Name | Type | Description |
|---|---|---|
pubkey | string | Recipient's 64-character hexadecimal public key |
plaintext | string | Message to encrypt |
Returns
Promise<string>
Example
const encrypted = await window.nostr.nip04.encrypt(
recipientPubkey,
"Secret message"
);nip04.decrypt(pubkey, ciphertext)
Decrypts a NIP-04 message.
Parameters
| Name | Type | Description |
|---|---|---|
pubkey | string | Sender's 64-character hexadecimal public key |
ciphertext | string | Encrypted message string |
Returns
Promise<string>
Example
const plaintext = await window.nostr.nip04.decrypt(
senderPubkey,
ciphertext
);
console.log(plaintext); // "Secret message"nip44.encrypt(pubkey, plaintext)
Encrypts a message using NIP-44. This example uses the standard two-argument call.
Parameters
| Name | Type | Description |
|---|---|---|
pubkey | string | Recipient's 64-character hexadecimal public key |
plaintext | string | Message to encrypt |
Returns
Promise<string>
Example
const encrypted = await window.nostr.nip44.encrypt(
recipientPubkey,
"Secret message"
);nip44.decrypt(pubkey, ciphertext)
Decrypts a NIP-44 message.
Parameters
| Name | Type | Description |
|---|---|---|
pubkey | string | Sender's 64-character hexadecimal public key |
ciphertext | string | Encrypted message string |
Returns
Promise<string>
Example
const plaintext = await window.nostr.nip44.decrypt(
senderPubkey,
ciphertext
);
console.log(plaintext); // "Secret message"getRelays()
Returns the relay URLs configured in the extension. Each entry has read: true and write: true. This method does not fetch the account's NIP-65 relay policies and may return an empty object.
Returns
Promise<Record<string, { read: boolean; write: boolean }>>
Example
const relays = await window.nostr.getRelays();
// {
// "wss://relay.damus.io": { read: true, write: true },
// "wss://nos.lol": { read: true, write: true }
// }Connection, permissions and errors
Calls return Promises and can reject if the user declines, the site is disconnected, identity access is disabled, or the request times out. Signing and encryption are unavailable for read-only accounts.
An account switch can invalidate a pending request. Page calls time out after 120 seconds, including time spent waiting for connection, permission or unlock. Catch errors and let the user retry; error messages are not stable machine-readable codes.
async function signNote(content) {
const provider = window.nostr;
if (typeof provider?.getPublicKey !== "function" ||
typeof provider?.signEvent !== "function") {
return { ok: false, reason: "provider-unavailable" };
}
try {
const pubkey = await provider.getPublicKey();
if (!pubkey) return { ok: false, reason: "no-active-account" };
const event = await provider.signEvent({
pubkey,
kind: 1,
content,
tags: [],
created_at: Math.floor(Date.now() / 1000),
});
return { ok: true, event };
} catch (error) {
return { ok: false, reason: "request-failed", error };
}
}Use the SDK for follow-graph queries and the WoT Oracle API for public mute evidence. Mute evidence is separate from follow distance; it does not produce a combined trust score. The extension provides identity and signing.