Home / Guides / mask-pii-before-claude

How to mask PII before calling the Claude API (Node.js)

Run deterministic PII masking with @noeticguard/core in your Node backend before anthropic.messages.create — local vault tokens, no cloud scrubbing endpoint.

Published 2026-08-28 · NoeticGuard engineering notes

Live masking playground

Paste text — PII and API keys become vault tokens before any LLM sees them.

Try a scenario:
01

Raw Prompt

Untrusted user input

Type sensitive data or pick a scenario. NoeticGuard Core tokenizes PII and high-precision secrets into a vault ([EMAIL_n], [SECRET_n]), routes safe placeholders to the LLM, then re-identifies on the way back to the user.

Inbound Shield · Tokenize
02

Masked Prompt (To LLM)

Vault tokens ([EMAIL_n], [SECRET_n]) + Brand Guard — reversible PII/secrets only

Masked prompt will appear here.

LLM Inference
03

Raw LLM Output

Model echoes vault tokens (never raw PII)

Run the pipeline to simulate the LLM response.

Outbound Shield · Re-identify
04

Final Unmasked Output (To User)

unmaskPii restores vault PII & secrets · competitors stay blocked

Run the pipeline to see PII restored for the end user.

Anthropic's Claude API is a common backend choice for agents, support copilots, and document Q&A. If user text contains emails, payment details, or national IDs, those values can appear in provider-side logs and retention systems. The fix is identical to OpenAI: run maskPii in your Node service before anthropic.messages.create.

Claude-specific notes

  • Messages API shape — mask the string inside messages[].content before the SDK call; unmask the text block in the response if your UI needs originals.
  • Multi-turn agents — reuse one vault per conversation so [EMAIL_1] stays stable across tool loops. On serverless, persist the vault (Redis/DB).
  • Policy from dashboard — fetch GET /v1/config with an ng_pub_ key so PCI/HIPAA packs and Brand Guard lists match workspace policy.

Pattern

  1. Install @noeticguard/core (see SDK quickstart).
  2. Call maskPii with a per-session vault.
  3. Pass only the masked content to Claude.
  4. Optionally unmaskPii the assistant reply for end users.
  5. Report usage via POST /v1/telemetry.
typescript
import Anthropic from '@anthropic-ai/sdk';
import { maskPii, unmaskPii } from '@noeticguard/core';

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const vault = new Map();

export async function chatWithClaudeMasked(userText: string) {
  const { output: masked, matches } = maskPii(userText, {
    vault,
    kinds: ['email', 'creditCard', 'phone', 'nationalId', 'iban'],
  });

  const message = await anthropic.messages.create({
    model: 'claude-sonnet-4-20250514',
    max_tokens: 1024,
    messages: [{ role: 'user', content: masked }],
  });

  const raw =
    message.content[0]?.type === 'text' ? message.content[0].text : '';
  return {
    reply: unmaskPii(raw, vault),
    entitiesMasked: matches.length,
  };
}

Common failure modes

  • Masking only the latest user turn while prior messages in the Claude thread still contain raw emails — mask every user/tool string that leaves your trust boundary.
  • Creating a new vault per tool call — entity IDs renumber and the model loses continuity. One vault per conversation (or ticket).
  • Skipping telemetry — maskPii works locally, but dashboard usage stays at 0 until POST /v1/telemetry.
  • Shipping ng_secret_ keys to browsers or mobile — use publishable ng_pub_ for config + telemetry only.

When Claude is not the only model

The same vault pattern works for OpenAI, Gemini, and DeepSeek — only the client SDK changes. Prefer one shared maskPii helper in your backend so detector packs and Brand Guard lists stay consistent. Employees pasting into the Claude web UI need Browser Shield, not the API wrapper above.

Also shipping OpenAI? See the OpenAI masking guide — the vault and telemetry pattern is the same; only the SDK client changes. For vendor and category comparisons, see our comparison hub.