diff --git a/disperser/controller/dispatcher.go b/disperser/controller/dispatcher.go
index 31cdffe086..4b46d9aec4 100644
--- a/disperser/controller/dispatcher.go
+++ b/disperser/controller/dispatcher.go
@@ -273,6 +273,23 @@ func (d *Dispatcher) HandleSignatures(ctx context.Context, batchData *batchData,
 			quorumResults[quorumID] = quorumResult.PercentSigned
 		}
 	}
+
+	// Track attestation metrics
+	operatorCount := make(map[core.QuorumID]int)
+	signerCount := make(map[core.QuorumID]int)
+	for quorumID, opState := range batchData.OperatorState.Operators {
+		operatorCount[quorumID] = len(opState)
+		if _, ok := signerCount[quorumID]; !ok {
+			signerCount[quorumID] = 0
+		}
+		for opID := range opState {
+			if _, ok := quorumAttestation.SignerMap[opID]; ok {
+				signerCount[quorumID]++
+			}
+		}
+	}
+	d.metrics.reportAttestation(operatorCount, signerCount, quorumAttestation.QuorumResults)
+
 	if len(nonZeroQuorums) == 0 {
 		err = d.updateBatchStatus(ctx, batchData, quorumResults)
 		if err != nil {
diff --git a/disperser/controller/dispatcher_metrics.go b/disperser/controller/dispatcher_metrics.go
index 8b94b8878b..c63a500b23 100644
--- a/disperser/controller/dispatcher_metrics.go
+++ b/disperser/controller/dispatcher_metrics.go
@@ -1,9 +1,11 @@
 package controller
 
 import (
+	"fmt"
 	"time"
 
 	common "github.com/Layr-Labs/eigenda/common"
+	"github.com/Layr-Labs/eigenda/core"
 	dispv2 "github.com/Layr-Labs/eigenda/disperser/common/v2"
 	"github.com/prometheus/client_golang/prometheus"
 	"github.com/prometheus/client_golang/prometheus/promauto"
@@ -34,12 +36,22 @@ type dispatcherMetrics struct {
 	updateBatchStatusLatency    *prometheus.SummaryVec
 	blobE2EDispersalLatency     *prometheus.SummaryVec
 	completedBlobs              *prometheus.CounterVec
+	attestation                 *prometheus.GaugeVec
 }
 
 // NewDispatcherMetrics sets up metrics for the dispatcher.
 func newDispatcherMetrics(registry *prometheus.Registry) *dispatcherMetrics {
 	objectives := map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}
 
+	attestation := promauto.With(registry).NewGaugeVec(
+		prometheus.GaugeOpts{
+			Namespace: dispatcherNamespace,
+			Name:      "attestation",
+			Help:      "number of signers and non-signers for the batch",
+		},
+		[]string{"type", "quorum"},
+	)
+
 	handleBatchLatency := promauto.With(registry).NewSummaryVec(
 		prometheus.SummaryOpts{
 			Namespace:  dispatcherNamespace,
@@ -270,6 +282,7 @@ func newDispatcherMetrics(registry *prometheus.Registry) *dispatcherMetrics {
 		updateBatchStatusLatency:    updateBatchStatusLatency,
 		blobE2EDispersalLatency:     blobE2EDispersalLatency,
 		completedBlobs:              completedBlobs,
+		attestation:                 attestation,
 	}
 }
 
@@ -371,3 +384,22 @@ func (m *dispatcherMetrics) reportCompletedBlob(size int, status dispv2.BlobStat
 	m.completedBlobs.WithLabelValues("total", "number").Inc()
 	m.completedBlobs.WithLabelValues("total", "size").Add(float64(size))
 }
+
+func (m *dispatcherMetrics) reportAttestation(operatorCount map[core.QuorumID]int, signerCount map[core.QuorumID]int, quorumResults map[core.QuorumID]*core.QuorumResult) {
+	for quorumID, count := range operatorCount {
+		quorumStr := fmt.Sprintf("%d", quorumID)
+		signers, ok := signerCount[quorumID]
+		if !ok {
+			continue
+		}
+		nonSigners := count - signers
+		quorumResult, ok := quorumResults[quorumID]
+		if !ok {
+			continue
+		}
+
+		m.attestation.WithLabelValues("signers", quorumStr).Set(float64(signers))
+		m.attestation.WithLabelValues("non_signers", quorumStr).Set(float64(nonSigners))
+		m.attestation.WithLabelValues("percent_signed", quorumStr).Set(float64(quorumResult.PercentSigned))
+	}
+}