On this page

On this page

Developer and self-hosted

Nostr

Nostr is a downloadable channel plugin (@openclaw/nostr) that lets OpenClaw receive and answer NIP-04 encrypted direct messages over Nostr relays. One account per gateway; DMs only.

Install

bash
openclaw plugins install @openclaw/nostr

Use the bare package spec to follow the current official release tag. Pin an exact version only when you need a reproducible install.

From a local checkout (dev workflows):

bash
openclaw plugins install --link <path-to-local-nostr-plugin>

Installing or enabling the plugin applies it to a running Gateway; check the application result. Onboarding (openclaw onboard) and openclaw channels add surface Nostr from the shared channel catalog once the plugin is installed.

Non-interactive setup

bash
openclaw channels add --channel nostr --private-key "$NOSTR_PRIVATE_KEY"openclaw channels add --channel nostr --private-key "$NOSTR_PRIVATE_KEY" --relay-urls "wss://relay.damus.io,wss://relay.primal.net"

Use --use-env to keep NOSTR_PRIVATE_KEY in the environment instead of storing the key in config (default account only).

Quick setup

  1. Generate a Nostr keypair (if needed):
bash
# Using naknak key generate
  1. Add to config:
json5
{  channels: {    nostr: {      privateKey: "${NOSTR_PRIVATE_KEY}",    },  },}
  1. Export the key:
bash
export NOSTR_PRIVATE_KEY="nsec1..."
  1. Restart the gateway.

Configuration reference

Key Type Default Description
privateKey string required Private key in nsec or hex format; secret refs allowed
relays string[] ['wss://relay.damus.io', 'wss://nos.lol'] Relay URLs (WebSocket)
dmPolicy string pairing DM access policy
allowFrom string[] [] Allowed sender pubkeys
enabled boolean true Enable/disable channel
name string - Display name
profile object - NIP-01 profile metadata

Profile metadata

Profile data is published as a NIP-01 kind:0 event. You can manage it from the Control UI (Channels -> Nostr -> Profile) or set it directly in config.

Example:

json5
{  channels: {    nostr: {      privateKey: "${NOSTR_PRIVATE_KEY}",      profile: {        name: "openclaw",        displayName: "OpenClaw",        about: "Personal assistant DM bot",        picture: "https://example.com/avatar.png",        banner: "https://example.com/banner.png",        website: "https://example.com",        nip05: "openclaw@example.com",        lud16: "openclaw@example.com",      },    },  },}

Notes:

  • Profile URLs must use https://.
  • Importing from relays merges fields and preserves local overrides.

Access control

DM policies

  • pairing (default): unknown senders get a pairing code.
  • allowlist: only pubkeys in allowFrom can DM.
  • open: public inbound DMs (requires allowFrom: ["*"]).
  • disabled: ignore inbound DMs.

Gateway pairing approval notifications require a running Nostr account. If the account is stopped, approval still succeeds, but the Gateway reports that notification failed.

The CLI's pairing approve nostr ... --notify cannot access the Gateway's Nostr connection, so notification fails even when the account is running. Pairing approval still succeeds; use a Gateway client to request an approval notification.

Enforcement notes:

  • Inbound event signatures are verified before sender policy and NIP-04 decryption, so forged events are rejected early.
  • Pairing replies are sent without decrypting or processing the original DM body.
  • Inbound DMs are rate-limited (globally and per sender) and oversized payloads are dropped before decrypt.
  • With dmPolicy: "allowlist" and a nonempty allowFrom containing only literal hex or npub public keys (optionally prefixed with nostr:), other authors are dropped locally before durable storage and rate accounting. The peer list is not sent to relays. Matching authors still undergo normal authorization. Wildcards, access groups, invalid entries, and other DM policies retain the normal admission path; this does not protect against relay/network flooding or abuse by allowed senders.

Allowlist example

json5
{  channels: {    nostr: {      privateKey: "${NOSTR_PRIVATE_KEY}",      dmPolicy: "allowlist",      allowFrom: ["npub1abc...", "npub1xyz..."],    },  },}

Key formats

Accepted formats:

  • Private key: nsec... or 64-char hex
  • Pubkeys (allowFrom): npub... or hex

Relays

Defaults: relay.damus.io and nos.lol.

json5
{  channels: {    nostr: {      privateKey: "${NOSTR_PRIVATE_KEY}",      relays: ["wss://relay.damus.io", "wss://relay.primal.net", "wss://nostr.wine"],    },  },}

Tips:

  • Use 2-3 relays for redundancy.
  • Avoid too many relays (latency, duplication).
  • Paid relays can improve reliability.
  • Local relays are fine for testing (ws://localhost:7777).

Protocol support

NIP Status Description
NIP-01 Supported Basic event format + profile metadata
NIP-04 Supported Encrypted DMs (kind:4)
NIP-17 Planned Gift-wrapped DMs
NIP-44 Planned Versioned encryption

Testing

Local relay

bash
# Start strfrydocker run -p 7777:7777 ghcr.io/hoytech/strfry
json5
{  channels: {    nostr: {      privateKey: "${NOSTR_PRIVATE_KEY}",      relays: ["ws://localhost:7777"],    },  },}

Manual test

  1. Note the bot pubkey from gateway logs or openclaw channels status (hex; convert to npub in your client if needed).
  2. Open a Nostr client (Amethyst, Damus, etc.).
  3. DM the bot pubkey.
  4. Verify the response.

Troubleshooting

Not receiving messages

  • Verify the private key is valid.
  • Check that relay URLs are reachable and use wss:// (or ws:// for local).
  • Confirm enabled is not false.
  • Check gateway logs for relay connection errors.

Not sending responses

  • Check relay accepts writes.
  • Verify outbound connectivity.
  • Watch for relay rate limits.

Duplicate responses

  • Expected when using multiple relays.
  • Messages are deduplicated by event ID; only the first delivery triggers a response.

Security

  • Never commit private keys.
  • Use environment variables for keys.
  • Consider allowlist for production bots.
  • Signatures are verified before sender policy, and sender policy is enforced before decrypt, so forged events are rejected early and unknown senders cannot force full crypto work.

Limitations (MVP)

  • Direct messages only (no group chats).
  • No media attachments.
  • NIP-04 only (NIP-17 gift-wrap planned).
Was this useful?