Home / Guides / mask-pii-before-openai
How to mask PII before calling the OpenAI API (Node.js)
Run deterministic PII masking with @noeticguard/core in your Node backend before openai.chat.completions.create — local tokens, no cloud scrubbing endpoint.
Published 2026-08-10 · NoeticGuard engineering notes
Live masking playground
Paste text — PII and API keys become vault tokens before any LLM sees them.
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.
Masked Prompt (To LLM)
Vault tokens ([EMAIL_n], [SECRET_n]) + Brand Guard — reversible PII/secrets only
Masked prompt will appear here.
Raw LLM Output
Model echoes vault tokens (never raw PII)
Run the pipeline to simulate the LLM response.
Final Unmasked Output (To User)
unmaskPii restores vault PII & secrets · competitors stay blocked
Run the pipeline to see PII restored for the end user.
If your Node service calls the OpenAI API with user or customer text, PII can land in provider logs, fine-tunes, and support exports. The fix is not a remote “scrubbing API” that receives the raw prompt — it is an in-process mask before chat.completions.create.
Pattern
- Load
@noeticguard/corein your backend (see SDK quickstart). - Call
maskPiiwith a per-session vault. - Send only the masked string to OpenAI.
- Optionally
unmaskPiithe model reply for your UI. - Report
masked_countvia POST /v1/telemetry with anng_pub_key.
import OpenAI from 'openai';
import { maskPii, unmaskPii } from '@noeticguard/core';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const vault = new Map();
export async function chatWithMaskedPii(userText: string) {
const { output: masked, matches } = maskPii(userText, {
vault,
kinds: ['email', 'creditCard', 'phone', 'nationalId'],
});
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: masked }],
});
const raw = completion.choices[0]?.message?.content ?? '';
return {
reply: unmaskPii(raw, vault),
entitiesMasked: matches.length,
};
}Also shipping Claude? See the Claude masking guide.