Privacy Health Checks: Beyond Database Connectivity
Privacy compliance isn’t something you achieve once and forget. It’s a continuous operational discipline—monitoring personal data lifecycle, detecting consent expiration, validating retention policy execution, and identifying anomalous access patterns before they become regulatory violations.
I’ve seen teams with meticulously documented privacy policies fail audits because nobody could demonstrate that those policies actually executed. The retention schedule said “delete after 24 months.” The database had records from 2019. The deletion job? It had been failing silently for eight months. The logs existed, buried somewhere in a storage account nobody monitored.
ISO/IEC 27701 makes this explicit. The standard doesn’t just demand policies on paper—it requires operational verification that those policies actually execute as intended. Control 7.4.9 addresses temporary files, 8.4.3 covers data retention, 7.2.1 handles consent. All of them share one requirement: continuous monitoring.
For .NET teams, this translates into a specific engineering challenge. You already have health checks for infrastructure—database connectivity, API responsiveness, cache status. The same pattern applies to privacy compliance. Same IHealthCheck interface, different questions.
The Privacy Monitoring Gap
Privacy health requires monitoring dimensions that infrastructure checks never touch:
- Consent lifecycle: What percentage of active users have expired consents? When does the next bulk expiration hit?
- Data retention: Did the nightly deletion job actually run? How much data exceeds retention periods right now?
- Access patterns: Is someone bulk-exporting customer records? Are query volumes spiking unexpectedly?
- Temporary storage: How many unprocessed export files are accumulating? For how long?
Without active monitoring, retention policies remain aspirational documents. Consent expirations go unnoticed until user complaints escalate. Access anomalies blend into routine operational noise—until the audit.
The Typical Monitoring Blind Spot
Most .NET applications monitor infrastructure health religiously but ignore privacy compliance entirely:
// What your health checks probably look like today
builder.Services.AddHealthChecks()
.AddDbContextCheck<ApplicationDbContext>() // ✓ Database up?
.AddUrlGroup(new Uri("https://api.stripe.com")) // ✓ Payment API reachable?
.AddRedis(redisConnection); // ✓ Cache responding?
// What's missing:
// - How many users have expired consents? (Nobody knows)
// - Did the retention policy actually run last night? (Hopefully)
// - Is someone bulk-exporting customer data right now? (Shrug)
When a data protection authority audits this system, they find retention policies documented but no evidence of continuous monitoring. They see consent records but no expiration tracking. The gap isn’t missing privacy controls—it’s missing visibility into whether those controls actually function.
Privacy Health Checks: The Core Pattern
A privacy health check follows the same IHealthCheck interface you already know—but queries privacy-relevant data instead of infrastructure status:
public class ConsentExpirationHealthCheck : IHealthCheck
{
private readonly ApplicationDbContext _context;
private const double WarningThreshold = 0.15; // 15% expired = warning
private const double CriticalThreshold = 0.30; // 30% expired = critical
public ConsentExpirationHealthCheck(ApplicationDbContext context)
=> _context = context;
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
var now = DateTime.UtcNow;
var totalUsers = await _context.Users
.CountAsync(u => u.IsActive, cancellationToken);
var expiredConsents = await _context.UserConsents
.CountAsync(c => c.ExpirationDate < now && c.User.IsActive, cancellationToken);
var expiredRatio = totalUsers > 0 ? (double)expiredConsents / totalUsers : 0;
return expiredRatio switch
{
>= CriticalThreshold => HealthCheckResult.Unhealthy(
$"{expiredRatio:P0} of users have expired consents"),
>= WarningThreshold => HealthCheckResult.Degraded(
$"{expiredRatio:P0} of users have expired consents"),
_ => HealthCheckResult.Healthy(
$"Consent status normal: {expiredConsents} expired of {totalUsers}")
};
}
}
That’s it. Two queries, one ratio, three possible outcomes. The pattern applies to any privacy metric.
Choosing Your Thresholds
The 15% and 30% thresholds in the example aren’t magic numbers—they’re starting points. Your thresholds depend on your business context and risk tolerance.
For a B2B SaaS platform with annual contracts, 15% expired consents might indicate a renewal cycle issue rather than a compliance emergency. For a healthcare application processing patient data daily, even 5% could warrant immediate attention.
Start conservative. It’s easier to relax thresholds after you understand your baseline than to explain to an auditor why you ignored a 25% expiration rate for six months. The first week after deployment, you’ll learn what “normal” looks like for your system—then calibrate accordingly.
The retention policy check follows the same logic:
public class RetentionPolicyHealthCheck : IHealthCheck
{
private readonly ApplicationDbContext _context;
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context, CancellationToken cancellationToken = default)
{
var lastRun = await _context.RetentionPolicyExecutions
.Where(e => e.Status == ExecutionStatus.Success)
.MaxAsync(e => (DateTime?)e.ExecutedAt, cancellationToken);
var hoursSinceLastRun = lastRun.HasValue
? (DateTime.UtcNow - lastRun.Value).TotalHours
: double.MaxValue;
return hoursSinceLastRun switch
{
> 48 => HealthCheckResult.Unhealthy(
$"Retention policy hasn't run in {hoursSinceLastRun:F0} hours"),
> 24 => HealthCheckResult.Degraded(
$"Retention policy last ran {hoursSinceLastRun:F0} hours ago"),
_ => HealthCheckResult.Healthy(
$"Retention policy ran {hoursSinceLastRun:F1} hours ago")
};
}
}
Registration: Three Lines of Code
builder.Services.AddHealthChecks()
.AddCheck<ConsentExpirationHealthCheck>("consent_expiration",
tags: ["privacy"])
.AddCheck<RetentionPolicyHealthCheck>("retention_policy",
tags: ["privacy"]);
// Separate endpoint for privacy checks
app.MapHealthChecks("/health/privacy", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("privacy")
});
Now /health/privacy tells you what /health never could: whether your privacy controls actually function.
Exporting to Application Insights
Health checks run on demand. For continuous monitoring, push metrics to Application Insights:
public class ConsentExpirationHealthCheck : IHealthCheck
{
private readonly ApplicationDbContext _context;
private readonly TelemetryClient _telemetry;
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context, CancellationToken cancellationToken = default)
{
// ... same queries as before ...
// Push to Application Insights for trending
_telemetry.TrackMetric("Privacy.Consent.ExpiredPercentage", expiredRatio * 100);
_telemetry.TrackMetric("Privacy.Consent.ExpiredCount", expiredConsents);
// ... return health status ...
}
}
This enables dashboards and alerts that fire before thresholds breach:
customMetrics
| where name == "Privacy.Consent.ExpiredPercentage"
| summarize AvgExpired = avg(value) by bin(timestamp, 1h)
| render timechart
The beauty of this approach: you’re not learning anything new. Same IHealthCheck interface you’ve used for years, same threshold-based results, same registration pattern. The only difference is what you’re querying—privacy metrics instead of ping responses.
What to Monitor
The pattern extends to any privacy-relevant metric. Here’s what matters for ISO/IEC 27701 compliance:
| Health Check | What It Catches | ISO 27701 Control |
|---|---|---|
| Consent expiration | Users processed without valid consent | 7.2.1 (Consent) |
| Retention policy execution | Silent failures in data deletion jobs | 8.4.3 (Retention) |
| Temporary file accumulation | Unprocessed exports, staging data | 7.4.9 (Temporary files) |
| Bulk export detection | Unusual data access patterns | 8.2.2 (Purpose limitation) |
Pick the metrics that matter for your regulatory context. A healthcare application needs different checks than an e-commerce platform.
A Real Scenario: The 3 AM Alert That Wasn’t
Consider what happens when your retention policy fails at 3 AM. Without privacy health checks, you discover the problem three weeks later during a routine database review—or worse, during an audit. The data that should have been deleted is still there, accumulating liability.
With a RetentionPolicyHealthCheck running every five minutes, you know within the hour. The health endpoint returns Unhealthy, your monitoring system fires an alert, and someone investigates before breakfast. The fix might be trivial—a database connection timeout, a permission change that broke the service account. But you caught it in hours, not weeks.
That’s the difference between “we have a retention policy” and “we can prove our retention policy works.”
The Audit Conversation Changes
Without privacy health checks:
“How do you verify your retention policies execute?”
“We have logs… somewhere. Let me check with the DBA.”
With privacy health checks:
“How do you verify your retention policies execute?”
“Here’s the Application Insights dashboard showing execution history, and here are the alerts that fire when execution fails. Last incident was three months ago—resolved in 47 minutes.”
The implementation cost—two health check classes and a few lines of registration—delivers continuous compliance verification that turns audit questions into dashboard demos.
Start Here
You don’t need to implement all of this at once. Add one privacy health check this week—pick whatever metric keeps you up at night:
- Consent expiration if GDPR compliance is your concern
- Retention policy execution if your deletion jobs are a black box
- Data volume trends if you’re not sure what’s accumulating where
One health check. One metric. One new endpoint. That’s enough to answer questions your infrastructure health checks never could—and enough to change the tone of your next compliance conversation.
Privacy compliance is an operational discipline. Your monitoring should reflect that.

Comments