Skip to main content

Relay Information

Reference for NIP-11 relay information documents and relay discovery.

NIP-11 Information Document​

Relays serve metadata via HTTP at their root URL.

Request​

curl -H "Accept: application/nostr+json" https://relay.example.com/

Response Format​

{
"name": "Example Relay",
"description": "A Nostr relay for everyone",
"pubkey": "32-byte-hex-pubkey",
"contact": "admin@example.com",
"supported_nips": [1, 2, 9, 11, 12, 15, 16, 20, 22, 33, 40],
"software": "https://github.com/Cameri/nostream",
"version": "1.22.6",
"limitation": {
"max_message_length": 65535,
"max_subscriptions": 20,
"max_filters": 10,
"max_subid_length": 100,
"max_event_tags": 100,
"max_content_length": 65535,
"min_pow_difficulty": 0,
"auth_required": false,
"payment_required": false,
"created_at_lower_limit": 31536000,
"created_at_upper_limit": 60
},
"relay_countries": ["US", "EU"],
"language_tags": ["en"],
"tags": ["community", "public"],
"posting_policy": "https://relay.example.com/policy",
"payments_url": "https://relay.example.com/pay",
"fees": {
"admission": [{"amount": 1000000, "unit": "msats"}],
"subscription": [{"amount": 5000000, "unit": "msats", "period": 2592000}],
"publication": [{"kinds": [4], "amount": 100, "unit": "msats"}]
},
"icon": "https://relay.example.com/icon.png"
}

Field Reference​

Basic Info​

FieldTypeDescription
namestringRelay name
descriptionstringRelay description
pubkeystringAdmin's public key
contactstringContact email/URL
softwarestringSoftware URL
versionstringSoftware version
iconstringRelay icon URL

Supported NIPs​

{
"supported_nips": [1, 2, 9, 11, 12, 15, 16, 20, 22, 33, 40]
}

Check before using features:

async function checkNipSupport(relayUrl, nip) {
const info = await getRelayInfo(relayUrl);
return info.supported_nips?.includes(nip) ?? false;
}

Limitations​

FieldDescription
max_message_lengthMaximum WebSocket message size
max_subscriptionsMax concurrent subscriptions
max_filtersMax filters per subscription
max_subid_lengthMax subscription ID length
max_event_tagsMax tags per event
max_content_lengthMax event content length
min_pow_difficultyRequired proof-of-work
auth_requiredNIP-42 auth required
payment_requiredPayment required to use
created_at_lower_limitMax age of events (seconds)
created_at_upper_limitMax future date (seconds)

Fees​

{
"fees": {
"admission": [{"amount": 1000000, "unit": "msats"}],
"subscription": [
{"amount": 5000000, "unit": "msats", "period": 2592000}
],
"publication": [
{"kinds": [4], "amount": 100, "unit": "msats"}
]
}
}

Fetching Relay Info​

JavaScript​

async function getRelayInfo(relayUrl) {
const httpUrl = relayUrl
.replace('wss://', 'https://')
.replace('ws://', 'http://');

const response = await fetch(httpUrl, {
headers: { Accept: 'application/nostr+json' }
});

if (!response.ok) {
throw new Error(`Failed to fetch relay info: ${response.status}`);
}

return response.json();
}

// Usage
const info = await getRelayInfo('wss://relay.damus.io');
console.log(info.name);
console.log(info.supported_nips);

With Timeout​

async function getRelayInfoWithTimeout(relayUrl, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);

try {
const httpUrl = relayUrl
.replace('wss://', 'https://')
.replace('ws://', 'http://');

const response = await fetch(httpUrl, {
headers: { Accept: 'application/nostr+json' },
signal: controller.signal
});

return response.json();
} finally {
clearTimeout(timeoutId);
}
}

Relay Discovery​

From User's Relay List (NIP-65)​

async function getUserRelays(pubkey) {
const events = await pool.querySync(defaultRelays, {
kinds: [10002],
authors: [pubkey],
limit: 1
});

if (events.length === 0) return [];

return events[0].tags
.filter(t => t[0] === 'r')
.map(t => ({
url: t[1],
read: !t[2] || t[2] === 'read',
write: !t[2] || t[2] === 'write'
}));
}

From NIP-05 Verification​

async function getRelaysFromNip05(identifier) {
const [name, domain] = identifier.split('@');
const url = `https://${domain}/.well-known/nostr.json?name=${name}`;

const response = await fetch(url);
const data = await response.json();

const pubkey = data.names?.[name];
if (!pubkey) return [];

return data.relays?.[pubkey] || [];
}

Public Relay Lists​

Monitoring Services​

ServiceURLDescription
nostr.watchnostr.watchRelay monitoring
nostr.infonostr.info/relaysRelay directory

Default Relays​

Common default relay lists:

const DEFAULT_RELAYS = [
'wss://relay.damus.io',
'wss://nos.lol',
'wss://relay.nostr.band',
'wss://relay.snort.social',
'wss://nostr.wine',
'wss://relay.primal.net',
'wss://purplepag.es'
];

Relay Categories​

By Purpose​

TypeDescriptionExample
GeneralAccept most eventsrelay.damus.io
PaidRequire paymentnostr.wine
PrivateAuth requiredPersonal relays
SpecializedSpecific contentLong-form only

By Region​

Consider geographic distribution for:

  • Lower latency
  • Legal compliance
  • Resilience

Best Practices​

  1. Check NIP support before using features
  2. Respect limitations to avoid disconnection
  3. Use multiple relays for reliability
  4. Cache relay info to reduce requests
  5. Handle missing fields gracefully
function getMaxContent(relayInfo) {
return relayInfo?.limitation?.max_content_length ?? 65535;
}

function isAuthRequired(relayInfo) {
return relayInfo?.limitation?.auth_required ?? false;
}

See Also​