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

Path Patterns

Use a single paths array with dot-notation and globs. A bare segment like password is shorthand for **.password — it redacts that key at any nesting depth:

evlog: {
  redact: {
    paths: [
      'password',              // same as '**.password'
      '*_token',               // key-name glob at any depth
      'headers.x-forwarded-for', // exact path
      'user.*',                // everything directly under user
    ],
  }
}
PatternMatches
user.emailExact path only
password or **.passwordpassword key at any depth
*_tokenKey names like access_token, refresh_token
user.*user.email, user.password, etc.
audit.changes.*.passwordMixed exact + wildcard segments

Path redaction replaces the entire value (including nested objects) with replacement. Use patterns when you need regex on string values inside fields.

This matches auditDiff({ redactPaths: ['password'] }) — same glob syntax, applied globally at emit time.

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
pathsstring[]undefinedDot-notation paths with globs (password, **.password, *_token, user.*)
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 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. Path redaction — exact paths and globs replaced with [REDACTED]
  2. Smart masking — built-in patterns scan all string values recursively with partial masking
  3. Pattern redaction — custom regex patterns scan all string values with flat replacement
  4. Console output — masked event printed to stdout
  5. 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