diff --git a/setup.cfg b/setup.cfg
index ebbd1ac295db4e0950f28815949e5900618e59b1..343668b5ab5e883c41f40fc31fd40c1f152ce0c3 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -48,6 +48,7 @@ install_requires =
     tahoe-lafs @ https://github.com/tahoe-lafs/tahoe-lafs/archive/d3c6f58a8ded7db3324ef97c47f5c1921c3d58b7.zip
     treq
     pyutil
+    prometheus-client
 
 [options.extras_require]
 test = coverage; fixtures; testtools; hypothesis
diff --git a/src/_zkapauthorizer/_plugin.py b/src/_zkapauthorizer/_plugin.py
index cf331c6986e88adbb9a9e5349b714fc18eae7f66..88998b03866830c04060ba3aba696ed802e4e4fa 100644
--- a/src/_zkapauthorizer/_plugin.py
+++ b/src/_zkapauthorizer/_plugin.py
@@ -27,6 +27,7 @@ from allmydata.client import _Client
 from allmydata.interfaces import IAnnounceableStorageServer, IFoolscapStoragePlugin
 from allmydata.node import MissingConfigEntry
 from challenge_bypass_ristretto import SigningKey
+from prometheus_client import CollectorRegistry
 from twisted.internet.defer import succeed
 from twisted.logger import Logger
 from twisted.python.filepath import FilePath
@@ -94,8 +95,17 @@ class ZKAPAuthorizer(object):
         """
         return get_redeemer(self.name, node_config, announcement, reactor)
 
-    def get_storage_server(self, configuration, get_anonymous_storage_server):
+    def get_storage_server(
+        self, configuration, get_anonymous_storage_server, reactor=None
+    ):
+        if reactor is None:
+            from twisted.internet import reactor
+        registry = CollectorRegistry()
+        # schedule_writing(registry)
         kwargs = configuration.copy()
+
+        kwargs.pop(u"prometheus-metrics-path", None)
+        kwargs.pop(u"prometheus-metrics-interval", None)
         root_url = kwargs.pop(u"ristretto-issuer-root-url")
         pass_value = int(kwargs.pop(u"pass-value", BYTES_PER_PASS))
         signing_key = load_signing_key(
@@ -110,6 +120,7 @@ class ZKAPAuthorizer(object):
             get_anonymous_storage_server(),
             pass_value=pass_value,
             signing_key=signing_key,
+            registry=registry,
             **kwargs
         )
         return succeed(
diff --git a/src/_zkapauthorizer/_storage_server.py b/src/_zkapauthorizer/_storage_server.py
index e379989c36f4ae1054da88791e8604a9c1fc92f6..4d47ad1e933df4d43488b3a881f460b55e1e6b51 100644
--- a/src/_zkapauthorizer/_storage_server.py
+++ b/src/_zkapauthorizer/_storage_server.py
@@ -171,6 +171,7 @@ class ZKAPAuthorizerStorageServer(Referenceable):
     _original = attr.ib(validator=provides(RIStorageServer))
     _pass_value = pass_value_attribute()
     _signing_key = attr.ib(validator=instance_of(SigningKey))
+    _registry = attr.ib()
     _clock = attr.ib(
         validator=provides(IReactorTime),
         default=attr.Factory(partial(namedAny, "twisted.internet.reactor")),
diff --git a/src/_zkapauthorizer/tests/test_plugin.py b/src/_zkapauthorizer/tests/test_plugin.py
index 78959a5d37712fd2d57f9eb5ebff7cda75f514bf..306007536e7c83dff8d7879e7f21b82860f24c56 100644
--- a/src/_zkapauthorizer/tests/test_plugin.py
+++ b/src/_zkapauthorizer/tests/test_plugin.py
@@ -19,6 +19,7 @@ Tests for the Tahoe-LAFS plugin.
 from __future__ import absolute_import
 
 import tempfile
+from datetime import timedelta
 from functools import partial
 from os import makedirs
 
@@ -36,7 +37,9 @@ from foolscap.broker import Broker
 from foolscap.ipb import IReferenceable, IRemotelyCallable
 from foolscap.referenceable import LocalReferenceable
 from hypothesis import given, settings
-from hypothesis.strategies import datetimes, just, sampled_from
+from hypothesis.strategies import datetimes, just, sampled_from, timedeltas
+from isodate import duration_isoformat
+from prometheus_client import CollectorRegistry, Gauge
 from StringIO import StringIO
 from testtools import TestCase
 from testtools.content import text_content
@@ -47,12 +50,14 @@ from testtools.matchers import (
     Contains,
     ContainsDict,
     Equals,
+    FileContains,
     HasLength,
     IsInstance,
     MatchesAll,
     MatchesStructure,
 )
 from testtools.twistedsupport import succeeded
+from testtools.twistedsupport._deferred import extract_result
 from twisted.internet.task import Clock
 from twisted.plugin import getPlugins
 from twisted.python.filepath import FilePath
@@ -74,6 +79,7 @@ from .matchers import Provides, raises
 from .strategies import (
     announcements,
     client_dummyredeemer_configurations,
+    clocks,
     dummy_ristretto_keys,
     lease_cancel_secrets,
     lease_renew_secrets,
@@ -262,6 +268,33 @@ class ServerPluginTests(TestCase):
             ),
         )
 
+    @given(timedeltas(min_value=timedelta(seconds=1)), clocks())
+    def test_metrics_written(self, metrics_interval, clock):
+        """
+        When the configuration tells us where to put a metrics .prom file
+        and an interval how often to do so, test that metrics are actually
+        written there after the configured interval.
+        """
+        metrics_path = self.useFixture(TempDir()).join(u"metrics")
+        configuration = {
+            u"prometheus-metrics-path": metrics_path,
+            u"prometheus-metrics-interval": duration_isoformat(metrics_interval),
+            u"ristretto-issuer-root-url": "foo",
+            u"ristretto-signing-key-path": SIGNING_KEY_PATH.path,
+        }
+        announceable = extract_result(
+            storage_server.get_storage_server(
+                configuration,
+                get_anonymous_storage_server,
+                reactor=clock,
+            )
+        )
+        registry = announceable.storage_server._registry
+        Gauge("foo", "bar", registry=registry).set(1)
+
+        clock.advance(metrics_interval.total_seconds())
+        self.assertThat(metrics_path, FileContains("foo 1"))
+
 
 tahoe_configs_with_dummy_redeemer = tahoe_configs(client_dummyredeemer_configurations())