Skip to content
tightlip
Menu

For developers

Swap personal data out of your prompts in two lines.

Wrap your OpenAI or Anthropic client. Tightlip finds names, account numbers, keys and other personal data in each request, swaps them for placeholders, and restores the answer inside your process. The model provider only ever sees the placeholders.

Wrap a client
import OpenAI from 'openai';
import { Tightlip } from 'tightlip';

const tl = new Tightlip({ apiKey: process.env.TIGHTLIP_API_KEY, profile: 'finance' });
const openai = tl.wrapOpenAI(new OpenAI());

// Same call as before. Names and numbers are swapped before the request
// leaves your server, and restored in the response, streaming included.
const res = await openai.chat.completions.create({
  model: 'gpt-4.1-mini',
  messages: [{ role: 'user', content: ticket.body }],
});
Or call it yourself
const s = tl.session();                 // one vault per conversation
const safe = await s.protect(text);     // meters credits: a count, never text
const answer = await callYourModel(safe.text);
const restored = s.restore(answer);     // real values back, in your process
CLI and local proxy
# See what would be protected in a file. Local only, no key needed.
npx tightlip check ./ticket.txt

# Put a protecting proxy in front of any OpenAI- or Anthropic-compatible tool.
TIGHTLIP_API_KEY=tl_live_... npx tightlip proxy --port 8787
1. Your textOn your device
Ticket 48213 from lena.fischer@northwind-dental.com Hi, our patient export keeps failing since yesterday. The link we use is https://app.northwind-dental.com/export?clinic=8821&token=f83kd92hdk2 Our integration key is sk-ant-api03-Zx81kQm2Lr0pVt7Yw3NcBd6Hs9Jf4Ga1Ue5Oi and the server is 10.4.22.17. Call me at +1 415 555 0199 if easier. Lena Fischer, Northwind Dental LLC
2. What the AI seesSent to the AI
Ticket 48213 from [EMAIL_1] Hi, our patient export keeps failing since yesterday. The link we use is [URL_1] Our integration key is [SECRET_1] and the server is [IP_ADDRESS_1]. Call me at [PHONE_1] if easier. [PERSON_1], [ORG_1]
3. The answer you readRestored on your device
Asked: Tell me what is wrong and what to reply.The ticket exposes a live API key. Ask Lena Fischer to revoke sk-ant-api03-Zx81kQm2Lr0pVt7Yw3NcBd6Hs9Jf4Ga1Ue5Oi today, then check the export job on 10.4.22.17. Reply to lena.fischer@northwind-dental.com once the new key is in place.
Real output from Tightlip on a made-up support ticket: 7 items protected (1 email address, 1 private link, 1 secret key, 1 IP address, 1 phone number and 2 more). The swap table that links each placeholder to its real value stayed on the device.

What your security reviewer will want to know

Short answers you can paste into the questionnaire. The longer version is on the security page.

Where does detection run?
Inside your process. The core library has zero runtime dependencies and runs in Node 18 and later, browsers and workers.
What does Tightlip’s server receive?
Your API key, a credit count and the word “sdk” or “proxy”. Never prompt text, never the swap table.
What if the check fails?
protect() throws instead of returning half-protected text, and the wrapped client does not send the request.
What if credits run out?
The SDK raises TightlipQuotaError and the prompt is not sent. Fail closed is the default.

Pricing for API use

1 credit (USD 0.05) per protected prompt of up to 8,000 input tokens, and 1 more for each further 8,000.

You only pay when Tightlip actually protects something. A prompt with nothing to swap is free.

You bring your own model and pay your provider as usual. New accounts start with USD 20 of credits.

Metering, the only call we receive
POST /api/v1/meter
Authorization: Bearer tl_live_...
Content-Type: application/json

{ "credits": 1, "source": "sdk" }

200 { "ok": true, "remaining": 1873 }
402 { "ok": false, "remaining": 0 }

Install

Until the npm release, install the package from our site. Install from this link rather than running npx tightlip on its own, so npm cannot fetch a different package with the same name.

npm install https://tightlipai.com/downloads/tightlip-0.1.0.tgz
Which clients does the wrapper support?
OpenAI chat.completions.create and responses.create, and Anthropic messages.create and messages.stream, with streaming.
Can I keep numbering stable across a conversation?
Yes. Create one session per conversation with tl.session() and pass it to the wrapper as { session }. The same value then keeps the same placeholder for the whole conversation.
Can I tell it about our own identifiers?
Yes. Pass customTerms for names it must always protect and allowTerms for words it must leave alone.

Get a key and protect your first prompt.