diff --git a/api/funkwhale_api/instance/dynamic_preferences_registry.py b/api/funkwhale_api/instance/dynamic_preferences_registry.py
index 1d11a2988ca1d76da7b61d8ef8657ac6cdee74df..03555b0be57bde18f4fe13ba1b62d852ffd93ae4 100644
--- a/api/funkwhale_api/instance/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/instance/dynamic_preferences_registry.py
@@ -68,3 +68,31 @@ class RavenEnabled(types.BooleanPreference):
         'Wether error reporting to a Sentry instance using raven is enabled'
         ' for front-end errors'
     )
+
+
+@global_preferences_registry.register
+class InstanceNodeinfoEnabled(types.BooleanPreference):
+    show_in_api = False
+    section = instance
+    name = 'nodeinfo_enabled'
+    default = True
+    verbose_name = 'Enable nodeinfo endpoint'
+    help_text = (
+        'This endpoint is needed for your about page to work.'
+        'It\'s also helpful for the various monitoring '
+        'tools that map and analyzize the fediverse, '
+        'but you can disable it completely if needed.'
+    )
+
+
+@global_preferences_registry.register
+class InstanceNodeinfoStatsEnabled(types.BooleanPreference):
+    show_in_api = False
+    section = instance
+    name = 'nodeinfo_stats_enabled'
+    default = True
+    verbose_name = 'Enable usage and library stats in nodeinfo endpoint'
+    help_text = (
+        'Disable this f you don\'t want to share usage and library statistics'
+        'in the nodeinfo endpoint but don\'t want to disable it completely.'
+    )
diff --git a/api/funkwhale_api/instance/nodeinfo.py b/api/funkwhale_api/instance/nodeinfo.py
new file mode 100644
index 0000000000000000000000000000000000000000..22d1a88928770c131714a2bb97c26ec7cb9a8b15
--- /dev/null
+++ b/api/funkwhale_api/instance/nodeinfo.py
@@ -0,0 +1,74 @@
+import memoize.djangocache
+
+import funkwhale_api
+from funkwhale_api.common import preferences
+
+from . import stats
+
+
+store = memoize.djangocache.Cache('default')
+memo = memoize.Memoizer(store, namespace='instance:stats')
+
+
+def get():
+    share_stats = preferences.get('instance__nodeinfo_stats_enabled')
+    data = {
+        'version': '2.0',
+        'software': {
+            'name': 'funkwhale',
+            'version': funkwhale_api.__version__
+        },
+        'protocols': ['activitypub'],
+        'services': {
+            'inbound': [],
+            'outbound': []
+        },
+        'openRegistrations': preferences.get('users__registration_enabled'),
+        'usage': {
+            'users': {
+                'total': 0,
+            },
+            'localPosts': 0,
+            'localComments': 0,
+        },
+        'metadata': {
+            'shortDescription': preferences.get('instance__short_description'),
+            'longDescription': preferences.get('instance__long_description'),
+            'name': preferences.get('instance__name'),
+            'library': {
+                'federationEnabled': preferences.get('federation__enabled'),
+                'federationNeedsApproval': preferences.get('federation__music_needs_approval'),
+            },
+        }
+    }
+    if share_stats:
+        getter = memo(
+            lambda: stats.get(),
+            max_age=600
+        )
+        statistics = getter()
+        data['usage']['users']['total'] = statistics['users']
+        data['metadata']['library']['tracks'] = {
+            'total': statistics['tracks'],
+        }
+        data['metadata']['library']['artists'] = {
+            'total': statistics['artists'],
+        }
+        data['metadata']['library']['albums'] = {
+            'total': statistics['albums'],
+        }
+        data['metadata']['library']['music'] = {
+            'hours': statistics['music_duration']
+        }
+
+        data['metadata']['usage'] = {
+            'favorites': {
+                'tracks': {
+                    'total': statistics['track_favorites'],
+                }
+            },
+            'listenings': {
+                'total': statistics['listenings']
+            }
+        }
+    return data
diff --git a/api/funkwhale_api/instance/urls.py b/api/funkwhale_api/instance/urls.py
index af23e7e08433b97c6c10f07e1b929892e5dbe32c..e66fdf88d70cc1c16dba01552e9ff88bde1d22d3 100644
--- a/api/funkwhale_api/instance/urls.py
+++ b/api/funkwhale_api/instance/urls.py
@@ -1,11 +1,9 @@
 from django.conf.urls import url
-from django.views.decorators.cache import cache_page
 
 from . import views
 
 
 urlpatterns = [
+    url(r'^nodeinfo/$', views.NodeInfo.as_view(), name='nodeinfo'),
     url(r'^settings/$', views.InstanceSettings.as_view(), name='settings'),
-    url(r'^stats/$',
-        cache_page(60 * 5)(views.InstanceStats.as_view()), name='stats'),
 ]
diff --git a/api/funkwhale_api/instance/views.py b/api/funkwhale_api/instance/views.py
index 7f8f393c964e24bfc7a5ee29bf6be2e30f337188..b40721c9c76da86aa18cfde3e00231b17b73ed47 100644
--- a/api/funkwhale_api/instance/views.py
+++ b/api/funkwhale_api/instance/views.py
@@ -4,6 +4,9 @@ from rest_framework.response import Response
 from dynamic_preferences.api import serializers
 from dynamic_preferences.registries import global_preferences_registry
 
+from funkwhale_api.common import preferences
+
+from . import nodeinfo
 from . import stats
 
 
@@ -27,10 +30,12 @@ class InstanceSettings(views.APIView):
         return Response(data, status=200)
 
 
