← Back to Quick Start

Automatically Redact Sensitive Data from Logs

Detect and mask PII, secrets, and other sensitive data in plain text and JSON — before it hits your log storage.

What you'll learn

  • How to redact emails, SSNs, credit cards, and API keys from text
  • How to process JSON input with nested sensitive fields
  • How to use the dry-run analyze mode to preview detections before redacting
  • How to integrate redaction into your logging pipeline

Prerequisites

Step 1: Your first call

Redact an email address and SSN from a log line:

curl -s -X POST /api/v1/redact \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "content": "User john.doe@example.com signed up. SSN: 123-45-6789. Card: 4111-1111-1111-1111",
    "contentType": "TEXT"
  }' | python3 -m json.tool

Expected response:

{
  "redactedContent": "User [EMAIL_REDACTED] signed up. SSN: [SSN_REDACTED]. Card: [CREDIT_CARD_REDACTED]",
  "detections": [
    {
      "type": "EMAIL",
      "originalValue": "john.doe@example.com",
      "startIndex": 5,
      "endIndex": 25,
      "replacement": "[EMAIL_REDACTED]"
    },
    {
      "type": "SSN",
      "originalValue": "123-45-6789",
      "startIndex": 42,
      "endIndex": 53,
      "replacement": "[SSN_REDACTED]"
    },
    {
      "type": "CREDIT_CARD",
      "originalValue": "4111-1111-1111-1111",
      "startIndex": 61,
      "endIndex": 80,
      "replacement": "[CREDIT_CARD_REDACTED]"
    }
  ],
  "totalDetections": 3,
  "processingTimeMs": 5
}

Step 2: Understanding the response

redactedContent The input with all sensitive data replaced by typed placeholders.
detections Array of each detected item with type, original value, position, and replacement token.
detections[].type Category: EMAIL, SSN, CREDIT_CARD, PHONE, API_KEY, IP_ADDRESS, JWT, etc.
totalDetections Count of sensitive items found and redacted.

Step 3: Common use cases

JSON input with nested fields

curl -s -X POST /api/v1/redact \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "content": "{\"user\": {\"name\": \"Jane Smith\", \"email\": \"jane@corp.com\", \"ssn\": \"987-65-4321\"}, \"action\": \"login\", \"ip\": \"203.0.113.42\"}",
    "contentType": "JSON"
  }'
{
  "redactedContent": "{\"user\": {\"name\": \"Jane Smith\", \"email\": \"[EMAIL_REDACTED]\", \"ssn\": \"[SSN_REDACTED]\"}, \"action\": \"login\", \"ip\": \"[IP_REDACTED]\"}",
  "detections": [
    {"type": "EMAIL", "originalValue": "jane@corp.com", "replacement": "[EMAIL_REDACTED]"},
    {"type": "SSN", "originalValue": "987-65-4321", "replacement": "[SSN_REDACTED]"},
    {"type": "IP_ADDRESS", "originalValue": "203.0.113.42", "replacement": "[IP_REDACTED]"}
  ],
  "totalDetections": 3,
  "processingTimeMs": 7
}

Dry-run analyze mode

Preview what would be redacted without modifying the content:

curl -s -X POST /api/v1/redact/analyze \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "content": "API key sk-abc123def456 found in config. Contact admin@internal.net",
    "contentType": "TEXT"
  }'
{
  "detections": [
    {"type": "API_KEY", "value": "sk-abc123def456", "startIndex": 8, "endIndex": 26, "confidence": "HIGH"},
    {"type": "EMAIL", "value": "admin@internal.net", "startIndex": 48, "endIndex": 66, "confidence": "HIGH"}
  ],
  "totalDetections": 2,
  "wouldRedact": true,
  "processingTimeMs": 4
}

The /analyze endpoint returns detection details without modifying the input — useful for auditing and testing.

Step 4: Handling errors

Input too large

HTTP/1.1 413 Payload Too Large

{
  "error": "INPUT_TOO_LARGE",
  "message": "Content exceeds maximum allowed size of 1MB"
}

Missing required fields

{
  "error": "VALIDATION_ERROR",
  "message": "content: must not be blank",
  "status": 400
}

Invalid content type

{
  "error": "VALIDATION_ERROR",
  "message": "contentType: must be one of [TEXT, JSON]",
  "status": 400
}

Step 5: Integration tips

Python logging filter

import logging
import requests

API_BASE = ""
HEADERS = {
    "Content-Type": "application/json",
    "X-API-Key": "YOUR_API_KEY"
}

class RedactionFilter(logging.Filter):
    """Logging filter that redacts sensitive data before output."""

    def filter(self, record):
        try:
            resp = requests.post(
                f"{API_BASE}/api/v1/redact",
                json={"content": record.getMessage(), "contentType": "TEXT"},
                headers=HEADERS, verify=False, timeout=2
            )
            if resp.ok:
                record.msg = resp.json()["redactedContent"]
                record.args = ()
        except Exception:
            pass  # Fail open: log unredacted rather than drop the message
        return True

# Usage
logger = logging.getLogger("myapp")
logger.addFilter(RedactionFilter())
logger.info("User john@example.com logged in from 10.0.0.1")

Batch processing tip

For high-volume log processing, consider buffering log lines and sending them in batches. The /redact endpoint accepts content up to 1 MB, so you can concatenate multiple log lines (separated by newlines) in a single request.

Next steps