Subscribe to NIP-66 events directly from Nostr relays. Verify monitor signatures yourself for trustless, privacy-preserving access to relay intelligence.
Use this file to discover all available pages before exploring further.
NIP-66 defines a relay monitoring system for Nostr. Monitors periodically check relays for health, capability, and availability, then publish their findings as signed Nostr events. You can subscribe to these events directly from the relays that carry them, verify the cryptographic signatures, and aggregate the data yourself — no intermediary, no API keys, and no trust required beyond the monitor signatures you inspect.
These relays carry NIP-66 monitoring data. Connect to one or more of them when building REQ filters.
Relay
Description
wss://relay.nostr.watch
Primary nostr-watch relay
wss://relaypag.es
Relaypages NIP-66 relay
wss://monitorlizard.nostr1.com
Monitor Lizard relay
Connect to multiple relays for redundancy. The same monitoring data is available across all three — if one is offline, the others still serve the events.
Always call verifyEvent() before trusting any NIP-66 data. Signature verification is what makes raw NIP-66 access trustless — you can prove that a specific monitor pubkey signed a specific observation.
import { verifyEvent } from 'nostr-tools'for (const event of events) { if (!verifyEvent(event)) { console.warn(`Invalid signature from ${event.pubkey}`) continue } // Event is cryptographically verified — safe to use}
Multiple monitors report on the same relay. To get a reliable picture, aggregate their observations by grouping events per monitor and computing consensus values:
import { SimplePool, verifyEvent } from 'nostr-tools'const pool = new SimplePool()const relays = ['wss://relay.nostr.watch', 'wss://relaypag.es']// Get all observations for a relayconst events = await pool.querySync(relays, { kinds: [30166], '#d': ['wss://relay.damus.io']})// Verify and deduplicate by monitor (keep most recent per monitor)const verified = events.filter(e => verifyEvent(e))const byMonitor = new Map()for (const event of verified) { const existing = byMonitor.get(event.pubkey) if (!existing || event.created_at > existing.created_at) { byMonitor.set(event.pubkey, event) }}// Aggregate RTT values (median across monitors)function getTagValue(event, tagName) { const tag = event.tags.find(t => t[0] === tagName) return tag ? Number(tag[1]) : null}const rttValues = [...byMonitor.values()] .map(e => getTagValue(e, 'rtt-open')) .filter(v => v !== null) .sort((a, b) => a - b)const medianRtt = rttValues[Math.floor(rttValues.length / 2)]console.log(`Median open RTT: ${medianRtt}ms from ${rttValues.length} monitors`)
Your app already speaks Nostr — if you are using nostr-tools, NDK, or a similar library, subscribing to kind 30166 events requires minimal additional code
Privacy is a priority — direct relay connections expose no IP to an intermediary API server
You need trustless verification — cryptographic signature verification proves that a named monitor produced a specific observation at a specific time
You are building a relay selection algorithm — raw observation data gives you full control over aggregation logic, outlier detection, and quorum thresholds
You need the freshest data possible — receive updates as monitors publish them rather than waiting for an aggregation layer
If you want structured relay intelligence without building your own aggregation pipeline, consider the REST API or CVM instead. They both derive from the same raw NIP-66 events.