Skip to main content

Verified against NodeInfo PROTOCOL.md and 2.0/2.1 JSON schemas (jhass/nodeinfo), FEP-0151 (FINAL), mastodon.social and misskey.io NodeInfo (fetched 2026-10-15) on 2026-10-15.

NodeInfo

NodeInfo is a protocol for exposing metadata about a server. It provides information like software name, version, usage statistics, and supported protocols.

Specification​

How It Works​

1. Client fetches /.well-known/nodeinfo
2. Response contains links to NodeInfo documents
3. Client fetches the NodeInfo document
4. Gets server metadata

Discovery​

Request​

GET /.well-known/nodeinfo HTTP/1.1
Host: example.com
Accept: application/json

Response​

{
"links": [
{
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",
"href": "https://example.com/nodeinfo/2.1"
},
{
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.0",
"href": "https://example.com/nodeinfo/2.0"
}
]
}

NodeInfo Document​

Schema 2.1 (Current)​

All of version, software (with name and version), protocols (at least one), services, openRegistrations, usage (with users) and metadata are required by both the 2.0 and 2.1 schemas; software.name must match ^[a-z0-9-]+$.

{
"version": "2.1",
"software": {
"name": "myserver",
"version": "1.0.0",
"repository": "https://github.com/example/myserver",
"homepage": "https://example.com/"
},
"protocols": ["activitypub"],
"usage": {
"users": {
"total": 1000,
"activeMonth": 500,
"activeHalfyear": 800
},
"localPosts": 50000
},
"openRegistrations": true,
"services": {
"inbound": [],
"outbound": ["atom1.0", "rss2.0"]
},
"metadata": {
"nodeName": "Example Server",
"nodeDescription": "A friendly ActivityPub server"
}
}

Mastodon (4.7) publishes only NodeInfo 2.0: mastodon.social's /.well-known/nodeinfo links just /nodeinfo/2.0, with nodeName, nodeDescription, optInServerDirectory and optInServerRecommendation in metadata. Don't assume a 2.1 document exists — follow whatever the discovery document links.

Properties​

PropertyDescription
versionNodeInfo schema version
software.nameSoftware name (^[a-z0-9-]+$)
software.versionSoftware version
protocolsSupported protocols
usage.usersUser statistics
usage.localPostsNumber of local posts
usage.localCommentsNumber of local comments (optional)
openRegistrationsWhether signups are open
servicesThird-party services the server can receive from (inbound) or publish to (outbound), e.g. rss2.0
metadataAdditional custom data

Implementation​

Discovery Endpoint​

// Use your configured domain, not req.hostname (the Host header is client-controlled)
const DOMAIN = 'example.com';

app.get('/.well-known/nodeinfo', (req, res) => {
res.json({
links: [
{
rel: 'http://nodeinfo.diaspora.software/ns/schema/2.1',
href: `https://${DOMAIN}/nodeinfo/2.1`
}
]
});
});

NodeInfo Endpoint​

app.get('/nodeinfo/2.1', async (req, res) => {
const stats = await getStats();

// The protocol asks for this media type, with the schema as profile
res.type('application/json; profile="http://nodeinfo.diaspora.software/ns/schema/2.1#"');
res.send(JSON.stringify({
version: '2.1',
software: {
name: 'myserver',
version: '1.0.0',
repository: 'https://github.com/example/myserver',
homepage: 'https://example.com'
},
protocols: ['activitypub'],
usage: {
users: {
total: stats.totalUsers,
activeMonth: stats.activeMonth,
activeHalfyear: stats.activeHalfYear
},
localPosts: stats.localPosts
},
openRegistrations: true,
services: {
inbound: [],
outbound: []
},
metadata: {
nodeName: 'My ActivityPub Server',
nodeDescription: 'A custom ActivityPub implementation'
}
}));
});

async function getStats() {
const now = new Date();
const monthAgo = new Date(now - 30 * 24 * 60 * 60 * 1000);
const halfYearAgo = new Date(now - 180 * 24 * 60 * 60 * 1000);

return {
totalUsers: await db.users.count(),
activeMonth: await db.users.count({ lastActiveAt: { $gte: monthAgo } }),
activeHalfYear: await db.users.count({ lastActiveAt: { $gte: halfYearAgo } }),
localPosts: await db.posts.count()
};
}

Schema Versions​

2.0 vs 2.1​

Version 2.1 adds:

  • software.repository - Source code URL
  • software.homepage - Project homepage

FEP-0151 says servers SHOULD implement 2.1. Clients follow the highest version linked from the discovery document, so publishing only 2.1 is fine; publish 2.0 too only if you need very old consumers.

FEP-0151 (2025 edition)​

FEP-0151 (FINAL, March 2026) is the current guidance on NodeInfo in fediverse software — a revised version of the 2020 FEP-f1d5. Key rules:

  • Treat software.name and software.version as opaque strings: you MUST NOT infer capabilities from them (version info MAY be used to block software with known vulnerabilities).
  • Servers that want to hide usage statistics SHOULD publish an empty usage.users object rather than skewed numbers.
  • For capability discovery, prefer protocol-level mechanisms such as FEP-844e over NodeInfo.

Common Software Names​

SoftwareName Value
Mastodonmastodon
Pleromapleroma
Pixelfedpixelfed
Lemmylemmy
PeerTubepeertube
Misskeymisskey
GoToSocialgotosocial

Protocols​

ProtocolDescription
activitypubActivityPub federation
diasporaDiaspora protocol
ostatusOStatus (legacy)
zotZot protocol (Hubzilla)

Usage by Federation Tools​

NodeInfo is used by:

  • FediDB - Statistics
  • Instance pickers and directories

Metadata Extensions​

metadata is free-form. FEP-0151 lists the widely used keys: nodeName, nodeDescription, staffAccounts (actor IDs) and federation.enabled:

{
"metadata": {
"nodeName": "My server",
"nodeDescription": "My server",
"staffAccounts": ["https://social.example/actors/1"],
"federation": { "enabled": true }
}
}

Other keys vary by software. Misskey, for example, publishes maintainer, langs, tosUrl, privacyPolicyUrl, repositoryUrl, feedbackUrl and more (from misskey.io's /nodeinfo/2.1). Treat anything outside FEP-0151's list as software-specific.

Caching​

NodeInfo can be cached:

res.set('Cache-Control', 'public, max-age=1800'); // 30 minutes

Testing​

# Fetch discovery document
curl https://mastodon.social/.well-known/nodeinfo

# Fetch NodeInfo
curl https://mastodon.social/nodeinfo/2.0

Next Steps​