Nostr is an open protocol in which each user holds a key pair, signs JSON messages called events, and publishes them to relays, which are ordinary servers that clients reach over WebSockets. Anyone can run a relay and a client can use several, and because every event is signed, a reader can check that a relay has not altered it.

Learning objectives

After reading this article you will be able to:

  • Describe the fields of a Nostr event and how its signature protects it
  • Explain how Nostr clients and relays exchange messages over WebSockets
  • Identify what a relay can still see despite NIP-44 encryption and NIP-59 gift wrapping

How Nostr works

The name stands for “Notes and Other Stuff Transmitted by Relays”. The project README describes the idea simply: each person publishes notes to several relays, which are simple servers, and people who follow them connect to those relays to fetch the notes. Relays can be run by anyone, with whatever rules their operators choose. Because every note is signed, a relay can refuse to carry a note or lose it, but it cannot forge or alter one without the signature failing. The repository is released into the public domain.

NIP-01 defines the core. There is one object type, the event, with these fields:

  • id, the SHA-256 hash of the serialised event
  • pubkey, the author’s public key
  • created_at, a Unix timestamp
  • kind, a number that tells clients how to interpret the event
  • tags, references to other events, keys and values
  • content, the payload
  • sig, a Schnorr signature over the id, on the secp256k1 curve

Kinds are grouped by convention. Regular events are expected to be stored by relays, replaceable events keep only the latest version per author and kind, and ephemeral events are not expected to be stored at all.

Clients and relays

Relays expose a WebSocket endpoint, and NIP-01 says a client should open one connection per relay and use it for all its subscriptions. A client sends three kinds of message: EVENT to publish, REQ to subscribe with one or more filters, and CLOSE to end a subscription. Filters can match on event ids, authors, kinds, tag values, and a time range. The relay answers with matching EVENTs, an EOSE marker at the end of stored events, OK to accept or reject a published event with a reason, CLOSED when it ends a subscription, and NOTICE for human-readable messages.

Relays decide what they accept. NIP-01’s examples include rejecting events from unregistered keys and events with implausible timestamps. Finding which relays hold a given person’s events is, in the README’s words, the hardest part, and clients use several heuristics to approach it.

NIPs

Everything beyond the basics lives in NIPs, Nostr Implementation Possibilities, kept in a public repository. The NIPs README is explicit that they are not a checklist: nothing forces software to implement any NIP, and each app picks the subset it needs. Some are marked unrecommended. NIP-04, the original encrypted direct message format, is deprecated in favour of NIP-17.

Private messages: NIP-44 and NIP-59

NIP-44 defines versioned encryption for payloads inside signed events. Version 2 uses secp256k1 ECDH, HKDF, padding, ChaCha20, HMAC-SHA256 and base64. The NIP lists its own limits plainly: no deniability, no forward secrecy, no post-compromise security, a user’s IP address possibly visible to relays, a public created_at, and padding that only partly hides message length. For high-risk situations it advises using specialised end-to-end encrypted messaging software.

NIP-59 adds gift wrapping to hide who sent what. The real event becomes an unsigned “rumor”. The rumor is encrypted into a “seal” signed by the author and addressed to nobody visible. The seal is then encrypted into a “gift wrap” signed by a random, one-time key and tagged with the recipient’s key so relays can route it. A relay sees the recipient tag and a throwaway signer, not the author or the content.

What Nostr is good for, and what it is not

Nostr gives an app a way to reach people anywhere without running its own messaging backend, as long as both sides can reach a common relay. That is also its limit: relays are servers on the internet, so Nostr needs a working network path. It does not replace a local radio when there is no network at all. Even with sealing, encryption hides content more than metadata: a relay sees connections, subscriptions, timing and volume.

Some apps pair it with a local link for that reason. Bitchat pairs a Bluetooth mesh with Nostr relays as its internet fallback, described in how to build an app like Bitchat. The Offline Protocol mesh SDK also lists Nostr as a transport. It is off by default in React Native and needs at least one reachable relay URL. In version 0.27.0 the SDK seals outgoing envelopes by default as NIP-59 gift wraps with NIP-44 encryption, and a relay still sees subscriptions, timing and traffic volume. Its cold contact setting, on by default, publishes key packages to relays so peers can make first contact.

Frequently asked questions

Does Nostr work without internet?

No. A relay is a server reached over a WebSocket, so both sides need a network path to a common relay. Nostr can stand in for a messaging backend you would otherwise run, but not for a local radio link.

Is Nostr end-to-end encrypted?

Not by default. Ordinary events are public and signed. NIP-44 defines encrypted payloads and NIP-59 wraps events to hide their author and content, and an app has to use them deliberately. NIP-44 lists its own limits, including no forward secrecy.

Sources

Build it with Offline Protocol

The Reticulum and Nostr page covers enabling Nostr in the mesh SDK, choosing relays for a deployment, keeping envelope sealing on, and what a relay still observes.

Read Reticulum and Nostr