diff --git a/.gitignore b/.gitignore
index bc8e2760177de08e7cd585a29067c5b7e3fa3a2e..b0989bf82f8fcd3f68d68dc36cac1302a9bcffcc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
 venv/
 config.ini
 __pycache__/
+state/
diff --git a/exporter.py b/exporter.py
index c1dec1a2d4e950c5f9ff84d0b5a3ae844756fea6..9c97c0e77d6d86f0b127cbcdb3d2390ddf49caa1 100755
--- a/exporter.py
+++ b/exporter.py
@@ -1,6 +1,6 @@
 #! /usr/bin/env python
 import requests
-from prometheus_client import start_http_server, Gauge
+from prometheus_client import start_http_server, Counter, Gauge
 from time import sleep
 import argparse
 
@@ -9,9 +9,57 @@ metric_channel_types = Gauge('matrix_channel_types_total', 'Channels per type',
 metric_channel_version = Gauge('matrix_channel_version_total', 'Channels per version', ['version'])
 metric_channel_state_events = Gauge('matrix_channel_state_events_total', 'State events per room',
                                     ['room_id', 'canonical_alias', 'name'])
+metric_channel_messages = Counter('matrix_channel_messages_total', 'Messages per channel', ['room_id', 'canonical_alias', 'name', 'type'])
 
 
 def fetch_metrics(synapse_url, access_token):
+    auth = {
+        'Authorization': f"Bearer {access_token}"
+    }
+
+    rooms = requests.get(f"{synapse_url}/_synapse/admin/v1/rooms", headers=auth).json()['rooms']
+
+    update_room_metrics(rooms)
+
+    for room in rooms:
+        statefile = f'state/{room['room_id']}.end'
+        url = f"{synapse_url}/_synapse/admin/v1/rooms/{room['room_id']}/messages"
+        messages = []
+
+        end = None
+        try:
+            with open(statefile, 'r') as file:
+                end = file.read()
+        except OSError:
+            print(f"No state file for room {room['room_id']} found. Fetching messages could take a while.")
+
+        while True:
+            params = {}
+            if end is not None:
+                params['from'] = end
+
+            result = requests.get(url, params=params, headers=auth).json()
+
+            if 'chunk' in result and len(result['chunk']):
+                messages.extend(result['chunk'])
+
+            if 'end' in result:
+                end = result['end']
+            else:
+                break
+
+        for message in messages:
+            metric_channel_messages.labels(
+                room_id=room['room_id'],
+                canonical_alias=room['canonical_alias'] if room['canonical_alias'] else '',
+                name=room['name'] if room['name'] else '',
+                type=message['type']).inc()
+
+        with open(statefile, 'w') as file:
+            file.write(end)
+
+
+def update_room_metrics(rooms):
     room_type_count = {
         'space': 0,
         'public': 0,
@@ -20,12 +68,6 @@ def fetch_metrics(synapse_url, access_token):
     }
     room_version_count = {}
 
-    auth = {
-        'Authorization': f"Bearer {access_token}"
-    }
-
-    rooms = requests.get(f"{synapse_url}/_synapse/admin/v1/rooms", headers=auth).json()['rooms']
-
     for room in rooms:
         if room['version'] not in room_version_count:
             room_version_count[room['version']] = 0