-class InstanceStats(views.APIView):
+class NodeInfo(views.APIView):
     permission_classes = []
     authentication_classes = []
 
     def get(self, request, *args, **kwargs):
-        data = stats.get()
+        if not preferences.get('instance__nodeinfo_enabled'):
+            return Response(status=404)
+        data = nodeinfo.get()
         return Response(data, status=200)
diff --git a/api/tests/instance/test_nodeinfo.py b/api/tests/instance/test_nodeinfo.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f5ca920c433352a6a947337815f7f1ccfdd7728
--- /dev/null
+++ b/api/tests/instance/test_nodeinfo.py
@@ -0,0 +1,107 @@
+from django.urls import reverse
+
+import funkwhale_api
+
+from funkwhale_api.instance import nodeinfo
+
+
+def test_nodeinfo_dump(preferences, mocker):
+    preferences['instance__nodeinfo_stats_enabled'] = True
+    stats = {
+        'users': 1,
+        'tracks': 2,
+        'albums': 3,
+        'artists': 4,
+        'track_favorites': 5,
+        'music_duration': 6,
+        'listenings': 7,
+    }
+    mocker.patch('funkwhale_api.instance.stats.get', return_value=stats)
+
+    expected = {
+        'version': '2.0',
+        'software': {
+            'name': 'funkwhale',
+            'version': funkwhale_api.__version__
+        },
+        'protocols': ['activitypub'],
+        'services': {
+            'inbound': [],
+            'outbound': []
+        },
+        'openRegistrations': preferences['users__registration_enabled'],
+        'usage': {
+            'users': {
+                'total': stats['users'],
+            },
+            'localPosts': 0,
+            'localComments': 0,
+        },
+        'metadata': {
+            'shortDescription': preferences['instance__short_description'],
+            'longDescription': preferences['instance__long_description'],
+            'name': preferences['instance__name'],
+            'library': {
+                'federationEnabled': preferences['federation__enabled'],
+                'federationNeedsApproval': preferences['federation__music_needs_approval'],
+                'tracks': {
+                    'total': stats['tracks'],
+                },
+                'artists': {
+                    'total': stats['artists'],
+                },
+                'albums': {
+                    'total': stats['albums'],
+                },
+                'music': {
+                    'hours': stats['music_duration']
+                },
+            },
+            'usage': {
+                'favorites': {
+                    'tracks': {
+                        'total': stats['track_favorites'],
+                    }
+                },
+                'listenings': {
+                    'total': stats['listenings']
+                }
+            }
+        }
+    }
+    assert nodeinfo.get() == expected
+
+
+def test_nodeinfo_dump_stats_disabled(preferences, mocker):
+    preferences['instance__nodeinfo_stats_enabled'] = False
+
+    expected = {
+        'version': '2.0',
+        'software': {
+            'name': 'funkwhale',
+            'version': funkwhale_api.__version__
+        },
+        'protocols': ['activitypub'],
+        'services': {
+            'inbound': [],
+            'outbound': []
+        },
+        'openRegistrations': preferences['users__registration_enabled'],
+        'usage': {
+            'users': {
+                'total': 0,
+            },
+            'localPosts': 0,
+            'localComments': 0,
+        },
+        'metadata': {
+            'shortDescription': preferences['instance__short_description'],
+            'longDescription': preferences['instance__long_description'],
+            'name': preferences['instance__name'],
+            'library': {
+                'federationEnabled': preferences['federation__enabled'],
+                'federationNeedsApproval': preferences['federation__music_needs_approval'],
+            },
+        }
+    }
+    assert nodeinfo.get() == expected
diff --git a/api/tests/instance/test_stats.py b/api/tests/instance/test_stats.py
index 6eaad76f7f9d8292211965a462f473c8bb41745a..6063e9300512819a9cc3e6d6bebcc477af9a59d7 100644
--- a/api/tests/instance/test_stats.py
+++ b/api/tests/instance/test_stats.py
@@ -3,16 +3,6 @@ from django.urls import reverse
 from funkwhale_api.instance import stats
 
 
-def test_can_get_stats_via_api(db, api_client, mocker):
-    stats = {
-        'foo': 'bar'
-    }
-    mocker.patch('funkwhale_api.instance.stats.get', return_value=stats)
-    url = reverse('api:v1:instance:stats')
-    response = api_client.get(url)
-    assert response.data == stats
-
-
 def test_get_users(mocker):
     mocker.patch(
         'funkwhale_api.users.models.User.objects.count', return_value=42)
diff --git a/api/tests/instance/test_views.py b/api/tests/instance/test_views.py
new file mode 100644
index 0000000000000000000000000000000000000000..c67688d537c76c7b16dc21f02b8df1e0cd838a5a
--- /dev/null
+++ b/api/tests/instance/test_views.py
@@ -0,0 +1,22 @@
+from django.urls import reverse
+
+
+def test_nodeinfo_endpoint(db, api_client, mocker):
+    payload = {
+        'test': 'test'
+    }
+    mocked_nodeinfo = mocker.patch(
+        'funkwhale_api.instance.nodeinfo.get', return_value=payload)
+    url = reverse('api:v1:instance:nodeinfo')
+    response = api_client.get(url)
+
+    assert response.status_code == 200
+    assert response.data == payload
+
+
+def test_nodeinfo_endpoint_disabled(db, api_client, preferences):
+    preferences['instance__nodeinfo_enabled'] = False
+    url = reverse('api:v1:instance:nodeinfo')
+    response = api_client.get(url)
+
+    assert response.status_code == 404