NodeInfo is a standardized way for Fediverse servers to expose metadata about themselves, including software information, supported protocols, usage statistics, and more.
Ruby gem implemementation of the NodeInfo protocol for the Fediverse,
providing both client and server functionality.
This gem implements NodeInfo 2.1 as specified in
FEP-f1d5.
- Language agnostic - Works with any Ruby framework or plain scripts
- Client - Discover and fetch
NodeInfofrom any Fediverse server - Server - Serve your own
NodeInfodocuments - Dynamic Stats - Support for static values or dynamic procs for usage statistics
Add this line to your application's Gemfile:
gem'node_info'And then execute:
bundleinstallOr install it yourself as:
geminstallnode_infoFetch NodeInfo from any Fediverse server:
require'node_info'# Create a clientclient=NodeInfo::Client.new# Fetch NodeInfo from a serverinfo=client.fetch'mastodon.social'# Access the informationputsinfo.software.name# => 'mastodon'putsinfo.software.version# => '4.2.0'putsinfo.protocols# => ['activitypub']putsinfo.open_registrations# => true# Access usage statisticsputsinfo.usage.users[:total]# => 1000000putsinfo.usage.users[:activeMonth]# => 50000putsinfo.usage.local_posts# => 5000000# Discover the NodeInfo URLurl=client.discover'mastodon.social'# => 'https://mastodon.social/nodeinfo/2.1'# Fetch the NodeInfo documentinfo=client.fetch_documenturl# Custom timeout (default: 10 seconds)client=NodeInfo::Client.newtimeout: 5# Disable redirect following (default: true)client=NodeInfo::Client.newfollow_redirects: falseServe NodeInfo documents from your application:
require'node_info'# Create a server with configurationserver=NodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version='1.0.0'config.software_repository='https://github.com/xoengineering/example'config.software_homepage='https://example.com'config.protocols=['activitypub']config.services_inbound=['atom1.0']config.services_outbound=['rss2.0','atom1.0']config.open_registrations=trueconfig.metadata={nodeName: 'An example instance',nodeDescription: 'An example place for exemplar people'}end# Generate the well-known response: /.well-known/nodeinfoserver.well_known_json'https://example.com'# => {# "links": [# {# "rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",# "href": "https://example.com/nodeinfo/2.1"# }# ]# }# Generate the NodeInfo document (/nodeinfo/2.1)server.to_json# => Full NodeInfo 2.1 JSON documentserver=NodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version='1.0.0'config.protocols=['activitypub']# Static valuesconfig.usage_users={total: 100,activeMonth: 50,activeHalfyear: 75}config.usage_local_posts=1000config.usage_local_comments=500endFor production applications, you’ll want to compute statistics dynamically:
server=NodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version='1.0.0'config.protocols=['activitypub']# Use procs to compute values dynamicallyconfig.usage_users=->{User.count}config.usage_users_active_month=->{User.active_last_month.count}config.usage_users_active_halfyear=->{User.active_last_six_months.count}config.usage_local_posts=->{Post.local.count}config.usage_local_comments=->{Comment.local.count}end# Stats are computed fresh each timeserver.to_json# Calls all the procs to get current valuesconfig.usage_users={total: ->{User.count},activeMonth: ->{User.active_last_month.count},activeHalfyear: ->{User.active_last_six_months.count}}require'sinatra'require'node_info'# Configure your server (perhaps in a config file or initializer)NODE_INFO_SERVER=NodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version='1.0.0'config.protocols=['activitypub']config.base_url='https://example.com'config.usage_users=->{User.count}end# Well-known endpointget'/.well-known/nodeinfo'docontent_type:jsonNODE_INFO_SERVER.well_known_jsonend# NodeInfo document endpointget'/nodeinfo/2.1'docontent_type:jsonNODE_INFO_SERVER.to_jsonend# config/routes.rbRails.application.routes.drawdoget'/.well-known/nodeinfo',to: 'node_info#well_known'get'/nodeinfo/2.1',to: 'node_info#show'end# app/controllers/node_info_controller.rbclassNodeInfoController < ApplicationControllerdefwell_knownrenderjson: server.well_known(request.base_url)enddefshowrenderjson: server.to_jsonendprivatedefserver@server ||= NodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version=Rails.application.config.versionconfig.protocols=['activitypub']config.open_registrations=Rails.application.config.open_registrationsconfig.usage_users=->{User.count}config.usage_users_active_month=->{User.active_last_month.count}config.usage_local_posts=->{Post.local.count}endendend# config/routes.rbget'/.well-known/nodeinfo',to: 'node_info.well_known'get'/nodeinfo/2.1',to: 'node_info.show'# app/actions/node_info/well_known.rbmoduleExampleAppmoduleActionsmoduleNodeInfoclassWellKnown < ExampleApp::Actiondefhandlerequest,responseserver=build_serverresponse.format=:jsonresponse.body=server.well_known_jsonrequest.base_urlendprivatedefbuild_serverNodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version='1.0.0'config.protocols=['activitypub']endendendendendend| Option | Type | Required | Description |
|---|---|---|---|
protocols | Array | Yes | Supported protocols (e.g., ['activitypub']) |
software_name | String | Yes | Name of your software |
software_version | String | Yes | Version of your software |
software_repository | String | No | URL to source code repository |
software_homepage | String | No | URL to software homepage |
services_inbound | Array | No | Inbound services (e.g., ['atom1.0']) |
services_outbound | Array | No | Outbound services (e.g., ['rss2.0']) |
open_registrations | Boolean | No | Whether registrations are open (default: false) |
usage_users | Hash/Proc | No | User statistics |
usage_users_active_month | Integer/Proc | No | Active users in last month |
usage_users_active_halfyear | Integer/Proc | No | Active users in last 6 months |
usage_local_posts | Integer/Proc | No | Number of local posts |
usage_local_comments | Integer/Proc | No | Number of local comments |
metadata | Hash | No | Custom metadata |
base_url | String | No | Base URL for well-known response |
The gem defines several error classes:
NodeInfo::Error# Base error classNodeInfo::DiscoveryError# Discovery failedNodeInfo::FetchError# Fetching document failedNodeInfo::ParseError# Parsing document failedNodeInfo::ValidationError# Validation failedNodeInfo::HTTPError# HTTP request failedExample error handling:
begininfo=client.fetch'example.com'rescueNodeInfo::DiscoveryError=>eputs"Could not discover NodeInfo: #{e.message}"rescueNodeInfo::FetchError=>eputs"Could not fetch NodeInfo: #{e.message}"rescueNodeInfo::ParseError=>eputs"Could not parse NodeInfo: #{e.message}"rescueNodeInfo::Error=>eputs"NodeInfo error: #{e.message}"endAfter checking out the repo, run bin/setup to install dependencies.
Then, run rake spec to run the tests.
You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install.
bundleexecrspecbundleexecrubocopbundleexecrakeBug reports and pull requests are welcome on GitHub at the https://github.com/xoengineering/node_info repo.
The gem is available as open source under the terms of the MIT License.