What Is NodeInfo and Why Should You Implement It?

NodeInfo is an open protocol specification that allows servers in federated networks to expose structured metadata about themselves. This includes what software they're running, which protocols they support, and aggregate usage statistics (like total user counts and post counts).

If you're building any kind of federated or ActivityPub-compatible server, implementing NodeInfo is expected by the ecosystem. Tools like Fediverse Observer and various instance directories use NodeInfo to catalog and classify servers. It's also a useful signal for other servers deciding whether to federate with you.

The Two-Step Discovery Pattern

NodeInfo uses a two-step discovery process to stay flexible across versions:

  1. A well-known endpoint at /.well-known/nodeinfo returns a JSON document listing available NodeInfo URLs and their schema versions.
  2. The actual NodeInfo document lives at a URL you specify (typically /nodeinfo/2.1 or /nodeinfo/2.0).

This indirection means you can support multiple NodeInfo schema versions simultaneously without changing the well-known URL.

Step 1: The Well-Known Discovery Endpoint

Create a route for GET /.well-known/nodeinfo that returns:

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

Serve this with Content-Type: application/json. The rel value is the canonical schema URI for NodeInfo 2.1 — use it exactly as shown.

Step 2: The NodeInfo Document

Create a route for GET /nodeinfo/2.1 that returns the full NodeInfo payload. Here's an annotated example:

{
  "version": "2.1",
  "software": {
    "name": "myapp",
    "version": "1.0.0",
    "repository": "https://github.com/you/myapp",
    "homepage": "https://myapp.example.com"
  },
  "protocols": ["activitypub"],
  "usage": {
    "users": {
      "total": 42,
      "activeMonth": 15,
      "activeHalfyear": 28
    },
    "localPosts": 300,
    "localComments": 120
  },
  "openRegistrations": false
}

Let's walk through the key fields:

  • software.name — The machine-readable name of your software. Use lowercase, no spaces.
  • protocols — An array of supported federation protocols. Valid values include activitypub, diaspora, ostatus.
  • usage.users.total — Total registered user accounts. This is aggregate data — no personal information is exposed.
  • usage.users.activeMonth — Users who have had activity in the last 30 days.
  • openRegistrations — Boolean indicating whether new sign-ups are accepted.

Implementation Notes by Language

Node.js / Express

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

app.get('/nodeinfo/2.1', async (req, res) => {
  const stats = await getUserStats(); // your own function
  res.json({
    version: '2.1',
    software: { name: 'myapp', version: '1.0.0' },
    protocols: ['activitypub'],
    usage: {
      users: { total: stats.total, activeMonth: stats.monthly },
      localPosts: stats.posts
    },
    openRegistrations: false
  });
});

Python / FastAPI

@app.get("/.well-known/nodeinfo")
def nodeinfo_discovery():
    return {"links": [{"rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",
                        "href": f"{BASE_URL}/nodeinfo/2.1"}]}

@app.get("/nodeinfo/2.1")
def nodeinfo():
    return {
        "version": "2.1",
        "software": {"name": "myapp", "version": "1.0.0"},
        "protocols": ["activitypub"],
        "usage": {"users": {"total": get_user_count()}},
        "openRegistrations": False
    }

Testing Your Implementation

Once deployed, you can verify your NodeInfo implementation using:

  • A direct browser or curl request to /.well-known/nodeinfo
  • Fediverse Observer — it will auto-detect and display your NodeInfo data
  • The official NodeInfo schema validator (validate your JSON against the schema at the rel URI)

NodeInfo is a lightweight but meaningful way to participate in the open federated ecosystem. Implementing it signals that your server is a good citizen of the decentralized web.