use case

Compliance Medium · SaaS, Healthcare, Fintech, E-commerce

GDPR-Compliant Logging

Implement privacy-first logging that meets GDPR requirements. Data minimization, retention policies, and right to erasure.

  • Data minimization
  • EU data residency
  • Right to erasure
  • Audit trails

GDPR compliance isn’t just about consent forms - it extends to how you collect, store, and process log data. This guide shows you how to implement privacy-first logging with LogTide.

The Problem with Traditional Logging

Most logging solutions treat logs as technical data without privacy considerations:

// ❌ BAD: Logging personal data without consideration
logger.info('User logged in', {
  email: '[email protected]',
  ip: '192.168.1.100',
  name: 'John Doe',
  sessionId: 'sess_abc123',
  userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...',
  location: { lat: 51.5074, lng: -0.1278 },
});
Your ApplicationLog with pseudonymizationLogTideEU infrastructureRetention policies appliedAutomatic deletion

Implementation: Step by Step

1. Data Minimization Strategy

First, audit what you’re currently logging and categorize:

Data TypeGDPR CategoryAction
User IDPersonal DataPseudonymize
EmailPersonal DataHash or omit
IP AddressPersonal DataTruncate or hash
Session IDPotentially PersonalShort retention
Error messagesTechnicalKeep (no PII)
Request pathsTechnicalKeep (no PII)

2. Pseudonymization Helpers

Create utility functions for consistent data handling:

import crypto from 'crypto';

// Hash personal identifiers (one-way)
export function hashPII(value: string, salt: string): string {
  return crypto
    .createHmac('sha256', salt)
    .update(value)
    .digest('hex')
    .substring(0, 16);
}

// Truncate IP addresses (GDPR-friendly)
export function truncateIP(ip: string): string {
  if (ip.includes(':')) {
    // IPv6: keep first 4 segments
    return ip.split(':').slice(0, 4).join(':') + '::';
  }
  // IPv4: zero last octet
  return ip.split('.').slice(0, 3).join('.') + '.0';
}

// Mask email (for debugging without full exposure)
export function maskEmail(email: string): string {
  const [local, domain] = email.split('@');
  if (!domain) return '***';
  return `${local.charAt(0)}***@${domain}`;
}

// Generate pseudonymous user ID
export function pseudonymizeUserId(userId: string, salt: string): string {
  return `user_${hashPII(userId, salt)}`;
}

3. Privacy-First Logger Wrapper

Create a logging wrapper that enforces privacy rules:

import { LogTideClient } from '@logtide/sdk-node';

const PII_SALT = process.env.PII_HASH_SALT!;

class PrivacyLogger {
  private client: LogTideClient;

  constructor() {
    this.client = new LogTideClient({
      apiUrl: process.env.LOGTIDE_API_URL!,
      apiKey: process.env.LOGTIDE_API_KEY!,
      globalMetadata: {
        environment: process.env.NODE_ENV,
        dataClassification: 'gdpr-compliant',
      },
    });
  }

  // Safe logging method that sanitizes data
  log(level: string, message: string, data: Record<string, unknown> = {}) {
    const sanitized = this.sanitize(data);
    this.client[level]('app', message, sanitized);
  }

  private sanitize(data: Record<string, unknown>): Record<string, unknown> {
    const result: Record<string, unknown> = {};

    for (const [key, value] of Object.entries(data)) {
      // Handle known PII fields
      if (key === 'email' && typeof value === 'string') {
        result.email_hash = hashPII(value, PII_SALT);
        continue;
      }

      if (key === 'ip' && typeof value === 'string') {
        result.ip_truncated = truncateIP(value);
        continue;
      }

      if (key === 'userId' && typeof value === 'string') {
        result.user_pseudo = pseudonymizeUserId(value, PII_SALT);
        continue;
      }

      // Block known sensitive fields
      if (['password', 'ssn', 'creditCard', 'token'].includes(key)) {
        continue; // Don't log at all
      }

      result[key] = value;
    }

    return result;
  }

  info(message: string, data?: Record<string, unknown>) {
    this.log('info', message, data);
  }

  warn(message: string, data?: Record<string, unknown>) {
    this.log('warn', message, data);
  }

  error(message: string, data?: Record<string, unknown>) {
    this.log('error', message, data);
  }
}

export const logger = new PrivacyLogger();

4. Usage in Your Application

import { logger } from './privacy-logger';

// ✅ GOOD: Privacy-compliant logging
app.post('/login', async (req, res) => {
  const { email, password } = req.body;

  try {
    const user = await authenticate(email, password);

    // Personal data is automatically sanitized
    logger.info('User login successful', {
      email,                    // → email_hash: "a1b2c3..."
      ip: req.ip,              // → ip_truncated: "192.168.1.0"
      userId: user.id,         // → user_pseudo: "user_d4e5f6..."
      userAgent: req.headers['user-agent'],
      loginMethod: 'password',
    });

    res.json({ success: true });
  } catch (error) {
    logger.warn('Login failed', {
      email,                    // → email_hash (can correlate attempts)
      ip: req.ip,
      reason: error.code,      // Technical, not personal
    });

    res.status(401).json({ error: 'Invalid credentials' });
  }
});

5. Retention Policies

LogTide retention is set per organization, from 1 to 365 days, and expired logs are deleted automatically. There are no per-service or per-level retention rules, so use separate organizations if two log types need different periods. The audit log of LogTide itself has its own retention (1 to 3650 days, or keep forever). Example periods:

Log TypeRetentionJustification
Access logs90 daysSecurity monitoring
Error logs30 daysDebugging
Debug logs7 daysDevelopment only

Where to set it:

  1. Self-hosted: retention is configured by your system administrator in the admin panel (organization page)
  2. LogTide Cloud: retention follows your plan (7, 30 or 90 days)
  3. Anything that must be kept longer than 365 days (for example tax records) belongs in a system designed for that, not in the log store

