Skip to content

Hello Nostr Documentation

Welcome to Hello Nostr Documentation

This documentation will guide you through understanding how Nostr works and how to send your first “Hello Nostr” message using HTML, CSS, and JavaScript. You can use the example code from https://gitlab.com/digitalethicsagency/hello-nostr/ or try out a live demonstration by https://note.hellonostr.dev/

Introduction to Nostr Development

Nostr is a simple, open protocol that powers decentralized communication. In this example, you will learn how to generate key pairs, sign messages, and send events to relays.

Key Formats in Nostr

Nostr keys are represented in two formats:

  1. npub/nsec format (human-readable)
  2. hex format (raw cryptographic representation)
  • npub: This is a public key, encoded in Bech32 format, which is easier for humans to read and share.
  • nsec: This is a private key, also encoded in Bech32, used to sign messages. Never share this key!

Here’s an example:

  • npub (public key): npub1abcxyz...
  • nsec (private key): nsec1xyz...

Alternatively, keys can be represented in hexadecimal format:

  • Public key (hex): abcdef123456...
  • Private key (hex): 9876abcdef...

The npub/nsec format is simply a user-friendly way to represent the same key data in a more readable form.


Signing Messages in Nostr

Nostr uses public-key cryptography. You will use:

  1. A private key (nsec or hex) to sign messages.
  2. A public key (npub or hex) to verify messages.

How it works:

  • The private key is used to create a cryptographic signature for your message.
  • This signature proves that the message is authentic and was sent by you.
  • The public key is used by others to verify that the signature is valid and the message hasn’t been altered.

Think of the private key like a stamp that only you have, and the public key like an ID card that others use to check the authenticity of the message.


Cryptography: ECDSA and secp256k1

Nostr uses the same cryptographic algorithm as Bitcoin to sign messages: ECDSA (Elliptic Curve Digital Signature Algorithm) with the secp256k1 curve.

This means that Nostr’s cryptography is built on a strong security foundation, similar to Bitcoin.


Event Types in Nostr (NIP 1)

NIP 1 defines the basic types of events (messages) in Nostr:

  • Kind 0 (Metadata): Used to store user profile information (e.g., display name, picture, bio).
  • Kind 1 (Notes): Used for general messages or posts (like tweets).

In this example, we will only work with Kind 0 and Kind 1 events.


Step-by-Step Guide to Send a Nostr Message

Here’s how the process is structured:

1. Key Generation

We first generate a new private key, which can be in different formats: Uint8Array (byte array for raw data processing), hex (human-readable), or Bech32 (error-resistant, human-readable format).

Here is the key generation process:

// Generate a new private key
const privKey = NostrTools.generateSecretKey();
// Get the public key from the private key
const pubKey = NostrTools.getPublicKey(privKey);
// Display keys in Bech32 (nsec/npub) format
console.log(NostrTools.nip19.nsecEncode(privKey)); // Private key
console.log(NostrTools.nip19.npubEncode(pubKey)); // Public key

2. Create and Sign an Event

Next, we create a Kind 1 event (a note) and sign it with the private key:

// Create a new event (Kind 1)
let event = {
kind: 1,
pubkey: pubKey,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: "#hellonostr", // Your message content
};
// Sign the event with the private key
event.id = NostrTools.getEventHash(event);
event = await NostrTools.finalizeEvent(event, privKey);
// Log the signed event
console.log("Signed event:", event);

3. Connect to Relays and Send the Event

To broadcast the event to the Nostr network, we connect to relay servers via WebSockets. Here’s how we send the event:

const relayUrls = [
"wss://relay.damus.io",
"wss://nostr.wine",
"wss://nostr.fmt.wiz.biz",
"wss://relay.snort.social",
"wss://frysian.nostrich.casa",
"wss://eden.nostr.land"
];
relayUrls.forEach((url) => {
const socket = new WebSocket(url);
socket.onopen = () => {
console.log(`Connected to ${url}`);
// Send the signed event to the relay
socket.send(JSON.stringify(["EVENT", event]));
};
socket.onmessage = (message) => {
console.log(`Message from ${url}:`, message.data);
};
socket.onclose = () => {
console.log(`Disconnected from ${url}`);
};
});

4. Displaying the Published Relays

After sending the event, you can display the relays where the message was published:

// Display relays where the message was published
function displayMessage(id, content, append = false) {
const outputDiv = document.getElementById(id);
outputDiv.parentElement.style.display = "grid";
outputDiv.innerHTML = append ? outputDiv.innerHTML + content : content;
}
// Example of how to use displayMessage to show relays
relayUrls.forEach((url) => {
const socket = new WebSocket(url);
socket.onopen = () => {
console.log(`Connected to ${url}`);
socket.send(JSON.stringify(["EVENT", event]));
};
socket.onmessage = (message) => {
displayMessage("relays", `<span>${url}</span>`, true); // Display relay information
console.log(`Message from ${url}:`, message.data);
};
socket.onclose = () => {
console.log(`Disconnected from ${url}`);
};
});

5. Additional Relay Information

  • Why use multiple relays?
    Using multiple relays increases the likelihood that your content is distributed and stays accessible, even if some relays go offline. Relays operate independently, meaning they don’t automatically sync data with each other. Connecting to several relays ensures broader distribution of your messages and improves redundancy.

  • Free vs. paid relays:
    There are both free and paid relays in the Nostr ecosystem. Free relays are great for testing and learning, but paid relays typically offer better performance and reliability because they can afford to maintain higher-quality infrastructure.

  • Using relays based on follower lists:
    Some Nostr clients dynamically select relays based on the user’s follower list. This ensures that you’re connected to the same relays as the people you follow, improving message delivery and visibility.

6. Summary of the Process

To recap, here’s the process for sending a Nostr message:

  1. Key Generation:
    We generated a private/public key pair using Nostr tools.

  2. Creating and Signing an Event:
    We created a Kind 1 event (a note) and signed it with the private key.

  3. Connecting to Relays:
    We connected to multiple relay servers using WebSockets to ensure the message was distributed across the Nostr network.

  4. Displaying Published Relays:
    We displayed the relays where the message was successfully published.

  5. Understanding Relay Usage:
    We explored the importance of using multiple relays, the difference between free and paid relays, and how relays improve message distribution and visibility.

By following this guide, you’ve successfully sent a Nostr message using HTML, JavaScript, and WebSockets. This provides a foundation for understanding how to interact with the Nostr protocol and work with its key features.