Learn

Auto-Redaction

Automatically scrub PII from wide events before console output and drains. Built-in smart masking for credit cards, emails, IPs, phone numbers, JWTs, and more.

Wide events capture comprehensive context, which makes it easy to accidentally log sensitive data. Auto-redaction scrubs PII from events before console output and before any drain sees the data.

Redaction is enabled by default in production (NODE_ENV === 'production'). In development, it is off so you see full values for debugging. No configuration needed — just deploy.

Opting Out

If you need to disable redaction in production:

export default defineNuxtConfig({
  modules: ['evlog/nuxt'],
  evlog: {
    redact: false,
  },
})

You can also enable redaction explicitly in development with redact: true.

wide event·raw
user.email"alice@example.com" ...
payment.card"4111111111111111" ...
user.ip"192.168.1.42" ...
auth"Bearer sk_live_abc123def" ...
metadata.password"hunter2-correct-horse" ...
user.phone"+33 6 12 34 56 78" ...
user.id42 ...
cart.total9999 ...
smart mask path redact untouched ready for drain · 0 PII leaked

Smart Masking

Built-in patterns use partial masking instead of flat [REDACTED] — preserving enough context for debugging while protecting the actual data.

PatternExample InputMasked Output
creditCard4111111111111111****1111
emailalice@example.coma***@***.com
ipv4192.168.1.100***.***.***.100
phone+33 6 12 34 56 78+33 ****5678
jwteyJhbGciOiJIUzI1NiIs...eyJ***.***
bearerBearer sk_live_abc123...Bearer ***
ibanFR76 3000 6000 0112 ...189FR76****189
127.0.0.1 and 0.0.0.0 are excluded from IPv4 masking since they are not real client addresses.

Configuration

Key-Based Redaction

Redact fields by key name at any nesting depth — no need to know the full dot-notation path. A single password entry covers user.password, data.a.b.password, and every other occurrence:

evlog: {
  redact: {
    keys: ['password', 'apiKey', 'authorization', 'cookie'],
    keyPatterns: [/.*_token$/i],
  }
}

Key-based redaction replaces the entire value (including nested objects) with replacement. Use keyPatterns for regex on property names; use patterns when you need regex on string values.

This matches the semantics of auditDiff({ redactPaths: ['password'] }) — the same key-name rules, but applied globally at emit time.

Custom Paths

Add exact dot-notation paths when you need to target one location only (e.g. hyphenated header keys):

evlog: {
  redact: {
    paths: ['headers.x-forwarded-for'],
    keys: ['authorization'],
  }
}

Path-based redaction replaces the entire leaf value with the replacement string (default [REDACTED]), regardless of content. Unlike keys, paths: ['password'] only redacts a top-level password field.

Selective Built-ins

Pick only the patterns you need:

evlog: {
  redact: {
    builtins: ['email', 'creditCard'],
  }
}

Custom Patterns

Add your own regex patterns. These use the flat replacement string, not smart masking:

evlog: {
  redact: {
    patterns: [/SECRET_\w+/g, /sk_live_\w+/g],
    replacement: '***',
  }
}

Disable Built-ins

If you only want custom redaction:

evlog: {
  redact: {
    builtins: false,
    paths: ['user.ssn'],
    patterns: [/INTERNAL_\w+/g],
  }
}

Configuration Reference

OptionTypeDefaultDescription
redactboolean | RedactConfigtrue in productionEnabled by default in production. false to disable. Object for fine-grained control
keysstring[]undefinedObject key names to redact at any depth (e.g. password → all password fields)
keyPatternsRegExp[]undefinedRegex on object key names at any depth (e.g. /.*_token$/)
pathsstring[]undefinedExact dot-notation paths only (e.g. headers.x-forwarded-for)
patternsRegExp[]undefinedCustom regex on string values. Uses flat replacement string
builtinsfalse | string[]All enabledfalse disables built-ins. Array selects specific ones
replacementstring'[REDACTED]'Replacement for keys, paths, and custom patterns. Built-ins use smart masking instead

Available built-in names: creditCard, email, ipv4, phone, jwt, bearer, iban.

How It Works

Redaction runs inside the emit pipeline, after the wide event is fully built but before any output:

  1. Key redaction — matching key names at any depth replaced with [REDACTED]
  2. Path redaction — exact dot-notation leaves replaced with [REDACTED]
  3. Smart masking — built-in patterns scan all string values recursively with partial masking
  4. Pattern redaction — custom regex patterns scan all string values with flat replacement
  5. Console output — masked event printed to stdout
  6. Drain — masked event sent to external services
Redaction runs after the HTTP response is sent, so it adds zero latency to your API responses.

Production Example

Redaction is already on by default in production. Combine with sampling for a typical setup:

export default defineNuxtConfig({
  modules: ['evlog/nuxt'],
  evlog: {
    env: { service: 'my-app' },
  },
  $production: {
    evlog: {
      sampling: {
        rates: { info: 10, debug: 0 },
        keep: [{ status: 400 }, { duration: 1000 }],
      },
    },
  },
})

Before / After

Without redaction, sensitive data lands in your logs and drains:

{
  "user": { "email": "alice@example.com", "ip": "192.168.1.42" },
  "payment": { "card": "4111111111111111" },
  "auth": "Bearer sk_live_abc123def456"
}

With redact: true:

{
  "user": { "email": "a***@***.com", "ip": "***.***.***.42" },
  "payment": { "card": "****1111" },
  "auth": "Bearer ***"
}

Same debugging context, no PII in your Axiom/Datadog/Sentry.

Next Steps