6. Right to Erasure (Article 17)

When a user requests deletion, you need to remove their log data:

import { LogTideClient } from '@logtide/sdk-node';

async function handleDeletionRequest(userId: string) {
  // 1. Delete from your database
  await db.users.delete({ where: { id: userId } });

  // 2. The pseudonymized logs don't directly identify the user
  // LogTide has no per-record delete: they are removed when retention expires

  // 3. Log the deletion (audit trail)
  logger.info('GDPR deletion request processed', {
    user_pseudo: pseudonymizeUserId(userId, PII_SALT),
    requestedAt: new Date().toISOString(),
    processedBy: 'system',
  });

  // 4. Return confirmation
  return {
    deleted: true,
    retentionNote: 'Pseudonymized logs expire with the 90-day retention period',
  };
}

Real-World Example: E-commerce Platform

Let’s say you’re building an e-commerce platform in the EU.

Requirements:

  • Log user activity for fraud detection
  • Meet GDPR data minimization
  • Support right to erasure
  • Keep order records for 7 years (tax compliance) in your database, since log retention is capped at 365 days

Implementation:

// Order logging (the tax record itself lives in your database)
logger.info('Order placed', {
  orderId: order.id,           // Business identifier
  amount: order.total,         // Financial data
  currency: order.currency,
  items: order.items.length,   // Aggregate, not details
  // User data pseudonymized automatically
  userId: order.userId,
  email: order.email,
  ip: req.ip,
});

// Fraud detection
logger.info('Payment attempt', {
  orderId: order.id,
  paymentMethod: 'card',       // Type only, no card numbers
  succeeded: true,
  // Pseudonymized for correlation
  userId: order.userId,
  ip: req.ip,
  fingerprint: deviceFingerprint,
});

// Marketing events (requires consent)
if (user.marketingConsent) {
  logger.info('Product viewed', {
    productId: product.id,
    category: product.category,
    userId: user.id,  // Pseudonymized, consent recorded
  });
}

GDPR Compliance Checklist

Use this for your audit:

  • Data Minimization

    • Audit all log statements for personal data
    • Remove unnecessary PII collection
    • Implement pseudonymization for required PII
  • Storage Location

    • Confirm logs stored in EU (or adequate country)
    • Document data transfer mechanisms if using cloud
  • Retention

    • Define retention periods for each log type
    • Configure automatic deletion in LogTide
    • Document justification for retention periods
  • Access Control

    • Implement role-based access to logs
    • Enable audit logging for log access
    • Regular access review process
  • Right to Erasure

    • Process for handling deletion requests
    • Mechanism to keep user identifiers out of logs (pseudonymization, PII masking), since logs are removed by retention expiry
    • Document what can/cannot be deleted (legal holds)
  • Documentation

    • Update privacy policy with logging practices
    • Document lawful basis for log processing
    • Maintain records of processing activities

Cost Comparison

Traditional SaaS Logging (Datadog, Splunk):

  • Data leaves your infrastructure
  • Limited control over data location
  • Retention often unlimited or expensive to manage
  • Per-GB pricing encourages data reduction

LogTide self-hosted:

  • Data stays in your infrastructure
  • Full control over data location
  • Configurable retention with automatic deletion
  • Fixed infrastructure cost

Compliance benefit: Easier GDPR compliance with self-hosted solution.

Common Pitfalls

1. “We anonymize everything”

True anonymization is irreversible. If you can link logs back to users (even with internal keys), it’s pseudonymization, not anonymization. GDPR still applies.

Correct approach: Use pseudonymization (one-way hashing) and document it as such.

2. “Logs are just technical data”

IP addresses, user agents, and session IDs can all be personal data under GDPR if they can identify a person.

Correct approach: Treat all user-related data as potentially personal.

3. “We’ll delete logs when requested”

If you can’t efficiently find a user’s logs or let them expire in time, you can’t fulfill deletion requests.

Correct approach: Use consistent user identifiers (pseudonymized) that you can search for, and a retention period short enough that logs expire in time.

This guide provides technical implementation, not legal advice. GDPR interpretation varies by country and case. Consult with a data protection officer or legal counsel for your specific situation.

Resources


Need help with GDPR-compliant logging?

Last updated: Nov 14, 2026 Edit this page on GitHub

Frequently Asked Questions

Is LogTide GDPR-compliant?

LogTide is designed with privacy-first principles including built-in PII masking rules (email, credit card, SSN, IP address, API key and sensitive field names), configurable per-organization retention with automatic deletion, and a self-hosted deployment model that lets you keep all log data within your own EU infrastructure. This makes it significantly easier to meet GDPR obligations than using SaaS logging platforms where data leaves your control.

How does LogTide handle EU data residency for logs?

Because LogTide is self-hosted, you choose where it runs. Deploying on EU infrastructure means log data never leaves your jurisdiction, removing the need for Standard Contractual Clauses or other data-transfer mechanisms required when sending logs to non-EU SaaS providers.

How does LogTide support the GDPR right to erasure?

LogTide recommends pseudonymizing personal identifiers such as user IDs and email addresses with one-way HMAC hashes at log time. LogTide has no per-record log deletion API: logs are removed when the organization retention period expires, so keep the retention window short enough for your erasure obligations and keep raw identifiers out of logs in the first place. The erasure request itself can be logged as an audit trail event.

How do I avoid logging personal data by accident with LogTide?

The guide provides a PrivacyLogger wrapper that automatically sanitizes known PII fields before they reach LogTide: emails are replaced with HMAC hashes, IP addresses are truncated to remove the last octet, user IDs are pseudonymized, and sensitive fields like passwords and tokens are dropped entirely.