Nostr DM Channel Plugin for OpenClaw via NIP-04 Encrypted Messages

This page covers the Nostr channel plugin for OpenClaw, enabling encrypted DM communication through Nostr relays. It provides installation, configuration, and setup instructions for developers integrating Nostr DMs.

Read this when

  • You want OpenClaw to receive DMs via Nostr
  • You're setting up decentralized messaging

Nostr is a downloadable channel plugin (@openclaw/nostr) that enables OpenClaw to receive and reply to NIP-04 encrypted direct messages through Nostr relays. One account per gateway; only DMs are supported.

Install

openclaw plugins install @openclaw/nostr

Use the bare package spec to track the latest official release tag. Pin a specific version only when you need reproducible builds.

From a local checkout (development workflows):

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

Restart the gateway after installing or enabling plugins. Once the plugin is installed, openclaw onboard and openclaw channels add expose Nostr in the shared channel catalog.

Non-interactive setup

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 rather than storing the key in configuration (applies to the default account only).

Quick setup

  1. Generate a Nostr keypair if you do not already have one:
# Using nak
nak key generate
  1. Add it to the configuration:
{
  channels: {
    nostr: {
      privateKey: "${NOSTR_PRIVATE_KEY}",
    },
  },
}
  1. Export the key:
export NOSTR_PRIVATE_KEY="nsec1..."
  1. Restart the gateway.

Configuration reference

KeyTypeDefaultDescription
privateKeystringrequiredPrivate key in nsec or hex format; secret references allowed
relaysstring[]['wss://relay.damus.io', 'wss://nos.lol']Relay WebSocket URLs
dmPolicystringpairingPolicy for DM access
allowFromstring[][]Public keys of allowed senders
enabledbooleantrueTurn the channel on or off
namestring-Name shown in the interface
profileobject-NIP-01 profile metadata

Profile metadata

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

Example:

{
  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 keeps local overrides intact.

Access control

DM policies

  • pairing (default): unknown senders receive a pairing code.
  • allowlist: only pubkeys in allowFrom can send DMs.
  • open: anyone can send DMs (requires allowFrom: ["*"]).
  • disabled: inbound DMs are ignored.

Enforcement notes:

  • Inbound event signatures are verified before the sender policy and NIP-04 decryption are applied, 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 discarded before decryption.

Allowlist example

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

Key formats

Accepted formats:

  • Private key: nsec... or a 64-character hex string
  • Pubkeys (allowFrom): npub... or hex

Relays

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

{
  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 to reduce latency and duplication.
  • Paid relays can improve reliability.
  • Local relays work fine for testing (ws://localhost:7777).

Protocol support

NIPStatusDescription
NIP-01SupportedBasic event format and profile metadata
NIP-04SupportedEncrypted DMs (kind:4)
NIP-17PlannedGift-wrapped DMs
NIP-44PlannedVersioned encryption

Testing

Local relay

# Start strfry
docker run -p 7777:7777 ghcr.io/hoytech/strfry
{
  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 format; convert to npub in your client if needed).
  2. Open a Nostr client such as Amethyst or Damus.
  3. Send a DM to the bot pubkey.
  4. Check that you receive a response.

Troubleshooting

Not receiving messages

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

Not sending responses

  • Confirm the relay allows writes.
  • Ensure outbound connectivity is working.
  • Keep an eye on relay rate limiting.

Duplicate responses

  • Normal behavior when several relays are in use.
  • Duplicate messages are removed based on event ID; only the initial delivery causes a response.

Security

  • Private keys must never be committed.
  • Store keys using environment variables.
  • For production bots, allowlist is recommended.
  • Signatures are validated before sender policy, and sender policy is checked before decryption, so fake events are turned away early and unknown senders cannot force full cryptographic processing.

Limitations (MVP)

  • Only direct messages are supported, no group chats.
  • Media attachments are not available.
  • Only NIP-04 is used; NIP-17 gift-wrap is planned for the future.
930 words · updated Jul 27, 2026