# REST API Reference Source: https://docs.blindfold.dev/api-reference/rest-api Complete HTTP API documentation for Blindfold The Blindfold REST API provides direct HTTP access to all privacy protection features. Use any programming language or HTTP client to integrate with Blindfold. ## Base URL ``` https://api.blindfold.dev/api/public/v1 ``` ### Regional Endpoints | Region | Base URL | | ---------------- | -------------------------------------------------------- | | **EU** (default) | `https://eu-api.blindfold.dev/api/public/v1` | | **US** | `https://us-api.blindfold.dev/api/public/v1` | | **Global** | `https://api.blindfold.dev/api/public/v1` (routes to EU) | See [Regions](/essentials/regions) for details on data residency and region selection. ## Authentication All API requests require authentication using an API key in the `X-API-Key` header: ```http theme={null} X-API-Key: your-api-key-here ``` ### Getting Your API Key 1. Sign up at [app.blindfold.dev](https://app.blindfold.dev) 2. Navigate to **API Keys** in the dashboard 3. Click **Create API Key** 4. Copy and securely store your key Keep your API key secure. Never commit it to version control or expose it in client-side code. ## Request Format All requests must: * Use `Content-Type: application/json` * Include the `X-API-Key` header * Send data as JSON in the request body ```http theme={null} POST /api/public/v1/tokenize HTTP/1.1 Host: api.blindfold.dev X-API-Key: your-api-key-here Content-Type: application/json { "text": "Your text here" } ``` ## Response Format All successful responses return JSON with: * `text`: The processed text * `detected_entities`: Array of detected entities (if applicable) * `entities_count`: Number of entities detected * Additional method-specific fields ### Success Response (200 OK) ```json theme={null} { "text": "Processed text", "entities_count": 2, "detected_entities": [ { "type": "EMAIL_ADDRESS", "text": "john@example.com", "start": 12, "end": 28, "score": 1.0 } ] } ``` ### Error Response (4xx, 5xx) ```json theme={null} { "detail": "Error message describing what went wrong" } ``` ## Policy-Based Detection Blindfold supports **policy-based PII detection** for simplified configuration and compliance. Instead of manually specifying entities and thresholds for each request, use pre-configured policies or create custom ones. ### Available Global Policies | Policy Name | Description | Threshold | Use Case | | ----------- | --------------------- | --------- | ----------------------------------- | | `basic` | Minimal PII detection | 0.30 | General purpose, fast detection | | `gdpr_eu` | GDPR EU compliant | 0.35 | European data protection compliance | | `hipaa_us` | HIPAA compliant | 0.40 | US healthcare data compliance | | `pci_dss` | PCI DSS compliant | 0.45 | Payment card industry compliance | | `strict` | Maximum detection | 0.25 | Comprehensive PII protection | ### Using Policies in API Calls All detection endpoints (`/detect`, `/tokenize`, `/mask`, `/redact`, `/hash`, `/encrypt`) support an optional `policy` parameter: ```json theme={null} { "text": "Your text here", "policy": "gdpr_eu" } ``` Using policies simplifies your code and ensures consistent PII detection across your application. Policies can be managed through the dashboard. ## Batch Processing All privacy method endpoints support **batch processing** — send multiple texts in a single request by using `texts` (array) instead of `text` (string). Configuration parameters (`policy`, `entities`, `score_threshold`) apply to all texts in the batch. ### Batch Request Format ```json theme={null} { "texts": ["Text one with PII", "Text two with PII", "Text three"], "policy": "gdpr_eu" } ``` ### Batch Response Format ```json theme={null} { "results": [ { "text": "...", "detected_entities": [...], "entities_count": 1 }, { "text": "...", "detected_entities": [...], "entities_count": 0 }, { "error": "Processing failed for this item" } ], "total": 3, "succeeded": 2, "failed": 1 } ``` ### Batch Limits | Limit | Value | | ----------------------- | ------------------------------- | | Max texts per request | 100 | | Max characters per text | 100,000 | | Rate limiting | Once per request (not per text) | You must provide either `text` (single) or `texts` (batch), not both. Each text in the batch must be non-empty. ### Batch Example ```bash cURL theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "texts": [ "Contact John Doe at john@example.com", "Call Jane at +1-555-9876", "No sensitive data here" ], "policy": "gdpr_eu" }' ``` ```python Python SDK theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key-here") result = client.tokenize_batch( texts=["John Doe john@example.com", "Jane Smith +1-555-9876"], policy="gdpr_eu" ) print(f"Processed {result.succeeded}/{result.total} texts") for item in result.results: print(item["text"]) ``` ```typescript JavaScript SDK theme={null} import { Blindfold } from '@blindfold/sdk' const client = new Blindfold({ apiKey: 'your-api-key-here' }) const result = await client.tokenizeBatch( ['John Doe john@example.com', 'Jane Smith +1-555-9876'], { policy: 'gdpr_eu' } ) console.log(`Processed ${result.succeeded}/${result.total} texts`) result.results.forEach(item => console.log(item.text)) ``` Batch processing is available on all 7 privacy methods: **tokenize**, **detect**, **redact**, **mask**, **synthesize**, **hash**, and **encrypt**. The `/detokenize` and `/discover` endpoints do not support batch mode. *** ## API Endpoints Tokenize, mask, redact, hash, encrypt, synthesize Detokenization and health checks Security, rate limiting, examples *** ## Privacy Method Endpoints These endpoints apply different privacy-preserving transformations to your text. ### Method Comparison Choose the right privacy method for your use case: | Method | Reversible | Output Example | Best For | | ------------------------------ | ---------- | --------------------- | --------------------------- | | [Detect](#post-detect) | N/A | `[{type, text, ...}]` | DLP, monitoring, compliance | | [Tokenize](#post-tokenize) | ✅ Yes | `` | AI processing, chatbots | | [Mask](#post-mask) | ❌ No | `***3456` | Display to users | | [Redact](#post-redact) | ❌ No | \`\` (removed) | Permanent removal, logs | | [Hash](#post-hash) | ❌ No | `ID_a3f8b9` | Analytics, deduplication | | [Encrypt](#post-encrypt) | ✅ Yes | `gAAAAABh...` | Secure storage | | [Synthesize](#post-synthesize) | ❌ No | `Jane Smith` (fake) | Testing, demos | **For AI applications:** Use **tokenize** + **detokenize** to protect PII while maintaining context for the AI model. **For compliance:** Use policies like `gdpr_eu`, `hipaa_us`, or `pci_dss` to automatically apply the correct entity types and thresholds. *** ### POST /detect Detect PII in text without modifying it. Returns only the detected entities. ```bash cURL (with policy) theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/detect \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "Contact John Doe at john@example.com", "policy": "gdpr_eu" }' ``` ```python Python (with policy) theme={null} import requests response = requests.post( "https://api.blindfold.dev/api/public/v1/detect", headers={ "X-API-Key": "your-api-key-here", "Content-Type": "application/json" }, json={ "text": "Contact John Doe at john@example.com", "policy": "gdpr_eu" } ) data = response.json() print(data) ``` ```javascript JavaScript (with policy) theme={null} const response = await fetch( 'https://api.blindfold.dev/api/public/v1/detect', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'Contact John Doe at john@example.com', policy: 'gdpr_eu' }) } ); const data = await response.json(); console.log(data); ``` **Request Body:** | Field | Type | Required | Description | | ----------------- | --------- | -------- | ----------------------------------------- | | `text` | string | Yes | Text to analyze for PII | | `policy` | string | No | Policy name (e.g., `gdpr_eu`, `hipaa_us`) | | `entities` | string\[] | No | Filter specific entity types | | `score_threshold` | number | No | Minimum confidence (0.0-1.0) | **Response:** ```json theme={null} { "entities_count": 2, "detected_entities": [ { "type": "Person", "text": "John Doe", "start": 8, "end": 16, "score": 0.95 }, { "type": "Email Address", "text": "john@example.com", "start": 20, "end": 36, "score": 1.0 } ] } ``` Unlike other methods, `/detect` does not return a `text` field — it only returns the detected entities. Use this when you need to know **what** PII exists without transforming the text. *** ### POST /tokenize Replace sensitive data with reversible tokens. Returns a mapping to restore original values. ```bash cURL (with policy) theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "Contact John Doe at john@example.com", "policy": "gdpr_eu" }' ``` ```bash cURL (manual config) theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "Contact John Doe at john@example.com", "entities": ["person", "email address"], "score_threshold": 0.4 }' ``` ```python Python (with policy) theme={null} import requests response = requests.post( "https://api.blindfold.dev/api/public/v1/tokenize", headers={ "X-API-Key": "your-api-key-here", "Content-Type": "application/json" }, json={ "text": "Contact John Doe at john@example.com", "policy": "gdpr_eu" # Use GDPR policy } ) data = response.json() print(data) ``` ```javascript JavaScript (with policy) theme={null} const response = await fetch( 'https://api.blindfold.dev/api/public/v1/tokenize', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'Contact John Doe at john@example.com', policy: 'gdpr_eu' // Use GDPR policy }) } ); const data = await response.json(); console.log(data); ``` **Request Body:** | Field | Type | Required | Description | | ----------------- | --------- | -------- | -------------------------------------------------------------------------------- | | `text` | string | Yes | Text to tokenize | | `policy` | string | No | Policy name (e.g., `gdpr_eu`, `hipaa_us`) - uses policy's entities and threshold | | `entities` | string\[] | No | Filter specific entity types (alternative to policy) | | `score_threshold` | number | No | Minimum confidence (0.0-1.0) (alternative to policy) | **Policy Usage Example:** ```bash theme={null} # Using a policy curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "Contact John Doe at john@example.com", "policy": "gdpr_eu" }' ``` **Response:** ```json theme={null} { "text": "Contact at ", "mapping": { "": "John Doe", "": "john@example.com" }, "entities_count": 2, "detected_entities": [ { "type": "PERSON", "text": "John Doe", "start": 8, "end": 16, "score": 0.95 }, { "type": "EMAIL_ADDRESS", "text": "john@example.com", "start": 20, "end": 36, "score": 1.0 } ] } ``` *** ## Utility Endpoints These endpoints provide utility functions and service information. ### POST /detokenize Restore original values from tokens using the mapping from `/tokenize`. **Use with:** `/tokenize` endpoint to complete the privacy-preserving workflow. ```bash cURL theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/detokenize \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "AI response for at ", "mapping": { "": "John Doe", "": "john@example.com" } }' ``` ```python Python theme={null} import requests response = requests.post( "https://api.blindfold.dev/api/public/v1/detokenize", headers={ "X-API-Key": "your-api-key-here", "Content-Type": "application/json" }, json={ "text": "AI response for at ", "mapping": { "": "John Doe", "": "john@example.com" } } ) data = response.json() print(data) ``` ```javascript JavaScript theme={null} const response = await fetch( 'https://api.blindfold.dev/api/public/v1/detokenize', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'AI response for at ', mapping: { '': 'John Doe', '': 'john@example.com' } }) } ); const data = await response.json(); console.log(data); ``` **Request Body:** | Field | Type | Required | Description | | --------- | ------ | -------- | ---------------------- | | `text` | string | Yes | Text containing tokens | | `mapping` | object | Yes | Token-to-value mapping | **Response:** ```json theme={null} { "text": "AI response for John Doe at john@example.com", "replacements_made": 2 } ``` *** ### POST /mask Partially hide sensitive data (e.g., `****-****-****-1234`). ```bash cURL (with policy) theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/mask \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "Credit card: 4532-7562-9102-3456", "policy": "pci_dss", "masking_char": "*", "chars_to_show": 4, "from_end": true }' ``` ```bash cURL (manual config) theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/mask \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "Credit card: 4532-7562-9102-3456", "entities": ["credit card number"], "masking_char": "*", "chars_to_show": 4, "from_end": true }' ``` ```python Python (with policy) theme={null} import requests response = requests.post( "https://api.blindfold.dev/api/public/v1/mask", headers={ "X-API-Key": "your-api-key-here", "Content-Type": "application/json" }, json={ "text": "Credit card: 4532-7562-9102-3456", "policy": "pci_dss", # PCI DSS policy for payment cards "masking_char": "*", "chars_to_show": 4, "from_end": True } ) data = response.json() print(data) ``` ```javascript JavaScript (with policy) theme={null} const response = await fetch( 'https://api.blindfold.dev/api/public/v1/mask', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'Credit card: 4532-7562-9102-3456', policy: 'pci_dss', // PCI DSS policy for payment cards masking_char: '*', chars_to_show: 4, from_end: true }) } ); const data = await response.json(); console.log(data); ``` **Request Body:** | Field | Type | Required | Description | | ----------------- | --------- | -------- | -------------------------------- | | `text` | string | Yes | Text to mask | | `masking_char` | string | No | Masking character (default: `*`) | | `chars_to_show` | number | No | Characters to show (default: 4) | | `from_end` | boolean | No | Show from end (default: true) | | `entities` | string\[] | No | Filter specific entity types | | `score_threshold` | number | No | Minimum confidence (0.0-1.0) | **Response:** ```json theme={null} { "text": "Credit card: ***************3456", "entities_count": 1, "detected_entities": [ { "type": "CREDIT_CARD", "text": "4532-7562-9102-3456", "start": 13, "end": 32, "score": 1.0 } ] } ``` *** ### POST /redact Permanently remove sensitive data. ```bash cURL (with policy) theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/redact \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "Patient: Jane Smith, SSN: 123-45-6789, DOB: 1985-04-12", "policy": "hipaa_us" }' ``` ```bash cURL (manual config) theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/redact \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "My SSN is 123-45-6789", "entities": ["social security number"], "score_threshold": 0.5 }' ``` ```python Python (with policy) theme={null} import requests response = requests.post( "https://api.blindfold.dev/api/public/v1/redact", headers={ "X-API-Key": "your-api-key-here", "Content-Type": "application/json" }, json={ "text": "Patient: Jane Smith, SSN: 123-45-6789, DOB: 1985-04-12", "policy": "hipaa_us" # HIPAA policy for healthcare data } ) data = response.json() print(data) ``` ```javascript JavaScript (with policy) theme={null} const response = await fetch( 'https://api.blindfold.dev/api/public/v1/redact', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'Patient: Jane Smith, SSN: 123-45-6789, DOB: 1985-04-12', policy: 'hipaa_us' // HIPAA policy for healthcare data }) } ); const data = await response.json(); console.log(data); ``` **Request Body:** | Field | Type | Required | Description | | ----------------- | --------- | -------- | ---------------------------- | | `text` | string | Yes | Text to redact | | `entities` | string\[] | No | Filter specific entity types | | `score_threshold` | number | No | Minimum confidence (0.0-1.0) | **Response:** ```json theme={null} { "text": "My SSN is ", "entities_count": 1, "detected_entities": [ { "type": "US_SSN", "text": "123-45-6789", "start": 10, "end": 21, "score": 1.0 } ] } ``` *** ### POST /hash Replace data with deterministic hashes. ```bash cURL (with policy) theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/hash \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "User john@example.com purchased item", "policy": "basic", "hash_type": "sha256", "hash_prefix": "ID_", "hash_length": 16 }' ``` ```bash cURL (manual config) theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/hash \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "User john@example.com purchased item", "entities": ["email address"], "hash_type": "sha256", "hash_prefix": "ID_", "hash_length": 16 }' ``` ```python Python (with policy) theme={null} import requests response = requests.post( "https://api.blindfold.dev/api/public/v1/hash", headers={ "X-API-Key": "your-api-key-here", "Content-Type": "application/json" }, json={ "text": "User john@example.com purchased item", "policy": "basic", # Basic policy for common PII "hash_type": "sha256", "hash_prefix": "ID_", "hash_length": 16 } ) data = response.json() print(data) ``` ```javascript JavaScript (with policy) theme={null} const response = await fetch( 'https://api.blindfold.dev/api/public/v1/hash', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'User john@example.com purchased item', policy: 'basic', // Basic policy for common PII hash_type: 'sha256', hash_prefix: 'ID_', hash_length: 16 }) } ); const data = await response.json(); console.log(data); ``` **Request Body:** | Field | Type | Required | Description | | ----------------- | --------- | -------- | ----------------------------------------------------------------------------------------- | | `text` | string | Yes | Text to hash | | `hash_type` | string | No | Hash algorithm: `md5`, `sha1`, `sha224`, `sha256`, `sha384`, `sha512` (default: `sha256`) | | `hash_prefix` | string | No | Prefix for hashes (default: `""`) | | `hash_length` | number | No | Hash length to use (default: 16) | | `entities` | string\[] | No | Filter specific entity types | | `score_threshold` | number | No | Minimum confidence (0.0-1.0) | **Response:** ```json theme={null} { "text": "User ID_a3f8b9c2d4e5f6g7 purchased item", "entities_count": 1, "detected_entities": [ { "type": "EMAIL_ADDRESS", "text": "john@example.com", "start": 5, "end": 21, "score": 1.0 } ] } ``` *** ### POST /synthesize Replace real data with realistic fake data. ```bash cURL theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/synthesize \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "John lives in New York", "language": "en" }' ``` ```python Python theme={null} import requests response = requests.post( "https://api.blindfold.dev/api/public/v1/synthesize", headers={ "X-API-Key": "your-api-key-here", "Content-Type": "application/json" }, json={ "text": "John lives in New York", "language": "en" } ) data = response.json() print(data) ``` ```javascript JavaScript theme={null} const response = await fetch( 'https://api.blindfold.dev/api/public/v1/synthesize', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'John lives in New York', language: 'en' }) } ); const data = await response.json(); console.log(data); ``` **Request Body:** | Field | Type | Required | Description | | ----------------- | --------- | -------- | ------------------------------------------------------------------------ | | `text` | string | Yes | Text to synthesize | | `language` | string | No | Language: `en`, `cs`, `de`, `fr`, `es`, `it`, `pl`, `sk` (default: `en`) | | `entities` | string\[] | No | Filter specific entity types | | `score_threshold` | number | No | Minimum confidence (0.0-1.0) | **Response:** ```json theme={null} { "text": "Michael Smith lives in Boston", "entities_count": 2, "detected_entities": [ { "type": "PERSON", "text": "John", "start": 0, "end": 4, "score": 0.95 }, { "type": "LOCATION", "text": "New York", "start": 14, "end": 22, "score": 0.90 } ] } ``` *** ### POST /encrypt Encrypt sensitive data using AES encryption. ```bash cURL (with policy) theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/encrypt \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "Secret: API key is sk-12345, Password: myPass123", "policy": "strict", "encryption_key": "my-secure-encryption-key" }' ``` ```bash cURL (manual config) theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/encrypt \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "Secret: API key is sk-12345", "entities": ["username", "password"], "encryption_key": "my-secure-encryption-key" }' ``` ```python Python (with policy) theme={null} import requests response = requests.post( "https://api.blindfold.dev/api/public/v1/encrypt", headers={ "X-API-Key": "your-api-key-here", "Content-Type": "application/json" }, json={ "text": "Secret: API key is sk-12345, Password: myPass123", "policy": "strict", # Strict policy for maximum detection "encryption_key": "my-secure-encryption-key" } ) data = response.json() print(data) ``` ```javascript JavaScript (with policy) theme={null} const response = await fetch( 'https://api.blindfold.dev/api/public/v1/encrypt', { method: 'POST', headers: { 'X-API-Key': 'your-api-key-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ text: 'Secret: API key is sk-12345, Password: myPass123', policy: 'strict', // Strict policy for maximum detection encryption_key: 'my-secure-encryption-key' }) } ); const data = await response.json(); console.log(data); ``` **Request Body:** | Field | Type | Required | Description | | ----------------- | --------- | -------- | ----------------------------- | | `text` | string | Yes | Text to encrypt | | `encryption_key` | string | No | Encryption key (min 16 chars) | | `entities` | string\[] | No | Filter specific entity types | | `score_threshold` | number | No | Minimum confidence (0.0-1.0) | **Response:** ```json theme={null} { "text": "Secret: gAAAAABh3K7x...", "entities_count": 1, "detected_entities": [ { "type": "API_KEY", "text": "sk-12345", "start": 19, "end": 27, "score": 0.85 } ] } ``` *** ### GET /health Health check endpoint. ```bash theme={null} curl https://api.blindfold.dev/api/public/v1/health ``` **Response:** ```json theme={null} { "status": "healthy", "service": "Public API", "version": "v1", "endpoints": [ "/v1/tokenize", "/v1/detokenize", "/v1/redact", "/v1/mask", "/v1/synthesize", "/v1/hash", "/v1/encrypt" ] } ``` ## Supported Entity Types All detection endpoints support filtering by entity type using **natural language names** (lowercase). Blindfold supports 60+ pre-trained entity types. See the complete list of 60+ entity types organized by category ### Quick Reference ### Personal Information * `person` - Person names * `email` / `email address` - Email addresses * `phone number` / `mobile phone number` - Phone numbers * `date of birth` - Birth dates * `blood type` - Blood type classification ### Contact Information * `address` / `postal code` - Physical addresses and postal codes * `landline phone number` - Fixed-line phone numbers * `fax number` - Fax numbers ### Financial * `credit card number` - Credit card numbers * `credit card brand` - Card issuer (Visa, Mastercard, etc.) * `credit card expiration date` - Card expiration dates * `cvv` / `cvc` - Card verification codes * `bank account number` - Bank account numbers * `iban` - International Bank Account Numbers * `tax identification number` - Tax IDs ### Government IDs * `social security number` - Social security numbers * `passport number` - Passport numbers * `driver's license number` - Driver's licenses * `national id number` - National ID cards * `cpf` - Brazilian individual taxpayer ID * `cnpj` - Brazilian company registry ### Healthcare * `health insurance number` - Health insurance IDs * `medical condition` - Medical diagnoses * `medication` - Medication names * `insurance company` - Insurance provider names ### Digital & Technical * `ip address` - IPv4 and IPv6 addresses * `username` - User identifiers * `social media handle` - Social media usernames ### Travel & Transactions * `flight number` - Airline flight numbers * `reservation number` - Booking confirmations * `transaction number` - Transaction IDs ### Registration * `license plate number` - Vehicle plates * `student id number` - Student IDs * `serial number` - Product serial numbers See the complete list of 60+ entity types in the [Supported Entities](/essentials/supported-entities) documentation. ## Plans & Limits | | Free | Pay As You Go | | ------------------------ | ------------ | ----------------------- | | **Characters** | 500K / month | Unlimited (\$0.50 / 1M) | | **Max text per request** | 5K chars | 500K chars | The API returns a `429 Too Many Requests` response when you exceed your plan limits. Implement retry logic with exponential backoff for production use. ## Error Codes | Code | Description | | ---- | ----------------------------------------- | | 200 | Success | | 400 | Bad Request - Invalid parameters | | 401 | Unauthorized - Invalid or missing API key | | 429 | Too Many Requests - Rate limit exceeded | | 500 | Internal Server Error - Server-side issue | ## Best Practices ### 1. Store API Keys Securely ```bash theme={null} # Use environment variables export BLINDFOLD_API_KEY="your-api-key-here" ``` ### 2. Handle Rate Limits Implement exponential backoff for rate limit errors: ```python theme={null} import time import requests def make_request_with_retry(url, data, max_retries=3): for attempt in range(max_retries): response = requests.post(url, json=data, headers=headers) if response.status_code == 429: # Rate limited - wait and retry wait_time = 2 ** attempt time.sleep(wait_time) continue return response raise Exception("Max retries exceeded") ``` ### 3. Validate Responses Always check the response status and handle errors: ```python theme={null} response = requests.post(url, json=data, headers=headers) if response.status_code == 200: data = response.json() print(f"Success: {data['text']}") elif response.status_code == 401: print("Invalid API key") elif response.status_code == 429: print("Rate limit exceeded") else: print(f"Error: {response.json()['detail']}") ``` ### 4. Use Connection Pooling For high-throughput applications, use connection pooling: ```python theme={null} import requests session = requests.Session() # Reuse session for multiple requests response = session.post(url, json=data, headers=headers) ``` ## Complete Examples Real-world integration patterns using the Blindfold REST API. Complete tokenize → AI → detokenize workflow GDPR, HIPAA, PCI DSS policy usage ### Example 1: AI Integration with GDPR Compliance ```python theme={null} import requests import os API_KEY = os.environ.get("BLINDFOLD_API_KEY") BASE_URL = "https://api.blindfold.dev/api/public/v1" headers = { "X-API-Key": f"{API_KEY}", "Content-Type": "application/json" } # 1. Tokenize user input using GDPR policy user_message = "My name is John Doe, email john@example.com, phone +49 30 12345678" tokenize_response = requests.post( f"{BASE_URL}/tokenize", headers=headers, json={ "text": user_message, "policy": "gdpr_eu" # Use GDPR-compliant policy } ) tokenize_data = tokenize_response.json() protected_text = tokenize_data["text"] mapping = tokenize_data["mapping"] print(f"Protected: {protected_text}") # Output: "My name is , email , phone " # 2. Send to AI (using protected text) # ... AI processing ... # 3. Detokenize AI response ai_response = f"Thank you {protected_text.split()[3]}!" # Example AI response detokenize_response = requests.post( f"{BASE_URL}/detokenize", headers=headers, json={ "text": ai_response, "mapping": mapping } ) final_text = detokenize_response.json()["text"] print(f"Final: {final_text}") # Output: "Thank you John Doe!" ``` ### Example 2: Healthcare Data with HIPAA Policy ```python theme={null} import requests import os API_KEY = os.environ.get("BLINDFOLD_API_KEY") BASE_URL = "https://api.blindfold.dev/api/public/v1" headers = { "X-API-Key": f"{API_KEY}", "Content-Type": "application/json" } # Redact healthcare data using HIPAA policy patient_data = """ Patient: Jane Smith DOB: 1985-04-12 SSN: 123-45-6789 Health Insurance: ABC123456 Diagnosis: Type 2 Diabetes Medication: Metformin 500mg """ redact_response = requests.post( f"{BASE_URL}/redact", headers=headers, json={ "text": patient_data, "policy": "hipaa_us" # Use HIPAA-compliant policy } ) redacted_data = redact_response.json() print(f"Redacted data:\n{redacted_data['text']}") print(f"Entities found: {redacted_data['entities_count']}") ``` ### Example 3: Payment Card Data with PCI DSS Policy ```python theme={null} import requests import os API_KEY = os.environ.get("BLINDFOLD_API_KEY") BASE_URL = "https://api.blindfold.dev/api/public/v1" headers = { "X-API-Key": f"{API_KEY}", "Content-Type": "application/json" } # Mask payment card data using PCI DSS policy transaction_data = "Transaction for card 4532-7562-9102-3456, CVV: 123, expires 12/25" mask_response = requests.post( f"{BASE_URL}/mask", headers=headers, json={ "text": transaction_data, "policy": "pci_dss", # Use PCI DSS policy for payment cards "masking_char": "*", "chars_to_show": 4, "from_end": True } ) masked_data = mask_response.json() print(f"Masked data: {masked_data['text']}") print(f"Entities found: {masked_data['entities_count']}") ``` ## Need Help? * **Email Support**: [hello@blindfold.dev](mailto:hello@blindfold.dev) * **SDK Documentation**: [Python SDK](/sdks/python-sdk) | [JavaScript SDK](/sdks/javascript-sdk) * **Examples**: [See practical examples](/examples) # Best Practices Source: https://docs.blindfold.dev/best-practices Production-ready patterns for using Blindfold effectively and securely This guide covers best practices for deploying Blindfold in production, optimizing performance, and ensuring security. ## Choosing the Right Privacy Method Different use cases require different privacy approaches. Here's how to choose: **When to use:** * AI chatbots and assistants (OpenAI, Anthropic Claude, Google Gemini) * LLM-powered applications (LangChain, LlamaIndex, Vercel AI SDK) * When you need to restore original data after processing **Why:** * Reversible - you can restore original PII after AI responds * Maintains context for AI (tokens preserve sentence structure) * Best for user-facing applications ```python theme={null} # AI Chatbot Example protected = client.tokenize(user_input, policy="gdpr_eu") ai_response = send_to_openai(protected.text) final = client.detokenize(ai_response, protected.mapping) return final.text # User gets personalized response ``` **When to use:** * Showing data to users (e.g., "Card ending in 3456") * Audit logs that need partial visibility * Customer support interfaces **Why:** * Not reversible - safe for display * Shows enough context to be useful * Prevents accidental exposure ```python theme={null} # Display to User masked = client.mask( "Card: 4532-7562-9102-3456", policy="pci_dss" ) # "Card: ***************3456" ``` **When to use:** * Audit logs with no PII requirement * Public data sharing * Compliance with "right to be forgotten" **Why:** * Completely removes PII * Cannot be reversed * Safest for long-term storage ```python theme={null} # Audit Logs logged = client.redact( "User John Doe (SSN: 123-45-6789) logged in", policy="strict" ) # "User (SSN: ) logged in" ``` **When to use:** * User tracking across sessions * Analytics and aggregation * Deduplication without storing PII **Why:** * Same input = same hash (consistent IDs) * Cannot reverse to original value * Safe for analytics databases ```python theme={null} # Analytics user_id = client.hash("john@example.com") # Always "ID_a3f8b9c2" for this email analytics.track(user_id, event="login") ``` **When to use:** * Long-term data storage * Database encryption * Regulatory compliance requiring encrypted PII **Why:** * Reversible with your encryption key * Industry-standard AES-256 encryption * You control the decryption key ```python theme={null} # Secure Storage encrypted = client.encrypt( "Patient: Jane Smith, DOB: 1985-03-15", encryption_key="your-32-byte-key", policy="hipaa_us" ) # Store encrypted.text safely # Later retrieve original = client.decrypt(encrypted.text, encryption_key="your-32-byte-key") ``` **When to use:** * Creating test datasets * Demos and screenshots * Development environments **Why:** * Generates realistic fake data * Maintains format and structure * Safe for public sharing ```python theme={null} # Test Data synthetic = client.synthesize( "John Doe, john@example.com, +1-555-1234", policy="gdpr_eu" ) # "Jane Smith, jane.smith@sample.com, +1-555-9876" ``` ## Choosing the Right Policy Policies simplify compliance by providing pre-configured entity sets. ### Policy Selection Guide | Policy | Use Case | Entity Count | Compliance | | ---------- | ----------------------- | ------------ | ------------------ | | `basic` | General PII protection | 3 types | General privacy | | `gdpr_eu` | European applications | 15+ types | GDPR Article 4 | | `hipaa_us` | Healthcare applications | 11+ types | HIPAA Privacy Rule | | `pci_dss` | Payment processing | 8+ types | PCI DSS 3.2.1 | | `strict` | Maximum protection | 60+ types | All regulations | ### When to Create Custom Policies Create custom policies when: Your industry has unique PII definitions not covered by standard policies ```python theme={null} # Legal Industry Example legal_policy = client.create_policy( name="legal_discovery", entities=[ "person", "organization", "email address", "case number", "attorney name", "client name" ], threshold=0.40 ) ``` You only need specific entity types and want faster processing ```python theme={null} # Fast Contact Detection contact_policy = client.create_policy( name="contact_only", entities=["email address", "phone number"], threshold=0.35 # Lower threshold = more detections ) ``` You need to detect domain-specific identifiers ```python theme={null} # E-commerce Example ecommerce_policy = client.create_policy( name="ecommerce_sensitive", entities=[ "person", "email address", "phone number", "order number", "tracking number", "customer id" ], threshold=0.40 ) ``` ## Security Best Practices ### API Key Management Never commit API keys to version control or expose them in client-side code. **Recommended Approaches:** ```bash theme={null} # .env file (add to .gitignore) BLINDFOLD_API_KEY=sk_live_... OPENAI_API_KEY=sk-... ``` ```python theme={null} # Python import os from dotenv import load_dotenv load_dotenv() api_key = os.getenv("BLINDFOLD_API_KEY") ``` ```javascript theme={null} // JavaScript import dotenv from 'dotenv'; dotenv.config(); const apiKey = process.env.BLINDFOLD_API_KEY; ``` **AWS Secrets Manager:** ```python theme={null} import boto3 from botocore.exceptions import ClientError def get_secret(): session = boto3.session.Session() client = session.client('secretsmanager') try: response = client.get_secret_value(SecretId='blindfold/api-key') return response['SecretString'] except ClientError as e: raise e api_key = get_secret() ``` **Google Secret Manager:** ```python theme={null} from google.cloud import secretmanager def access_secret(): client = secretmanager.SecretManagerServiceClient() name = "projects/PROJECT_ID/secrets/blindfold-api-key/versions/latest" response = client.access_secret_version(request={"name": name}) return response.payload.data.decode("UTF-8") api_key = access_secret() ``` **Never in Browser:** ```javascript theme={null} // ❌ WRONG - Client-side code const client = new Blindfold({ apiKey: 'sk_live_...' }); ``` **Use API Routes:** ```javascript theme={null} // ✅ CORRECT - Next.js API Route // app/api/protect/route.js import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: process.env.BLINDFOLD_API_KEY // Server-side only }); export async function POST(request) { const { text } = await request.json(); const result = await client.tokenize(text, { policy: "gdpr_eu" }); return Response.json(result); } ``` ### Mapping Storage Mappings must be stored securely to enable detokenization. **Benefits:** * Fast access * Built-in expiration * Encrypted in transit ```python theme={null} import redis import json from datetime import timedelta redis_client = redis.Redis( host='localhost', port=6379, ssl=True, # Use TLS password=os.getenv('REDIS_PASSWORD') ) # Store mapping with 24-hour expiration protected = client.tokenize(user_input, policy="gdpr_eu") session_id = generate_session_id() redis_client.setex( f"mapping:{session_id}", timedelta(hours=24), json.dumps(protected.mapping) ) # Retrieve later mapping_json = redis_client.get(f"mapping:{session_id}") mapping = json.loads(mapping_json) original = client.detokenize(ai_response, mapping) ``` **Benefits:** * Persistent storage * Query capabilities * Backup support ```python theme={null} from cryptography.fernet import Fernet import json # Generate encryption key (store securely) encryption_key = Fernet.generate_key() cipher = Fernet(encryption_key) # Encrypt mapping before storing protected = client.tokenize(user_input, policy="gdpr_eu") encrypted_mapping = cipher.encrypt( json.dumps(protected.mapping).encode() ) # Store in database db.execute( "INSERT INTO mappings (session_id, encrypted_data, expires_at) VALUES (?, ?, ?)", (session_id, encrypted_mapping, datetime.now() + timedelta(hours=24)) ) # Retrieve and decrypt row = db.execute("SELECT encrypted_data FROM mappings WHERE session_id = ?", (session_id,)) decrypted = cipher.decrypt(row[0]) mapping = json.loads(decrypted) ``` **Benefits:** * Simple implementation * Automatic cleanup * No external dependencies **Use only for short-lived sessions (\< 1 hour)** ```python theme={null} # Flask example from flask import session @app.route('/protect', methods=['POST']) def protect(): protected = client.tokenize(request.json['text'], policy="gdpr_eu") # Store in encrypted session cookie session['mapping'] = protected.mapping session['expires'] = (datetime.now() + timedelta(hours=1)).isoformat() return jsonify({"text": protected.text}) @app.route('/restore', methods=['POST']) def restore(): mapping = session.get('mapping') if not mapping: return jsonify({"error": "Mapping expired"}), 400 original = client.detokenize(request.json['text'], mapping) return jsonify({"text": original.text}) ``` **Mapping Security Checklist:** * [ ] Set expiration time (recommended: 24 hours or less) * [ ] Encrypt mappings at rest * [ ] Use TLS/SSL for transmission * [ ] Implement access controls * [ ] Log access for audit trails * [ ] Auto-delete expired mappings * [ ] Never log mappings in plain text ## Performance Optimization ### Use Async for Concurrency Process multiple requests in parallel for better throughput. ```python theme={null} import asyncio from blindfold import AsyncBlindfold async def process_messages(messages): async with AsyncBlindfold(api_key=api_key) as client: # Process concurrently tasks = [ client.tokenize(msg, policy="gdpr_eu") for msg in messages ] results = await asyncio.gather(*tasks) return results # Process 100 messages concurrently messages = get_user_messages() results = asyncio.run(process_messages(messages)) ``` **Performance:** * Sequential: 100 requests × 200ms = 20 seconds * Async: \~2-3 seconds (limited by API rate limits) ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: apiKey }); async function processMessages(messages) { // Process concurrently with Promise.all const promises = messages.map(msg => client.tokenize(msg, { policy: "gdpr_eu" }) ); const results = await Promise.all(promises); return results; } // Process 100 messages concurrently const messages = getUserMessages(); const results = await processMessages(messages); ``` **Performance:** * Sequential: 100 requests × 200ms = 20 seconds * Async: \~2-3 seconds (limited by API rate limits) ### Batch Similar Requests Combine similar text into single requests when possible. ```python theme={null} # ❌ Inefficient - 3 API calls result1 = client.tokenize("User 1: john@example.com") result2 = client.tokenize("User 2: jane@example.com") result3 = client.tokenize("User 3: bob@example.com") # ✅ Efficient - 1 API call combined_text = """ User 1: john@example.com User 2: jane@example.com User 3: bob@example.com """ result = client.tokenize(combined_text, policy="basic") # Parse results by line lines = result.text.split('\n') ``` ### Cache Results Cache tokenization results for frequently used text. ```python theme={null} from functools import lru_cache import hashlib class CachedBlindfold: def __init__(self, api_key): self.client = Blindfold(api_key=api_key) self._cache = {} def tokenize(self, text, policy="basic"): # Create cache key cache_key = hashlib.sha256( f"{text}:{policy}".encode() ).hexdigest() # Check cache if cache_key in self._cache: return self._cache[cache_key] # Call API result = self.client.tokenize(text, policy=policy) # Store in cache self._cache[cache_key] = result return result # Use cached client client = CachedBlindfold(api_key=api_key) # First call - hits API result1 = client.tokenize("john@example.com", policy="basic") # Second call - uses cache (instant) result2 = client.tokenize("john@example.com", policy="basic") ``` ### Optimize Detection Threshold Higher thresholds = faster processing, fewer detections. ```python theme={null} # Using GDPR policy (threshold: 0.35) result = client.tokenize(text, policy="gdpr_eu") # Using custom entities and threshold for specific needs result = client.tokenize( text, entities=["person", "email address", "phone number"], score_threshold=0.60 # Higher threshold for fewer false positives ) # Lower threshold to catch more edge cases result = client.tokenize( text, entities=["person", "email address", "phone number"], score_threshold=0.25 ) ``` **Threshold Selection:** * **0.60+**: High confidence only, fast processing * **0.35-0.60**: Balanced (recommended for most use cases) * **0.25-0.35**: Catch more edge cases, may have false positives * **\< 0.25**: Maximum detection, slower, more false positives ## Error Handling ### Comprehensive Error Handling Handle all error types gracefully. ```python theme={null} from blindfold import ( Blindfold, AuthenticationError, APIError, RateLimitError, ValidationError ) import logging logger = logging.getLogger(__name__) def safe_tokenize(text, policy="gdpr_eu"): try: result = client.tokenize(text, policy=policy) return result except AuthenticationError: # Invalid API key - alert admin immediately logger.critical("Blindfold API key is invalid or expired") # Send alert to ops team send_admin_alert("Invalid Blindfold API key") return None except RateLimitError as e: # Rate limited - implement backoff logger.warning(f"Rate limited. Retry after {e.retry_after}s") time.sleep(e.retry_after) # Retry once try: return client.tokenize(text, policy=policy) except Exception as retry_error: logger.error(f"Retry failed: {retry_error}") return None except ValidationError as e: # Invalid input - return user-friendly message logger.error(f"Validation error: {e.message}") return {"error": "Invalid input provided"} except APIError as e: # API error - log details and fail gracefully logger.error(f"Blindfold API error ({e.status_code}): {e.message}") # Could be 500, 503, etc. return None except Exception as e: # Unexpected error - log and alert logger.exception(f"Unexpected error in tokenization: {e}") send_admin_alert(f"Unexpected Blindfold error: {e}") return None ``` ```javascript theme={null} import { Blindfold, AuthenticationError, APIError, RateLimitError, ValidationError } from '@blindfold/sdk'; const logger = console; // Use your logging library async function safeTokenize(text, policy = "gdpr_eu") { try { const result = await client.tokenize(text, { policy }); return result; } catch (error) { if (error instanceof AuthenticationError) { // Invalid API key - alert admin immediately logger.error("Blindfold API key is invalid or expired"); await sendAdminAlert("Invalid Blindfold API key"); return null; } else if (error instanceof RateLimitError) { // Rate limited - implement backoff logger.warn(`Rate limited. Retry after ${error.retryAfter}s`); await sleep(error.retryAfter * 1000); // Retry once try { return await client.tokenize(text, { policy }); } catch (retryError) { logger.error(`Retry failed: ${retryError.message}`); return null; } } else if (error instanceof ValidationError) { // Invalid input - return user-friendly message logger.error(`Validation error: ${error.message}`); return { error: "Invalid input provided" }; } else if (error instanceof APIError) { // API error - log details and fail gracefully logger.error(`Blindfold API error (${error.statusCode}): ${error.message}`); return null; } else { // Unexpected error - log and alert logger.error(`Unexpected error in tokenization: ${error.message}`); await sendAdminAlert(`Unexpected Blindfold error: ${error.message}`); return null; } } } ``` ### Retry Strategy with Exponential Backoff ```python theme={null} import time from blindfold import Blindfold, APIError, RateLimitError def tokenize_with_retry(text, policy="gdpr_eu", max_retries=3): """Tokenize with exponential backoff retry strategy""" for attempt in range(max_retries): try: result = client.tokenize(text, policy=policy) return result except RateLimitError as e: # Use retry-after header wait_time = e.retry_after logger.warning(f"Rate limited. Waiting {wait_time}s...") time.sleep(wait_time) continue except APIError as e: if e.status_code >= 500: # Server error - retry with exponential backoff wait_time = (2 ** attempt) + random.uniform(0, 1) logger.warning(f"Server error. Retry {attempt + 1}/{max_retries} after {wait_time}s") time.sleep(wait_time) continue else: # Client error - don't retry raise except Exception as e: # Unexpected error - don't retry raise raise Exception(f"Failed after {max_retries} retries") ``` ## Monitoring and Logging ### Track API Usage Monitor your API usage to prevent unexpected rate limit hits. ```python theme={null} import logging from datetime import datetime class MonitoredBlindfold: def __init__(self, api_key): self.client = Blindfold(api_key=api_key) self.request_count = 0 self.error_count = 0 self.logger = logging.getLogger(__name__) def tokenize(self, text, policy="basic"): start_time = datetime.now() try: result = self.client.tokenize(text, policy=policy) self.request_count += 1 # Log successful request duration = (datetime.now() - start_time).total_seconds() self.logger.info( f"Tokenize success: {result.entities_count} entities, " f"{duration:.2f}s, policy={policy}" ) return result except Exception as e: self.error_count += 1 duration = (datetime.now() - start_time).total_seconds() # Log error self.logger.error( f"Tokenize error: {str(e)}, " f"{duration:.2f}s, policy={policy}" ) raise def get_stats(self): return { "total_requests": self.request_count, "total_errors": self.error_count, "error_rate": self.error_count / max(self.request_count, 1) } ``` ### Set Up Alerts Monitor critical metrics and set up alerts. ```python theme={null} # Example: DataDog monitoring from datadog import statsd def tokenize_with_metrics(text, policy="gdpr_eu"): with statsd.timed('blindfold.tokenize.duration'): try: result = client.tokenize(text, policy=policy) # Track success statsd.increment('blindfold.tokenize.success') statsd.gauge('blindfold.entities_detected', result.entities_count) return result except RateLimitError: statsd.increment('blindfold.tokenize.rate_limited') raise except Exception as e: statsd.increment('blindfold.tokenize.error') raise ``` ## Compliance Considerations ### GDPR Compliance Only detect and protect the entities you need. ```python theme={null} # ✅ Good - Only detect what's needed result = client.tokenize( text, entities=["person", "email address"] # Minimal set ) # ❌ Overkill - Detecting everything result = client.tokenize(text, policy="strict") # 60+ entities ``` Implement data deletion for user requests. ```python theme={null} def delete_user_data(user_id): # 1. Delete mappings from storage redis_client.delete(f"mapping:{user_id}") # 2. Delete encrypted data from database db.execute("DELETE FROM mappings WHERE user_id = ?", (user_id,)) # 3. Log deletion for audit trail logger.info(f"Deleted all data for user {user_id}") return {"status": "deleted"} ``` Request a DPA from Blindfold for your records. Contact: [hello@blindfold.dev](mailto:hello@blindfold.dev) Subject: "DPA Request - \[Your Company]" ### HIPAA Compliance ```python theme={null} # Always use hipaa_us policy for healthcare data result = client.tokenize( patient_data, policy="hipaa_us" ) ``` ```python theme={null} # Ensure TLS/SSL for all API calls (enabled by default) client = Blindfold( api_key=api_key, # SDK uses HTTPS by default ) ``` Request a BAA from Blindfold if processing PHI. Contact: [hello@blindfold.dev](mailto:hello@blindfold.dev) Subject: "BAA Request - \[Your Organization]" ## Testing Best Practices ### Unit Testing Test your privacy protection logic thoroughly. ```python theme={null} import unittest from blindfold import Blindfold class TestPrivacyProtection(unittest.TestCase): def setUp(self): self.client = Blindfold(api_key="test_key") def test_email_detection(self): """Test that emails are properly detected""" result = self.client.tokenize( "Contact: john@example.com", policy="basic" ) self.assertEqual(result.entities_count, 1) self.assertIn("", result.text) self.assertIn("", result.mapping) self.assertEqual(result.mapping[""], "john@example.com") def test_detokenization_restores_original(self): """Test that detokenization works correctly""" original = "My email is john@example.com" # Tokenize protected = self.client.tokenize(original, policy="basic") # Detokenize restored = self.client.detokenize( protected.text, protected.mapping ) self.assertEqual(restored.text, original) def test_no_pii_returns_unchanged(self): """Test that text without PII is unchanged""" text = "The weather is nice today" result = self.client.tokenize(text, policy="basic") self.assertEqual(result.entities_count, 0) self.assertEqual(result.text, text) self.assertEqual(result.mapping, {}) ``` ### Integration Testing Test the complete flow with real AI providers. ```python theme={null} import pytest from blindfold import Blindfold from openai import OpenAI @pytest.fixture def clients(): return { 'blindfold': Blindfold(api_key=os.getenv("BLINDFOLD_API_KEY")), 'openai': OpenAI(api_key=os.getenv("OPENAI_API_KEY")) } def test_ai_integration_flow(clients): """Test complete privacy-preserving AI flow""" user_input = "My name is John Doe and my email is john@example.com" # Step 1: Protect PII protected = clients['blindfold'].tokenize( user_input, policy="gdpr_eu" ) assert protected.entities_count > 0 assert "John Doe" not in protected.text assert "john@example.com" not in protected.text # Step 2: Send to AI completion = clients['openai'].chat.completions.create( model="gpt-4", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": protected.text} ] ) ai_response = completion.choices[0].message.content # Step 3: Restore original data final_response = clients['blindfold'].detokenize( ai_response, protected.mapping ) # Verify restoration worked if "" in ai_response: assert "John Doe" in final_response.text if "" in ai_response: assert "john@example.com" in final_response.text ``` ## Production Deployment Checklist Before deploying to production: ### Security * [ ] API keys stored in secret management system (not environment variables) * [ ] Mappings encrypted at rest * [ ] TLS/SSL enabled for all connections * [ ] API keys never exposed in client-side code * [ ] Logging doesn't include sensitive data or mappings * [ ] Access controls implemented for mapping storage * [ ] Regular security audits scheduled ### Performance * [ ] Async methods used for concurrent requests * [ ] Caching implemented for frequently used text * [ ] Batch processing for similar requests * [ ] Appropriate detection threshold chosen * [ ] Connection pooling configured * [ ] Timeouts set appropriately ### Error Handling * [ ] All error types handled gracefully * [ ] Retry logic with exponential backoff implemented * [ ] Fallback behavior defined for API failures * [ ] Admin alerts configured for critical errors * [ ] User-friendly error messages displayed ### Monitoring * [ ] Request count tracking * [ ] Error rate monitoring * [ ] Latency tracking * [ ] Rate limit monitoring * [ ] Alerts configured for anomalies * [ ] Logging integrated with central logging system ### Compliance * [ ] Appropriate policy selected (GDPR, HIPAA, PCI DSS) * [ ] Data retention policies implemented * [ ] Mapping expiration configured * [ ] DPA/BAA obtained if required * [ ] Privacy policy updated * [ ] Audit trail implemented ### Testing * [ ] Unit tests for all privacy methods * [ ] Integration tests with AI providers * [ ] Load testing completed * [ ] Edge cases tested (empty text, very long text, special characters) * [ ] Failure scenarios tested ## Need Help? Read the complete documentation Contact [hello@blindfold.dev](mailto:hello@blindfold.dev) for help See real-world integration examples Complete API documentation # Compliance & Legal Source: https://docs.blindfold.dev/compliance How Blindfold helps you meet GDPR, HIPAA, PCI DSS, EU AI Act, CCPA, LGPD, and SOC 2 requirements ## Why Compliance Matters for AI When using AI services like OpenAI, Anthropic, or other LLM providers, you're sending user data to third-party systems. This creates significant **legal and compliance risks** under modern privacy regulations. **Blindfold protects you** by ensuring sensitive data never reaches AI providers in plain text. PII is detected and anonymized *before* it leaves your infrastructure. ``` User message Blindfold AI Provider "Email hans@example.de" → "Email " → AI only sees tokens ↓ "I'll email hans@..." ← Detokenize with mapping ← "I'll email " ``` ## Regulation Guides EU data protection for AI applications. Use the **EU region** and `gdpr_eu` policy to keep European personal data compliant. Protect PHI in healthcare AI. Use the **US region** and `hipaa_us` policy to meet HIPAA de-identification requirements. Secure cardholder data in payment AI. Use the `pci_dss` policy to mask, encrypt, and redact card numbers. Meet the world's first comprehensive AI regulation. Data minimization, transparency, and high-risk system requirements. Keep sensitive data in the right jurisdiction. Regional endpoints and tokenization for cross-border AI compliance. Protect California consumer data. Prevent "sale" or "sharing" of personal information with AI providers. Brazil's data protection law. Use the EU region and `gdpr_eu` policy for LGPD-compliant AI processing. Demonstrate security practices to enterprise customers. Audit logs, encryption, and access controls. ## Quick Comparison | Regulation | Policy | Region | Key Focus | | ------------------ | -------------------- | ------- | ------------------------------------------------------------------ | | **GDPR** | `gdpr_eu` | EU | Personal data of EU residents — names, emails, IBANs, addresses | | **HIPAA** | `hipaa_us` | US | Protected Health Information — 18 identifiers including SSNs, MRNs | | **PCI DSS** | `pci_dss` | Any | Cardholder data — card numbers, CVVs, expiry dates | | **EU AI Act** | `gdpr_eu` + `strict` | EU | Data minimization, transparency, high-risk AI systems | | **Data Residency** | Any | EU / US | Cross-border data transfers, Schrems II, GDPR Chapter V | | **CCPA / CPRA** | `strict` | US | California consumer rights — opt-out of sale/sharing of PI | | **LGPD** | `gdpr_eu` | EU | Brazilian personal data — names, CPFs, addresses | | **SOC 2** | Any | Any | Trust Services Criteria — security, confidentiality, privacy | ## Common Compliance Questions Yes, for GDPR compliance. Contact us at [hello@blindfold.dev](mailto:hello@blindfold.dev) to sign a DPA. Blindfold processes personal data to detect and protect PII, making us a data processor under GDPR. Yes. Blindfold offers: * Business Associate Agreement (BAA) * AES-256 encryption (HIPAA compliant) * Audit logging * Access controls Contact us for a BAA: [hello@blindfold.dev](mailto:hello@blindfold.dev) SOC 2 certification is in progress. Contact us for current compliance status and security documentation. * **EU region**: PII processed on EU-based servers (`eu-api.blindfold.dev`) * **US region**: PII processed on US-based servers (`us-api.blindfold.dev`) * **Data retention**: We don't store your text data * **Audit logs**: Retained for 90 days * **Backups**: Encrypted at rest See [Regions](/essentials/regions) for details. Because Blindfold protects PII before it reaches AI providers: 1. **If AI provider is breached**: Your users' real PII was never exposed (only tokens/hashes) 2. **If Blindfold is breached**: We notify you within 72 hours per GDPR 3. **Reduced risk**: Tokenized/hashed data is not useful to attackers Blindfold provides: 1. **Audit logs** — every PII detection and anonymization is logged 2. **API documentation** — proof of data protection implementation 3. **DPA/BAA** — legal agreements for GDPR/HIPAA 4. **Dashboard reports** — export audit logs for compliance reviews Export audit logs from the [dashboard](https://app.blindfold.dev) for compliance reports. ## Getting Started with Compliance Create your account at [app.blindfold.dev](https://app.blindfold.dev) Select EU or US region based on your data residency requirements. See [Regions](/essentials/regions). Use `gdpr_eu`, `hipaa_us`, or `pci_dss` depending on your regulation. See [Policies](/essentials/policies). Follow the [Quick Start guide](/quickstart) to add Blindfold to your application. Email [hello@blindfold.dev](mailto:hello@blindfold.dev) for DPA, BAA, or security documentation. ## Need Help? Contact our legal team for DPAs, BAAs, and compliance questions Get help with integration and implementation Read our technical documentation Working code examples for GDPR and HIPAA *** **Disclaimer**: This documentation provides general information about compliance requirements. It is not legal advice. Consult with legal counsel to ensure your specific implementation meets all applicable regulations. # CCPA / CPRA Compliance Source: https://docs.blindfold.dev/compliance/ccpa Protect California consumer data in AI applications The **California Consumer Privacy Act** (CCPA) is the most comprehensive state-level privacy law in the United States. The **California Privacy Rights Act** (CPRA), which amended and expanded CCPA effective January 2023, added new consumer rights and created the California Privacy Protection Agency (CPPA) for enforcement. When your AI application processes personal information of California residents, CCPA/CPRA applies — and sending that data to third-party AI providers like OpenAI or Anthropic creates significant legal risk. Blindfold solves this by **tokenizing personal information in the US region** before it reaches any AI provider. The LLM only sees anonymized tokens like `` — never real names, SSNs, or email addresses. ## Who Must Comply CCPA/CPRA applies to any for-profit business that collects California consumers' personal information **and** meets any one of these thresholds: * **Annual gross revenue** over \$25 million * **Buy, sell, or share** the personal information of 100,000 or more consumers, households, or devices * **Derive 50% or more of annual revenue** from selling or sharing consumers' personal information CCPA applies based on where your **users** live, not where your company is located. If you have California customers, CCPA likely applies to you. ## Key CCPA/CPRA Rights **Right**: Consumers can request what personal information is collected, used, disclosed, or sold about them. **Risk with AI**: If you send consumer data to AI providers, you must disclose this in your privacy policy — and be able to tell consumers exactly what data was shared. **With Blindfold**: Since only anonymized tokens reach the AI provider, no real personal information is disclosed. Audit logs document exactly what entity types were detected and protected. **Right**: Consumers can request deletion of their personal information. **Risk with AI**: Data sent to AI providers may be retained in their logs, caches, or training data — making deletion impossible. **With Blindfold**: No real personal information reaches the AI provider. For your own records, use `tokenize()` with mapping deletion — once the mapping is destroyed, tokens become meaningless and irrecoverable. **Right**: Consumers can opt out of the sale or sharing of their personal information, including sharing with AI providers. **Risk with AI**: Sending consumer data to a third-party AI provider may constitute "sharing" under CCPA/CPRA, even without monetary exchange. **With Blindfold**: Tokenization eliminates this risk entirely. Since only anonymized tokens leave your system, there is no "sale" or "sharing" of personal information — regardless of consumer opt-out status. **Right**: Consumers can request correction of inaccurate personal information held by a business. **Risk with AI**: If inaccurate data is sent to AI providers, corrections cannot propagate to third-party systems. **With Blindfold**: Real personal information stays in your system where you control it. Corrections only need to happen in your database — the AI provider never had the real data. **Right**: Consumers can limit the use and disclosure of sensitive personal information — including Social Security numbers, financial account information, precise geolocation, racial or ethnic origin, health data, and biometric information. **Risk with AI**: Sensitive PI sent to AI providers violates this right if the consumer has opted to limit its use. **With Blindfold**: Sensitive PI is detected and tokenized before AI calls. The `strict` policy catches SSNs, financial data, health information, and other sensitive categories automatically. ## How AI Creates CCPA Risk Under CCPA/CPRA, "sharing" means disclosing personal information to a third party for cross-context behavioral advertising or other purposes — and the definition is broad. When you send consumer data to third-party AI providers like OpenAI or Anthropic, this may constitute **"sharing"** or even **"selling"** personal information under CCPA. This creates three problems: 1. **Opt-out obligations** — consumers who opt out of sharing must have their data excluded from AI provider calls 2. **Disclosure requirements** — you must list AI providers as recipients in your privacy policy 3. **Right to delete** — data sent to AI providers may be irrecoverable **Tokenization eliminates all three risks.** When you tokenize before AI calls, no personal information reaches the AI provider. There is nothing to opt out of, nothing to disclose, and nothing to delete. ``` Consumer Message Blindfold US Region AI Provider "Hi, I'm Sarah Johnson, "Hi, I'm , AI sees only sarah.johnson@example.com, → , → anonymized tokens SSN 123-45-6789" " ↓ "Dear Sarah Johnson, ← Detokenize with mapping ← "Dear , we've updated your..." (PI stays in US) we've updated your..." ``` ## CCPA Categories and Blindfold CCPA defines specific categories of personal information (Cal. Civ. Code 1798.140(v)). Here is how Blindfold's entity detection maps to them: | CCPA Category | Examples | Blindfold Entity Types | | ---------------------------- | ------------------------------------------------ | --------------------------------------------- | | **Identifiers** | Name, SSN, email, address | Person, Email Address, US SSN, Address | | **Financial Information** | Bank account, credit card | Credit Card Number, Bank Account Number, IBAN | | **Commercial Information** | Purchase records, transactions | Handled by custom policies | | **Internet Activity** | IP addresses, browsing history | IP Address | | **Geolocation** | Physical location, GPS | Location, Address | | **Professional Information** | Employer, job title | Organization | | **Sensitive PI (CPRA)** | SSN, financial accounts, health data, biometrics | US SSN, Medical Record Number, Biometric Data | ## Code Examples ### Tokenize Before AI Calls The most common pattern: protect California consumer data before any AI API call. ```python Python theme={null} from blindfold import Blindfold from openai import OpenAI blindfold = Blindfold(api_key="your-key", region="us") openai_client = OpenAI(api_key="your-openai-key") consumer_message = ( "Hi, my name is Sarah Johnson and I need help with my account. " "My email is sarah.johnson@example.com, SSN 123-45-6789. " "I live at 742 Evergreen Terrace, Los Angeles, CA 90001." ) # Step 1: Tokenize PI before sending to AI provider tokenized = blindfold.tokenize(consumer_message, policy="strict") # → "Hi, my name is and I need help with my account. # My email is , . # I live at ." # Step 2: Send only tokens to OpenAI — no "sharing" of PI completion = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "You are a customer support agent."}, {"role": "user", "content": tokenized.text}, ], ) ai_response = completion.choices[0].message.content # Step 3: Restore real values for the consumer restored = blindfold.detokenize(ai_response, tokenized.mapping) print(restored.text) ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; import OpenAI from 'openai'; const blindfold = new Blindfold({ apiKey: 'your-key', region: 'us' }); const openai = new OpenAI({ apiKey: 'your-openai-key' }); const consumerMessage = 'Hi, my name is Sarah Johnson and I need help with my account. ' + 'My email is sarah.johnson@example.com, SSN 123-45-6789. ' + 'I live at 742 Evergreen Terrace, Los Angeles, CA 90001.'; // Step 1: Tokenize PI before sending to AI provider const tokenized = await blindfold.tokenize(consumerMessage, { policy: 'strict', }); // Step 2: Send only tokens to OpenAI — no "sharing" of PI const completion = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [ { role: 'system', content: 'You are a customer support agent.' }, { role: 'user', content: tokenized.text }, ], }); const aiResponse = completion.choices[0].message.content; // Step 3: Restore real values for the consumer const restored = await blindfold.detokenize(aiResponse, tokenized.mapping); console.log(restored.text); ``` ### Redact Consumer Data from Logs Permanently remove personal information from application logs to minimize data retention: ```python Python theme={null} from blindfold import Blindfold blindfold = Blindfold(api_key="your-key", region="us") log_entries = [ "2026-02-19 User Sarah Johnson (sarah.johnson@example.com) submitted a support ticket.", "2026-02-19 Payment processed for card ending 3456, customer Mike Chen, IP 192.168.1.42.", "2026-02-19 Account update requested by Lisa Park, SSN 987-65-4321.", ] # Redact PI from all log entries (irreversible) batch = blindfold.redact_batch(log_entries, policy="strict") for i, result in enumerate(batch.results): print(f"Log {i+1}: {result['text']}") # Log 1: "2026-02-19 User [REDACTED] ([REDACTED]) submitted a support ticket." # Log 2: "2026-02-19 Payment processed for card ending [REDACTED], customer [REDACTED], IP [REDACTED]." # Log 3: "2026-02-19 Account update requested by [REDACTED], [REDACTED]." ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; const blindfold = new Blindfold({ apiKey: 'your-key', region: 'us' }); const logEntries = [ '2026-02-19 User Sarah Johnson (sarah.johnson@example.com) submitted a support ticket.', '2026-02-19 Payment processed for card ending 3456, customer Mike Chen, IP 192.168.1.42.', '2026-02-19 Account update requested by Lisa Park, SSN 987-65-4321.', ]; // Redact PI from all log entries (irreversible) const batch = await blindfold.redactBatch(logEntries, { policy: 'strict' }); for (const [i, result] of batch.results.entries()) { console.log(`Log ${i + 1}: ${result.text}`); } ``` ### Right to Delete Implementation Tokenization naturally supports CCPA's Right to Delete. When a consumer requests deletion, destroy the token mapping — the tokens become meaningless: ```python theme={null} from blindfold import Blindfold blindfold = Blindfold(api_key="your-key", region="us") # Original consumer interaction (stored with tokenized text + mapping) consumer_message = ( "My name is Sarah Johnson, email sarah.johnson@example.com. " "Please cancel my subscription." ) tokenized = blindfold.tokenize(consumer_message, policy="strict") # Stored text: "My name is , email . # Please cancel my subscription." # Stored mapping: {"": "Sarah Johnson", "": "sarah.johnson@example.com"} # --- Consumer requests deletion under CCPA Art. 1798.105 --- # Step 1: Delete the mapping from your database delete_token_mapping(consumer_id="sarah-johnson-123") # Step 2: The tokenized text is now permanently de-identified # "" can never be linked back to "Sarah Johnson" # No real PI remains — deletion obligation satisfied # Optional: Redact stored records for extra safety records = fetch_consumer_records(consumer_id="sarah-johnson-123") for record in records: redacted = blindfold.redact(record.content, policy="strict") update_record(record.id, redacted.text) ``` ## Blindfold as a CCPA Safeguard Using Blindfold tokenization before AI provider calls provides three key CCPA protections: * **No "sale" or "sharing"** — the AI provider never receives real personal information, so sending tokenized data does not constitute a sale or sharing under CCPA/CPRA * **Data minimization** — only anonymized tokens leave your system, minimizing the personal information exposed to third parties * **Audit trail** — every PI detection is logged with entity types, counts, timestamps, and policy used, providing documentation for CCPA compliance reviews and consumer requests ## CCPA/CPRA Compliance Checklist Check if you meet any of the three thresholds: \$25M revenue, 100K+ consumers' data, or 50%+ revenue from selling/sharing PI. Map the CCPA categories (identifiers, financial, geolocation, etc.) to the data flowing through your AI application. Use `blindfold.tokenize()` with `policy="strict"` and `region="us"` to protect consumer PI before it reaches any third-party AI provider. Provide a "Do Not Sell or Share My Personal Information" link. With Blindfold tokenization, no real PI is shared — but the mechanism is still required. Use Blindfold's audit trail to document what personal information was detected and how it was protected. Export logs from the [dashboard](https://app.blindfold.dev). Disclose how you use AI providers, what categories of PI are collected, and how Blindfold tokenization prevents sharing of real consumer data. CCPA regulations evolve through CPPA rulemaking. Review your compliance posture, privacy policy, and Blindfold configuration at least quarterly. # Data Residency Source: https://docs.blindfold.dev/compliance/data-residency Keep sensitive data in the right jurisdiction when using AI **Data residency** refers to the physical or geographic location where data is stored and processed. When you build AI-powered applications, every API call to an LLM provider sends your users' data to wherever that provider's servers are located — often the United States. This creates a problem: if your users are in the EU, Brazil, or China, their personal data may be crossing borders without the legal safeguards those jurisdictions require. Blindfold solves this by either **processing PII within the correct region** or **removing PII before it crosses any border**. ## Why Data Residency Matters for AI When you call OpenAI, Anthropic, or any other AI provider, user data travels to their servers — typically in the US. For a simple prompt like *"Help Hans Mueller at [hans.mueller@example.de](mailto:hans.mueller@example.de) with his subscription"*, you have just transferred a German citizen's personal data outside the EU. This matters because: * **Regulations restrict cross-border transfers** — GDPR, LGPD, PIPL, and others impose strict rules on sending personal data abroad * **AI providers are third-party processors** — every LLM call is a data processing event under privacy law * **Adequacy decisions are fragile** — the EU-US Privacy Shield was invalidated overnight by Schrems II; relying solely on legal frameworks is risky * **Fines are substantial** — GDPR penalties reach 4% of global annual turnover; PIPL violations can result in service suspension Sending personal data to an AI provider in another jurisdiction without proper safeguards is a cross-border data transfer — even if the data is only processed in memory and never stored. ## Key Regulations **Articles 44-49** govern cross-border data transfers. Personal data can only leave the EU/EEA if the destination country has an **adequacy decision** from the European Commission, or if appropriate safeguards are in place. **Schrems II ruling** (2020) invalidated the EU-US Privacy Shield, leaving Standard Contractual Clauses (SCCs) as the primary mechanism — but SCCs require a supplementary transfer impact assessment. **Key points**: * Adequacy decisions exist for limited countries (Japan, South Korea, UK, etc.) * The EU-US Data Privacy Framework (2023) replaced Privacy Shield but faces legal challenges * Tokenized data (e.g., ``) is not personal data and falls outside Chapter V transfer rules **Article 33** of the Lei Geral de Protecao de Dados restricts international data transfers. Personal data may only be transferred to countries or organizations that provide an **adequate level of protection**, or with the data subject's **explicit and informed consent**. **Key points**: * Brazil's ANPD (National Data Protection Authority) has yet to publish its full adequacy list * Transfer mechanisms mirror GDPR: adequacy decisions, SCCs, binding corporate rules * Consent must be specific, informed, and separate from other consents * LGPD penalties reach 2% of revenue in Brazil (up to 50 million BRL per infraction) **Articles 38-43** of the Personal Information Protection Law impose the strictest cross-border transfer rules globally. Transfers require a **security assessment** by the Cyberspace Administration of China (CAC) for large-scale processors. **Key points**: * Critical Information Infrastructure (CII) operators must store personal data within China (strict data localization) * Processors handling data of 1M+ individuals must pass a CAC security assessment before any transfer * Standard contracts are available for smaller-scale transfers but still require filing with the CAC * Separate consent is required for each cross-border transfer India's **Digital Personal Data Protection Act** (2023) empowers the central government to restrict transfers to specific countries via notification. While broadly permissive (transfers are allowed unless a country is blacklisted), certain categories of data may be subject to **localization requirements**. **Key points**: * Government can notify countries where transfers are prohibited * Certain sectors (e.g., financial, telecom) have existing RBI/SEBI/TRAI data localization mandates * Significant Data Fiduciaries face additional obligations * Penalties up to 250 crore INR (\~\$30M) for non-compliance **Section 72** of the Protection of Personal Information Act requires that cross-border transfers only occur when the recipient is subject to an **adequate level of protection** — either through the recipient country's laws, binding corporate rules, or the data subject's consent. **Key points**: * Adequacy is assessed by the Information Regulator * Consent is a valid transfer mechanism * Binding corporate rules and contractual safeguards are accepted * POPIA applies to any processing of South African residents' data, regardless of where the processor is located ## Global Data Residency Requirements | Regulation | Jurisdiction | Key Requirement | Blindfold Solution | | ---------- | ------------ | ---------------------------------------------- | ---------------------------------- | | **GDPR** | EU/EEA | No transfer without adequacy decision or SCCs | EU region endpoint (`region="eu"`) | | **LGPD** | Brazil | Adequate protection required for transfers | EU region (adequacy aligned) | | **PIPL** | China | Security assessment for cross-border transfers | Tokenize before transfer | | **DPDPA** | India | Localization for certain data categories | Tokenize before transfer | | **POPIA** | South Africa | Adequate protection or consent required | Tokenize before transfer | ## How Blindfold Solves Data Residency Blindfold offers two complementary approaches to data residency compliance: 1. **Regional endpoints** — Process PII within the correct jurisdiction so personal data never leaves the region. Use this when regulations require data to stay within a specific geography. 2. **Tokenize before transfer** — Replace PII with anonymous tokens like `` before sending data to any AI provider. Since tokens contain no personal data, they are not subject to cross-border transfer restrictions. Use this when regional processing alone is insufficient or when the AI provider is in a different jurisdiction. ### Regional Endpoints | Region | Endpoint | Data Location | | ------ | ---------------------- | ------------------ | | **EU** | `eu-api.blindfold.dev` | Frankfurt, Germany | | **US** | `us-api.blindfold.dev` | Virginia, US | API keys work globally — the same key works with any region. You choose the region in your SDK constructor or API URL, not in your API key configuration. ### When to Use Which Approach | Scenario | Approach | | --------------------------------- | --------------------------------------------------- | | EU users + US-based AI provider | EU region + tokenize before AI call | | US users + US-based AI provider | US region (data stays domestic) | | Brazilian users + any AI provider | EU region + tokenize (LGPD-GDPR alignment) | | Chinese users + any AI provider | Tokenize before any cross-border transfer | | Multi-region application | Configure region per-request based on user location | ## Code Examples ### EU Data Residency with GDPR Policy Protect EU personal data by processing PII in the EU before sending tokens to OpenAI: ```python Python theme={null} from blindfold import Blindfold from openai import OpenAI blindfold = Blindfold(api_key="your-key", region="eu") openai_client = OpenAI(api_key="your-openai-key") user_message = ( "Hallo, mein Name ist Hans Mueller. Meine E-Mail ist " "hans.mueller@example.de und meine IBAN ist DE89 3704 0044 0532 0130 00. " "Ich brauche Hilfe mit meiner Bestellung." ) # Step 1: Tokenize PII on EU servers (Frankfurt) tokenized = blindfold.tokenize(user_message, policy="gdpr_eu") # → "Hallo, mein Name ist . Meine E-Mail ist # und meine IBAN ist . # Ich brauche Hilfe mit meiner Bestellung." # Step 2: Only anonymous tokens cross the border to OpenAI (US) completion = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "You are a helpful customer support agent."}, {"role": "user", "content": tokenized.text}, ], ) ai_response = completion.choices[0].message.content # Step 3: Restore real values for the human agent restored = blindfold.detokenize(ai_response, tokenized.mapping) print(restored.text) ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; import OpenAI from 'openai'; const blindfold = new Blindfold({ apiKey: 'your-key', region: 'eu' }); const openai = new OpenAI({ apiKey: 'your-openai-key' }); const userMessage = 'Hallo, mein Name ist Hans Mueller. Meine E-Mail ist ' + 'hans.mueller@example.de und meine IBAN ist DE89 3704 0044 0532 0130 00. ' + 'Ich brauche Hilfe mit meiner Bestellung.'; // Step 1: Tokenize PII on EU servers (Frankfurt) const tokenized = await blindfold.tokenize(userMessage, { policy: 'gdpr_eu' }); // Step 2: Only anonymous tokens cross the border to OpenAI (US) const completion = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [ { role: 'system', content: 'You are a helpful customer support agent.' }, { role: 'user', content: tokenized.text }, ], }); const aiResponse = completion.choices[0].message.content; // Step 3: Restore real values for the human agent const restored = await blindfold.detokenize(aiResponse, tokenized.mapping); console.log(restored.text); ``` ### US Data Residency for Healthcare Keep US patient data within US borders using the HIPAA policy: ```python Python theme={null} from blindfold import Blindfold from openai import OpenAI blindfold = Blindfold(api_key="your-key", region="us") openai_client = OpenAI(api_key="your-openai-key") patient_note = ( "Patient: Emily Johnson, DOB 03/15/1985, MRN 4567890. " "Diagnosed with Type 2 diabetes. Contact: emily.johnson@example.com, " "SSN 123-45-6789." ) # Tokenize PHI on US servers (Virginia) tokenized = blindfold.tokenize(patient_note, policy="hipaa_us") # → "Patient: , DOB , MRN . # Diagnosed with Type 2 diabetes. Contact: , # SSN ." # Safe to send to AI — no PHI exposed completion = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "You are a clinical documentation assistant."}, {"role": "user", "content": tokenized.text}, ], ) restored = blindfold.detokenize( completion.choices[0].message.content, tokenized.mapping, ) print(restored.text) ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; import OpenAI from 'openai'; const blindfold = new Blindfold({ apiKey: 'your-key', region: 'us' }); const openai = new OpenAI({ apiKey: 'your-openai-key' }); const patientNote = 'Patient: Emily Johnson, DOB 03/15/1985, MRN 4567890. ' + 'Diagnosed with Type 2 diabetes. Contact: emily.johnson@example.com, ' + 'SSN 123-45-6789.'; // Tokenize PHI on US servers (Virginia) const tokenized = await blindfold.tokenize(patientNote, { policy: 'hipaa_us' }); // Safe to send to AI — no PHI exposed const completion = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [ { role: 'system', content: 'You are a clinical documentation assistant.' }, { role: 'user', content: tokenized.text }, ], }); const restored = await blindfold.detokenize( completion.choices[0].message.content, tokenized.mapping, ); console.log(restored.text); ``` ### Cross-Border AI Without PII Exposure When you tokenize first, the data that crosses borders contains no personal information — making it compliant with any data residency regulation: ```python theme={null} from blindfold import Blindfold from openai import OpenAI blindfold = Blindfold(api_key="your-key", region="eu") openai_client = OpenAI(api_key="your-openai-key") # A Brazilian customer writes in Portuguese customer_message = ( "Olá, meu nome é Maria Silva, CPF 123.456.789-00, " "e-mail maria.silva@example.com.br. Preciso de ajuda com meu pedido." ) # Step 1: Tokenize in the EU region tokenized = blindfold.tokenize(customer_message, policy="gdpr_eu") # → "Olá, meu nome é , CPF , # e-mail . Preciso de ajuda com meu pedido." # Step 2: Send tokens to OpenAI (US) — no personal data crosses borders # is not Maria Silva. is not an email. # This is NOT a cross-border data transfer under LGPD or GDPR. completion = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[ { "role": "system", "content": "You are a customer support agent. Respond in Portuguese.", }, {"role": "user", "content": tokenized.text}, ], ) ai_response = completion.choices[0].message.content # Step 3: Restore real values — PII never left the EU restored = blindfold.detokenize(ai_response, tokenized.mapping) print(restored.text) ``` ## Tokenization as a Data Residency Strategy Tokenization fundamentally changes the data residency equation. When Blindfold replaces *Hans Mueller* with ``, the resulting token: * **Contains no personal data** — `` cannot be traced back to any individual without the mapping * **Is not subject to transfer restrictions** — under GDPR, anonymous data falls outside the regulation entirely (Recital 26) * **Can be sent anywhere globally** — to OpenAI in the US, Anthropic in the US, or any other provider in any jurisdiction The **mapping** (which links `` back to *Hans Mueller*) stays within Blindfold's regional infrastructure. When you use `region="eu"`, this mapping is processed and held in Frankfurt — never crossing borders. This means you can: * Use **any AI provider** regardless of where they are hosted * Avoid complex **Standard Contractual Clauses** for AI provider relationships * Reduce your **transfer impact assessment** scope — no personal data in the transfer means no assessment needed for that data flow * Stay compliant even if **adequacy decisions are revoked** (as happened with Privacy Shield) Tokenization as an anonymization strategy is supported by GDPR Recital 26, which states that the principles of data protection should not apply to anonymous information — information that does not relate to an identified or identifiable natural person. ## Data Residency Checklist Determine which data residency laws apply based on where your users are located — not where your company is incorporated. A German user's data is subject to GDPR regardless of whether your company is in the US. Select the Blindfold region that matches your compliance needs. Use `region="eu"` for EU/EEA users and LGPD-aligned processing. Use `region="us"` for US users and HIPAA workloads. Set the region in your SDK constructor so all PII processing happens in the correct jurisdiction: ```python theme={null} blindfold = Blindfold(api_key="your-key", region="eu") ``` Use the policy that matches the regulation: `gdpr_eu` for GDPR/LGPD, `hipaa_us` for HIPAA, or `pci_dss` for payment data. Policies ensure the right entity types are detected for each regulation. After your first API calls, check the audit trail in the [Blindfold Dashboard](https://app.blindfold.dev) to confirm requests are being processed in the expected region. Record how personal data enters your system, where it is tokenized, what crosses borders (only tokens), and where the mapping is held. This documentation is essential for GDPR Article 30 records and transfer impact assessments. When you launch in a new country, revisit your data residency strategy. New regulations may require a different region, a different policy, or additional tokenization steps. Check this page for updates as Blindfold adds new regions. # EU AI Act Compliance Source: https://docs.blindfold.dev/compliance/eu-ai-act Meet the world's first comprehensive AI regulation requirements The **EU AI Act** is the world's first comprehensive AI regulation, applying to any AI system that operates in the EU or affects EU citizens. It establishes requirements for data minimization, transparency, and documentation — with stricter rules for high-risk AI systems. Blindfold helps you comply by ensuring **personal data is removed from AI inputs**, providing an **audit trail** of all data processing, and supporting **EU data residency**. ## Timeline | Date | Milestone | | -------- | ------------------------------------------- | | Aug 2024 | EU AI Act enters into force | | Feb 2025 | Prohibited AI practices apply | | Aug 2025 | General-purpose AI rules + governance | | Aug 2026 | High-risk AI system obligations (Annex III) | | Aug 2027 | Full enforcement for all AI systems | ## Risk Categories The EU AI Act classifies AI systems by risk level: **Banned.** Social scoring, real-time biometric surveillance, manipulative AI. These systems are prohibited. **Strict requirements.** AI in healthcare, finance, HR, education, law enforcement. Must meet transparency, documentation, and data governance standards. **Transparency obligations.** Chatbots, AI-generated content. Must disclose AI involvement to users. **No requirements.** Spam filters, AI in games. Most AI applications fall here. ## Key Requirements for AI Systems **Requirement**: Training and input data must be relevant, representative, and limited to what is necessary. **Risk**: Sending full user conversations to LLMs includes far more personal data than necessary for the AI task. **With Blindfold**: Tokenize PII before AI calls. The LLM receives only the information needed for its task — personal identifiers are replaced with anonymous tokens. ```python theme={null} # Data minimization: only anonymized context reaches the AI tokenized = blindfold.tokenize(user_message, policy="gdpr_eu") response = openai.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": tokenized.text}], ) ``` **Requirement**: AI systems must be transparent about how they process data. Users must be informed when interacting with AI. **With Blindfold**: Audit logs document exactly what personal data was detected, what was anonymized, and what was sent to the AI provider. This creates a clear record for transparency requirements. **Requirement**: High-risk AI systems must maintain technical documentation and log all operations. **With Blindfold**: Every API call is logged with entity types detected, policy used, timestamp, and region. Export these logs for regulatory documentation. **Requirement**: Data used in AI systems must meet quality, relevance, and privacy standards. **With Blindfold**: The `detect()` method lets you audit text for personal data without modifying it — useful for data governance reviews and quality checks. ```python theme={null} # Audit data for PII without modifying it detection = blindfold.detect(training_data) for entity in detection.detected_entities: print(f"Found {entity.type}: {entity.text}") ``` **Requirement**: High-risk AI systems must allow human oversight and intervention. **With Blindfold**: Tokenization is reversible — humans can always see the real data via `detokenize()`, while the AI only works with anonymized versions. This maintains human oversight of the actual information. ## How Blindfold Maps to the EU AI Act | AI Act Requirement | Article | Blindfold Feature | | ------------------------- | ---------- | --------------------------------------------- | | Data minimization | Art. 10 | `tokenize()` removes PII before AI input | | Transparency | Art. 13 | Audit logs document all PII processing | | Documentation | Art. 11-12 | Export audit logs for regulatory records | | Data governance | Art. 10 | `detect()` audits data for PII | | Human oversight | Art. 14 | `detokenize()` restores data for human review | | Data protection by design | Art. 10 | SDK-level PII protection in your pipeline | ## High-Risk AI Systems The EU AI Act imposes stricter requirements on AI systems in these domains: **AI Act Classification**: High-risk (Annex III, Section 5) **Requirements**: Robust data governance, thorough testing, documentation of training data, continuous monitoring. **Blindfold Approach**: * Use `region="us"` or `region="eu"` depending on patient location * Apply `hipaa_us` (US patients) or `gdpr_eu` (EU patients) policy * Tokenize all PHI before clinical AI tools * Maintain audit trail for regulatory inspections See [HIPAA Compliance](/compliance/hipaa) for healthcare-specific guidance. **AI Act Classification**: High-risk (Annex III, Section 5) **Requirements**: Transparency in AI-driven credit scoring, fraud detection, and insurance underwriting. Data quality and bias monitoring. **Blindfold Approach**: * Apply `pci_dss` policy for payment data * Apply `gdpr_eu` policy for customer personal data * Redact financial PII from AI training datasets * Encrypt customer data at rest See [PCI DSS Compliance](/compliance/pci-dss) for payment-specific guidance. **AI Act Classification**: High-risk (Annex III, Section 4) **Requirements**: AI used in recruitment, performance evaluation, or workforce management must be transparent, unbiased, and documented. **Blindfold Approach**: * Apply `gdpr_eu` policy to anonymize candidate data * Tokenize before AI screening tools to prevent bias on names/addresses * Maintain audit trail of all AI-assisted HR decisions * Redact PII from aggregated workforce analytics **AI Act Classification**: High-risk (Annex III, Section 3) **Requirements**: AI in education (grading, admissions, learning analytics) must be transparent and fair. **Blindfold Approach**: * Tokenize student PII before AI grading or analytics * Apply `gdpr_eu` policy for EU student data * Maintain audit trail for fairness reviews ## Code Examples ### Data Minimization for AI Calls ```python theme={null} from blindfold import Blindfold from openai import OpenAI blindfold = Blindfold(api_key="your-key", region="eu") openai_client = OpenAI(api_key="your-openai-key") # Customer support message with personal data message = ( "Hi, I'm Marie Dupont (marie.dupont@example.fr). " "I was charged twice on 02/10/2026 for order #12345." ) # Remove personal data before AI processing (data minimization) tokenized = blindfold.tokenize(message, policy="gdpr_eu") # → "Hi, I'm (). # I was charged twice on 02/10/2026 for order #12345." # AI only processes what it needs — no real personal data completion = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": tokenized.text}], ) # Restore for the human agent restored = blindfold.detokenize( completion.choices[0].message.content, tokenized.mapping, ) ``` ### Audit Data for PII (Data Governance) Use `detect()` to check datasets for personal data without modifying them: ```python theme={null} # Audit training data for PII before using in AI systems training_samples = [ "Customer feedback: Great service from the team!", "John Smith at john@example.com reported a bug on 02/15.", "Order #98765 shipped to Berlin on schedule.", ] for sample in training_samples: detection = blindfold.detect(sample, policy="gdpr_eu") if detection.entities_count > 0: print(f"PII found in: {sample[:50]}...") for entity in detection.detected_entities: print(f" - {entity.type}: {entity.text}") ``` ## Relationship with GDPR The EU AI Act and GDPR are complementary: | Aspect | GDPR | EU AI Act | | --------------------- | ---------------------------- | ----------------------------------- | | **Focus** | Personal data protection | AI system safety and transparency | | **Scope** | Any personal data processing | AI systems operating in the EU | | **Data requirements** | Minimize collection | Minimize AI inputs + ensure quality | | **Documentation** | Processing records (Art. 30) | Technical documentation (Art. 11) | | **Oversight** | Data Protection Officers | AI governance structures | **Using Blindfold for both**: Apply the `gdpr_eu` policy with the EU region to satisfy both regulations simultaneously. GDPR protects the personal data, while the audit trail satisfies AI Act transparency requirements. ## EU AI Act Compliance Checklist Determine if your AI system is high-risk, limited-risk, or minimal-risk under the EU AI Act. Use `blindfold.tokenize()` to remove personal data before AI processing. Set `region="eu"` for data processed in Europe — required for GDPR alignment. Use Blindfold's audit trail to document what PII was detected and anonymized. Use `blindfold.detect()` to scan training datasets for personal data. Record how data flows through your system, where PII is detected, and how it's protected. As the EU AI Act phases in (through 2027), review your compliance posture with each milestone. # GDPR Compliance Source: https://docs.blindfold.dev/compliance/gdpr How to process EU personal data through AI models while staying GDPR-compliant The **General Data Protection Regulation** (GDPR) applies to all EU/EEA residents' data, regardless of where your company is located. When you send personal data to AI providers like OpenAI or Anthropic, you're transferring it to a third-party processor — often outside the EU. Blindfold solves this by **tokenizing personal data in the EU region** before it reaches any AI provider. The LLM only sees anonymized tokens like `` — never real names, emails, or addresses. ## Key GDPR Requirements for AI Applications **Requirement**: Only process the minimum personal data necessary for the purpose. **Risk with AI**: Sending full user messages to an LLM means the AI provider processes *all* personal data in the text — far more than necessary. **With Blindfold**: PII is replaced with tokens before the AI call. The LLM only receives what it needs to generate a useful response, without real personal data. **Requirement**: Data collected for one purpose must not be used for another. **Risk with AI**: AI providers may log, train on, or analyze the personal data you send them. **With Blindfold**: Since only tokens reach the AI provider, there's no real personal data to repurpose. **Requirement**: Personal data transfers outside the EU/EEA require adequate safeguards (Schrems II ruling). **Risk with AI**: Most LLM providers (OpenAI, Anthropic) process data in the US, triggering Chapter V transfer rules. **With Blindfold**: Use the EU region (`region="eu"`) — PII is tokenized on EU servers. Only anonymized tokens cross borders, which are no longer personal data under GDPR. **Requirement**: Data subjects can request deletion of their personal data. **Risk with AI**: Data sent to AI providers may be retained in their logs and training data — deletion is impossible. **With Blindfold**: No real personal data reaches the AI provider. For your own records, use `redact()` to permanently remove PII. **Requirement**: Formal agreements must exist between data controllers and processors. **With Blindfold**: Since tokenized data is no longer personal data, your DPA requirements with AI providers are simplified. Blindfold offers its own DPA — contact [hello@blindfold.dev](mailto:hello@blindfold.dev). ## How Blindfold Maps to GDPR | GDPR Article | Requirement | Blindfold Feature | | ------------ | ------------------------- | ----------------------------------------- | | Art. 5(1)(c) | Data minimization | Tokenization removes PII before AI calls | | Art. 5(1)(b) | Purpose limitation | AI provider never receives real data | | Art. 17 | Right to erasure | `redact()` permanently removes PII | | Art. 25 | Data protection by design | SDK-level PII protection in your pipeline | | Art. 30 | Records of processing | Audit logs track all PII operations | | Art. 32 | Security of processing | `encrypt()` with AES-256 for storage | | Art. 44-49 | Cross-border transfers | EU region ensures PII stays in Europe | ## EU Region + `gdpr_eu` Policy ### Region Selection Use the EU region to ensure personal data is processed on EU-based servers: ```python Python theme={null} from blindfold import Blindfold client = Blindfold( api_key="your-api-key", region="eu", # PII processed in the EU ) ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key', region: 'eu', // PII processed in the EU }); ``` ### What `gdpr_eu` Detects The `gdpr_eu` policy covers all GDPR Article 4(1) personal data types: | Entity Type | Examples | | ----------------------- | --------------------------------------------------------- | | Person | Hans Mueller, Marie Dupont | | Email Address | [hans.mueller@example.de](mailto:hans.mueller@example.de) | | Phone Number | +49 170 1234567 | | Address | Berliner Str. 42, 10115 Berlin | | IBAN | DE89 3704 0044 0532 0130 00 | | National ID Number | Country-specific national IDs | | Passport Number | C01X00T47 | | Tax ID | Country-specific tax identifiers | | Date of Birth | 15/03/1985 | | Credit Card Number | 4532-7562-9102-3456 | | Bank Account Number | Account numbers | | IP Address | 192.168.1.100 | | Health Insurance Number | Insurance identifiers | | Medical Condition | Diagnoses, symptoms | ## Code Examples ### Tokenize Before Sending to OpenAI The most common pattern: protect EU user data before any AI API call. ```python Python theme={null} from blindfold import Blindfold from openai import OpenAI blindfold = Blindfold(api_key="your-key", region="eu") openai = OpenAI(api_key="your-openai-key") user_message = ( "Hi, my name is Hans Mueller and I need help with my subscription. " "My email is hans.mueller@example.de, IBAN DE89 3704 0044 0532 0130 00." ) # Step 1: Tokenize PII in the EU tokenized = blindfold.tokenize(user_message, policy="gdpr_eu") # → "Hi, my name is and I need help with my subscription. # My email is , IBAN ." # Step 2: Send only tokens to OpenAI completion = openai.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": tokenized.text}], ) ai_response = completion.choices[0].message.content # Step 3: Restore real values in the response restored = blindfold.detokenize(ai_response, tokenized.mapping) print(restored.text) ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; import OpenAI from 'openai'; const blindfold = new Blindfold({ apiKey: 'your-key', region: 'eu' }); const openai = new OpenAI({ apiKey: 'your-openai-key' }); const userMessage = 'Hi, my name is Hans Mueller. My email is hans.mueller@example.de, ' + 'IBAN DE89 3704 0044 0532 0130 00.'; // Step 1: Tokenize PII in the EU const tokenized = await blindfold.tokenize(userMessage, { policy: 'gdpr_eu' }); // Step 2: Send only tokens to OpenAI const completion = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [{ role: 'user', content: tokenized.text }], }); const aiResponse = completion.choices[0].message.content; // Step 3: Restore real values const restored = await blindfold.detokenize(aiResponse, tokenized.mapping); console.log(restored.text); ``` ### Right to be Forgotten (Article 17) When a data subject requests deletion, use `redact()` to permanently remove their PII: ```python theme={null} # User requests data deletion under GDPR Art. 17 user_records = fetch_user_records(user_id) for record in user_records: redacted = blindfold.redact(record.content, policy="gdpr_eu") update_record(record.id, redacted.text) # "Hans Mueller emailed about billing" # → "[REDACTED] emailed about billing" # PII permanently removed — compliant with Right to be Forgotten ``` ### Batch Processing Support Tickets Process multiple EU support tickets in a single API call: ```python theme={null} tickets = [ "Customer Marie Dupont (marie.dupont@example.fr) reports billing issue.", "Jan Novak (jan.novak@example.cz) requests data export under GDPR Art. 15.", "Sofia Garcia, sofia.garcia@example.es, cannot access her account.", ] # Tokenize all tickets at once batch = blindfold.tokenize_batch(tickets, policy="gdpr_eu") for i, result in enumerate(batch.results): print(f"Ticket {i+1}: {result['text']}") print(f" PII removed: {result['entities_count']} entities") ``` ## Data Residency When you use `region="eu"`: * **Processing**: PII detection runs on EU-based servers at `eu-api.blindfold.dev` * **No cross-border transfer**: Personal data never leaves the EU during processing * **Tokens are not personal data**: The anonymized output (``) can safely cross borders * **Your API key works globally**: No separate keys needed per region See [Regions](/essentials/regions) for full details on data residency. ## Audit Trail for DPAs Every Blindfold API call is logged in your audit trail, providing documentation for Data Processing Agreements: * **What was detected**: Entity types and counts per request * **When**: Timestamp of every PII operation * **Which policy**: The detection policy used * **Processing region**: EU or US Export audit logs from the [Blindfold Dashboard](https://app.blindfold.dev) for DPA compliance reviews. ## Cookbook Example For a complete, runnable GDPR + OpenAI integration, see the cookbook: Full working example with EU region, `gdpr_eu` policy, single queries, and batch ticket processing. ## GDPR Compliance Checklist Use this checklist when integrating Blindfold for GDPR compliance: Set `region="eu"` in your SDK client to ensure PII is processed in Europe. Use `policy="gdpr_eu"` on all tokenize/redact/encrypt calls handling EU data. Always call `blindfold.tokenize()` before sending text to any LLM provider. Use `blindfold.redact()` to permanently remove PII when data subjects request deletion. Contact [hello@blindfold.dev](mailto:hello@blindfold.dev) to sign a Data Processing Agreement. Export audit logs from the dashboard for compliance documentation. Record where PII enters your system, how it's protected, and where anonymized data is sent. # HIPAA Compliance Source: https://docs.blindfold.dev/compliance/hipaa Protect PHI in healthcare AI applications with US data residency The **Health Insurance Portability and Accountability Act** (HIPAA) protects medical information in the United States. Any AI application that processes Protected Health Information (PHI) must comply with HIPAA's Privacy and Security Rules. Blindfold helps by **tokenizing PHI in the US region** before it reaches any AI provider. The LLM only sees anonymized tokens — never real patient names, SSNs, or medical records. ## Who Must Comply Healthcare providers, health plans, and healthcare clearinghouses that transmit health information electronically. Any organization that creates, receives, maintains, or transmits PHI on behalf of a covered entity — including AI/software vendors. If your AI application processes patient data for a healthcare organization, HIPAA likely applies to you. ## The 18 HIPAA Identifiers HIPAA's Safe Harbor method (45 CFR § 164.514(b)(2)) requires removal of 18 types of identifiers for de-identification. Blindfold's `hipaa_us` policy covers them: | # | Identifier | Blindfold Entity Type | Covered | | -- | -------------------------------------------- | -------------------------- | ------------------- | | 1 | Names | Person | ✅ | | 2 | Geographic subdivisions (smaller than state) | Address | ✅ | | 3 | Dates (except year) related to individual | Date of Birth | ✅ | | 4 | Phone numbers | Phone Number | ✅ | | 5 | Fax numbers | Phone Number | ✅ | | 6 | Email addresses | Email Address | ✅ | | 7 | Social Security Numbers | Social Security Number | ✅ | | 8 | Medical Record Numbers | Medical Record Number | ✅ | | 9 | Health plan beneficiary numbers | Health Insurance ID Number | ✅ | | 10 | Account numbers | Bank Account Number | ✅ | | 11 | Certificate/license numbers | License Number | ✅ | | 12 | Vehicle identifiers | Vehicle ID | ✅ | | 13 | Device identifiers | Device ID | ✅ | | 14 | Web URLs | URL | ✅ | | 15 | IP addresses | IP Address | ✅ | | 16 | Biometric identifiers | Biometric Data | ✅ | | 17 | Full-face photographs | — | N/A (text-only API) | | 18 | Any other unique identifying number | Custom entities | ✅ | ## How Blindfold Helps ### Minimum Necessary Rule HIPAA requires that only the **minimum necessary** PHI is used for any given purpose. With Blindfold: ``` Patient Data Blindfold US Region AI Provider "Patient Sarah Johnson, ", AI sees only SSN 123-45-6789, → , → anonymized tokens MRN P-4532..." ..." ↓ "Patient Sarah Johnson ← Detokenize with mapping ← "Patient is a 47-year-old..." (PHI stays in US) is a 47-year-old..." ``` ### Safe Harbor De-Identification Blindfold's tokenization satisfies the Safe Harbor method by removing all 18 identifier types. The tokenized output is considered **de-identified data** under HIPAA, which is no longer subject to the Privacy Rule. ## US Region + `hipaa_us` Policy ### Region Selection Use the US region to ensure PHI is processed on US-based servers: ```python Python theme={null} from blindfold import Blindfold client = Blindfold( api_key="your-api-key", region="us", # PHI processed in the US ) ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key', region: 'us', // PHI processed in the US }); ``` ### What `hipaa_us` Detects | Entity Type | Examples | | -------------------------- | --------------------------------------------------------- | | Person | Sarah Johnson, Dr. Emily Chen | | Social Security Number | 123-45-6789 | | Medical Record Number | P-4532, MRN-78901 | | Health Insurance ID Number | BC-9876543 | | Date of Birth | 03/15/1978 | | Email Address | [sarah.johnson@email.com](mailto:sarah.johnson@email.com) | | Phone Number | (555) 234-5678 | | Address | 123 Oak Street, Springfield | | Medical Condition | chest pain, diabetes, hypertension | | Medication | metformin, lisinopril | | Insurance Company | BlueCross, Aetna | ## Code Examples ### Tokenize a Patient Record ```python Python theme={null} from blindfold import Blindfold from openai import OpenAI blindfold = Blindfold(api_key="your-key", region="us") openai_client = OpenAI(api_key="your-openai-key") patient_message = ( "Patient Sarah Johnson (DOB 03/15/1978, SSN 123-45-6789, " "MRN P-4532) presented with chest pain. " "Contact: sarah.johnson@email.com, phone (555) 234-5678." ) # Step 1: Tokenize PHI tokenized = blindfold.tokenize(patient_message, policy="hipaa_us") print(f"PHI detected: {tokenized.entities_count} identifiers") for entity in tokenized.detected_entities: print(f" [{entity.type}] {entity.text}") # Step 2: Send to OpenAI — only anonymized tokens completion = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "You are a healthcare records assistant."}, {"role": "user", "content": tokenized.text}, ], ) # Step 3: Restore PHI in the response restored = blindfold.detokenize( completion.choices[0].message.content, tokenized.mapping, ) print(restored.text) ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; import OpenAI from 'openai'; const blindfold = new Blindfold({ apiKey: 'your-key', region: 'us' }); const openai = new OpenAI({ apiKey: 'your-openai-key' }); const patientMessage = 'Patient Sarah Johnson (DOB 03/15/1978, SSN 123-45-6789, ' + 'MRN P-4532) presented with chest pain. ' + 'Contact: sarah.johnson@email.com, phone (555) 234-5678.'; // Step 1: Tokenize PHI const tokenized = await blindfold.tokenize(patientMessage, { policy: 'hipaa_us', }); // Step 2: Send to OpenAI const completion = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [ { role: 'system', content: 'You are a healthcare records assistant.' }, { role: 'user', content: tokenized.text }, ], }); // Step 3: Restore PHI const restored = await blindfold.detokenize( completion.choices[0].message.content, tokenized.mapping, ); console.log(restored.text); ``` ### Multi-Turn PHI-Safe Conversation Maintain PHI mappings across a multi-turn healthcare chat: ```python theme={null} class HealthcareChatbot: def __init__(self): self.blindfold = Blindfold(api_key="your-key", region="us") self.openai = OpenAI(api_key="your-openai-key") self.conversation = [ {"role": "system", "content": "You are a healthcare assistant."} ] self.mapping = {} # Accumulated across turns def chat(self, user_message: str) -> str: # Tokenize new message tokenized = self.blindfold.tokenize(user_message, policy="hipaa_us") # Merge new mappings into conversation-wide mapping self.mapping.update(tokenized.mapping) # Add tokenized message to conversation self.conversation.append({"role": "user", "content": tokenized.text}) # Send to AI — only tokens completion = self.openai.chat.completions.create( model="gpt-4o-mini", messages=self.conversation, ) ai_response = completion.choices[0].message.content self.conversation.append({"role": "assistant", "content": ai_response}) # Restore PHI for display restored = self.blindfold.detokenize(ai_response, self.mapping) return restored.text ``` ### Batch PHI Redaction Permanently remove PHI from multiple records for safe storage or logging: ```python theme={null} records = [ "Patient: Robert Lee, SSN 111-22-3333, admitted for knee surgery.", "Patient: Maria Santos, DOB 11/05/1990, MRN P-2468. Allergy to penicillin.", "Patient: David Kim, SSN 444-55-6666, referred by Dr. Amanda Torres.", ] # Redact all records in one call (irreversible) batch = blindfold.redact_batch(records, policy="hipaa_us") for i, result in enumerate(batch.results): print(f"Record {i+1}: {result['text']}") print(f" PHI removed: {result['entities_count']} identifiers") ``` ## Three Modes of PHI Protection | Mode | Method | Reversible | Use Case | | ------------ | ---------------------- | -------------- | ------------------------------------------------- | | **Tokenize** | `blindfold.tokenize()` | Yes | AI chat, summarization — restore PHI in responses | | **Redact** | `blindfold.redact()` | No | Logs, storage — permanently remove PHI | | **Encrypt** | `blindfold.encrypt()` | Yes (with key) | Secure archives — AES-256 encrypted PHI storage | ```python Tokenize (for AI) theme={null} # Reversible — PHI can be restored tokenized = blindfold.tokenize(text, policy="hipaa_us") # → "Patient (SSN )" restored = blindfold.detokenize(response, tokenized.mapping) ``` ```python Redact (for logs) theme={null} # Permanent removal — PHI cannot be recovered redacted = blindfold.redact(text, policy="hipaa_us") # → "Patient [REDACTED] (SSN [REDACTED])" ``` ```python Encrypt (for storage) theme={null} # Reversible with encryption key encrypted = blindfold.encrypt(text, encryption_key="your-key") # → "Patient aGVsbG8... (SSN dGVzdA...)" decrypted = blindfold.decrypt(encrypted.text, encryption_key="your-key") ``` ## Audit Trail Every Blindfold API call is logged, supporting HIPAA's audit requirements (45 CFR § 164.312(b)): * **Who**: Which API key made the request * **What**: Entity types detected and count * **When**: Timestamp of every PHI operation * **Where**: Processing region (US) * **How**: Which privacy method and policy was used Export audit logs from the [Blindfold Dashboard](https://app.blindfold.dev). ## BAA Readiness Blindfold is ready to sign a **Business Associate Agreement** (BAA) with covered entities and their business associates. A BAA is required under HIPAA when a third party handles PHI. Contact us at **[hello@blindfold.dev](mailto:hello@blindfold.dev)** to request a BAA. ## Cookbook Example For a complete, runnable HIPAA healthcare chatbot, see the cookbook: Full working example with US region, `hipaa_us` policy, single queries, multi-turn chat, and batch redaction. ## HIPAA Compliance Checklist Set `region="us"` to ensure PHI is processed within the United States. Use `policy="hipaa_us"` on all calls handling patient data. Always call `blindfold.tokenize()` before sending PHI to any AI provider. Use `blindfold.redact()` to remove PHI from application logs and audit records. Use `blindfold.encrypt()` for PHI stored in databases or file systems. Contact [hello@blindfold.dev](mailto:hello@blindfold.dev) to execute a Business Associate Agreement. Use separate API keys for different applications and teams. Regularly export and review audit logs from the dashboard. # LGPD Compliance Source: https://docs.blindfold.dev/compliance/lgpd Protect Brazilian personal data in AI applications The **Lei Geral de Protecao de Dados** (LGPD, Law No. 13,709/2018) is Brazil's comprehensive data protection law, in effect since September 2020. Enforced by the **ANPD** (Autoridade Nacional de Protecao de Dados), LGPD regulates how organizations collect, process, store, and share personal data of individuals in Brazil. When your AI application processes personal data of individuals located in Brazil, LGPD applies. Blindfold helps by **tokenizing personal data before it reaches any AI provider**. The LLM only sees anonymized tokens like `` — never real names, CPFs, or addresses. ## Who Must Comply LGPD applies to: * **Any organization** processing personal data of individuals located in Brazil * **Regardless of where the organization is headquartered** — a US or EU company processing Brazilian data must comply * When **data processing occurs in Brazil**, when **data subjects are in Brazil**, or when **data was collected in Brazil** LGPD applies extraterritorially — your company doesn't need to be in Brazil. If you process personal data of individuals in Brazil, you must comply. ## Key LGPD Requirements **Requirement**: Personal data processing requires one of 10 legal bases — more than GDPR's 6. These include consent, legitimate interest, contract performance, legal obligation, research, exercise of rights, health protection, credit protection, and public administration. **Risk with AI**: Sending personal data to AI providers may lack a clear legal basis, especially when data is used for model training or analytics by the provider. **With Blindfold**: Since only anonymized tokens reach the AI provider, the legal basis question for the AI provider's processing is simplified — tokens are not personal data. **Requirement**: Data subjects have the right to confirmation of processing, access, correction, anonymization of unnecessary data, deletion, data portability, information about third-party sharing, and information about denying consent. **With Blindfold**: Use `tokenize()` for anonymization, `redact()` for deletion, and `detect()` to identify what personal data exists. Audit logs document all processing activities for access requests. **Requirement**: Personal data may only be transferred to countries with adequate protection levels, or with specific guarantees such as Standard Contractual Clauses, binding corporate rules, or specific consent from the data subject. **Risk with AI**: Most AI providers (OpenAI, Anthropic) process data in the US, which may not meet LGPD adequacy requirements. **With Blindfold**: Use the EU region (`region="eu"`) — PII is tokenized before crossing borders. Only anonymized tokens reach the AI provider, which are no longer personal data under LGPD. **Requirement**: The ANPD may require a Data Protection Impact Assessment (DPIA / RIPD) when processing activities may create risks to data subjects' fundamental rights and freedoms. **With Blindfold**: Blindfold's audit trail documents all PII detection and anonymization, providing evidence for your DPIA that personal data is protected before AI processing. **Requirement**: Organizations must appoint a DPO (Encarregado) whose identity and contact information must be publicly disclosed. The Encarregado handles data subject requests, advises on data protection practices, and communicates with the ANPD. **With Blindfold**: Audit logs and processing records from Blindfold support the DPO's oversight responsibilities by documenting how personal data is protected in AI workflows. ## LGPD vs GDPR LGPD is closely modeled on the EU's GDPR, but there are important differences: | Aspect | LGPD | GDPR | | -------------------------- | --------------------------------------- | ---------------------------- | | Legal bases for processing | 10 | 6 | | Supervisory authority | ANPD | National DPAs | | Maximum fines | 2% of revenue, max R\$50M per violation | 4% of revenue or EUR 20M | | DPO required | Yes (all organizations) | Conditional (specific cases) | | Cross-border transfers | Adequacy + guarantees | Adequacy + SCCs | | Effective date | September 2020 | May 2018 | ## How Blindfold Maps to LGPD | LGPD Article | Requirement | Blindfold Feature | | ------------ | ------------------------- | ------------------------------------------ | | Art. 6 (III) | Data minimization | Tokenization removes PII before AI calls | | Art. 7 | Legal basis documentation | Audit logs track all processing activities | | Art. 12 | Anonymization | `tokenize()`, `hash()`, `redact()` | | Art. 18 (IV) | Right to anonymization | `tokenize()` + delete mapping | | Art. 33 | International transfers | EU region + tokenization | | Art. 46 | Security measures | AES-256 encryption, access controls | ## EU Region for LGPD Since LGPD is closely modeled on GDPR, using Blindfold's EU region with the `gdpr_eu` policy provides excellent coverage for LGPD requirements. The `gdpr_eu` policy detects entity types relevant to both European and Brazilian personal data. Brazil's LGPD is closely aligned with GDPR. The `gdpr_eu` policy covers the entity types needed for LGPD compliance. ```python Python theme={null} from blindfold import Blindfold client = Blindfold( api_key="your-api-key", region="eu", # Recommended for LGPD compliance ) ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key', region: 'eu', // Recommended for LGPD compliance }); ``` ## `gdpr_eu` Policy Coverage for LGPD | Entity Type | LGPD Category | Examples | | -------------------- | ------------------ | --------------------------------------------------------------- | | Person | Nome (Name) | Maria Silva, Joao Santos | | Email Address | Email | [maria.silva@example.com.br](mailto:maria.silva@example.com.br) | | Phone Number | Telefone | +55 11 98765-4321 | | Location | Endereco | Sao Paulo, Rua Augusta 123 | | Date of Birth | Data de nascimento | 15/03/1990 | | US SSN / National ID | CPF | 123.456.789-09 | | Credit Card Number | Cartao de credito | 4532-7562-9102-3456 | | IBAN | Conta bancaria | BR15 0000 0000 0000 1093 2840 814 P2 | | IP Address | Endereco IP | 189.6.45.123 | | Organization | Empresa | Empresa XYZ Ltda | ## Code Examples ### Tokenize Brazilian Personal Data The most common pattern: protect Brazilian user data before any AI API call. ```python Python theme={null} from blindfold import Blindfold from openai import OpenAI blindfold = Blindfold(api_key="your-key", region="eu") openai_client = OpenAI(api_key="your-openai-key") user_message = ( "Ola, meu nome e Maria Silva e preciso de ajuda com minha assinatura. " "Meu email e maria.silva@example.com.br, CPF 123.456.789-09, " "telefone +55 11 98765-4321." ) # Step 1: Tokenize PII with gdpr_eu policy tokenized = blindfold.tokenize(user_message, policy="gdpr_eu") # → "Ola, meu nome e e preciso de ajuda com minha assinatura. # Meu email e , CPF , # telefone ." # Step 2: Send only tokens to OpenAI completion = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": tokenized.text}], ) ai_response = completion.choices[0].message.content # Step 3: Restore real values in the response restored = blindfold.detokenize(ai_response, tokenized.mapping) print(restored.text) ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; import OpenAI from 'openai'; const blindfold = new Blindfold({ apiKey: 'your-key', region: 'eu' }); const openai = new OpenAI({ apiKey: 'your-openai-key' }); const userMessage = 'Ola, meu nome e Maria Silva e preciso de ajuda com minha assinatura. ' + 'Meu email e maria.silva@example.com.br, CPF 123.456.789-09, ' + 'telefone +55 11 98765-4321.'; // Step 1: Tokenize PII with gdpr_eu policy const tokenized = await blindfold.tokenize(userMessage, { policy: 'gdpr_eu' }); // Step 2: Send only tokens to OpenAI const completion = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [{ role: 'user', content: tokenized.text }], }); const aiResponse = completion.choices[0].message.content; // Step 3: Restore real values const restored = await blindfold.detokenize(aiResponse, tokenized.mapping); console.log(restored.text); ``` ### Anonymize for LGPD Art. 12 Use `hash()` to irreversibly anonymize personal data for analytics or research — satisfying LGPD's anonymization requirements: ```python Python theme={null} from blindfold import Blindfold blindfold = Blindfold(api_key="your-key", region="eu") customer_record = ( "Cliente: Joao Santos, email joao.santos@example.com.br, " "CPF 987.654.321-00, endereco Rua Augusta 123, Sao Paulo." ) # Hash PII — irreversible anonymization (Art. 12) hashed = blindfold.hash(customer_record, policy="gdpr_eu") # PII replaced with one-way hashes — cannot be reversed # Safe for analytics, research, and aggregate reporting print(hashed.text) ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; const blindfold = new Blindfold({ apiKey: 'your-key', region: 'eu' }); const customerRecord = 'Cliente: Joao Santos, email joao.santos@example.com.br, ' + 'CPF 987.654.321-00, endereco Rua Augusta 123, Sao Paulo.'; // Hash PII — irreversible anonymization (Art. 12) const hashed = await blindfold.hash(customerRecord, { policy: 'gdpr_eu' }); // PII replaced with one-way hashes — cannot be reversed // Safe for analytics, research, and aggregate reporting console.log(hashed.text); ``` ### Right to Anonymization (Art. 18) When a data subject exercises their right to anonymization under Art. 18(IV), tokenize their data and then delete the mapping to make anonymization permanent: ```python theme={null} from blindfold import Blindfold blindfold = Blindfold(api_key="your-key", region="eu") # Data subject requests anonymization under LGPD Art. 18(IV) user_records = fetch_user_records(user_id) for record in user_records: # Step 1: Tokenize the record tokenized = blindfold.tokenize(record.content, policy="gdpr_eu") # Step 2: Store only the tokenized text (discard the mapping) update_record(record.id, tokenized.text) # "Maria Silva emailed about billing from Sao Paulo" # → " emailed about billing from " # Mapping is never stored — anonymization is permanent # The original PII cannot be recovered # Data subject's personal data is now permanently anonymized ``` ## Benefits for LGPD Compliance | Benefit | Details | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | **No international data transfer risk** | Tokens are not personal data — they can safely cross borders without triggering Art. 33 transfer restrictions | | **Data minimization** | Art. 6(III) satisfied automatically — AI providers only receive anonymized tokens | | **Audit trail** | Art. 37 record of processing activities — every PII operation is logged with timestamps, entity types, and policies | | **Anonymization** | Art. 12 compliance through tokenization and hashing — data subjects' right to anonymization is supported | ## LGPD Compliance Checklist Determine if your AI application processes personal data of individuals in Brazil. LGPD applies regardless of where your organization is located. Set `region="eu"` in your SDK client. The EU region provides data residency aligned with LGPD requirements. Use `policy="gdpr_eu"` on all tokenize, redact, encrypt, and hash calls handling Brazilian personal data. Always call `blindfold.tokenize()` before sending text to any LLM provider. This ensures no real personal data reaches third parties. Export audit logs from the [Blindfold Dashboard](https://app.blindfold.dev) to document your processing activities as required by Art. 37. Use `detect()` for access requests, `redact()` for deletion, `hash()` for irreversible anonymization, and `tokenize()` with discarded mappings for right to anonymization. Designate an Encarregado, publicly disclose their contact information, and document your data flows including how Blindfold protects personal data in AI workflows. LGPD is evolving — the ANPD continues to issue new regulations and guidance. Review your compliance posture regularly as new ANPD resolutions are published. *** **Disclaimer**: This documentation provides general information about LGPD compliance requirements. It is not legal advice. Consult with legal counsel familiar with Brazilian data protection law to ensure your specific implementation meets all applicable requirements. # PCI DSS Compliance Source: https://docs.blindfold.dev/compliance/pci-dss Protect cardholder data in AI-powered payment applications The **Payment Card Industry Data Security Standard** (PCI DSS) is mandatory for any organization that stores, processes, or transmits credit card data. If your AI application handles payment information — even in free-text customer messages — PCI DSS applies. Blindfold's `pci_dss` policy automatically detects and protects cardholder data before it reaches AI providers, reducing your PCI scope. ## Who Must Comply PCI DSS applies to: * **Merchants** that accept card payments * **Service providers** that store, process, or transmit cardholder data * **Any AI application** that processes text containing card numbers, CVVs, or expiry dates If a customer pastes a credit card number into your AI chatbot, your application is processing cardholder data — even if you didn't ask for it. ## Key PCI DSS Requirements | Requirement | Description | Blindfold Solution | | ----------- | ---------------------------------- | --------------------------------- | | **Req 3** | Protect stored cardholder data | `encrypt()` with AES-256 | | **Req 3.3** | Mask PAN when displayed | `mask()` shows only last 4 digits | | **Req 3.4** | Render PAN unreadable in storage | `encrypt()` or `hash()` | | **Req 7** | Restrict access to cardholder data | Separate API keys per application | | **Req 10** | Track and monitor all access | Audit logs for every operation | | **Req 12** | Maintain a security policy | Policy-based detection rules | ## `pci_dss` Policy The `pci_dss` policy detects payment-related sensitive data: | Entity Type | Examples | | ---------------------- | --------------------------- | | Credit Card Number | 4532-7562-9102-3456 | | Credit Card Expiration | 12/25, 03/2027 | | CVV / CVC | 123, 4567 | | Credit Card Brand | Visa, Mastercard, Amex | | Bank Account Number | 1234567890 | | IBAN | DE89 3704 0044 0532 0130 00 | | Person | Cardholder name | | Email Address | Contact email | ## Code Examples ### Mask Card Numbers for Display (Req 3.3) PCI DSS requires that PANs are masked when displayed, showing at most the first 6 and last 4 digits: ```python Python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-key") text = "Customer card: 4532-7562-9102-3456, CVV: 789, Exp: 12/25" masked = client.mask(text, policy="pci_dss") # → "Customer card: ************3456, CVV: ***, Exp: *****" print(masked.text) # Safe to display in UI ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-key' }); const text = 'Customer card: 4532-7562-9102-3456, CVV: 789, Exp: 12/25'; const masked = await client.mask(text, { policy: 'pci_dss' }); // → "Customer card: ************3456, CVV: ***, Exp: *****" console.log(masked.text); // Safe to display in UI ``` ### Encrypt for Storage (Req 3.4) Render cardholder data unreadable anywhere it is stored: ```python Python theme={null} # Encrypt card data for database storage transaction = "Payment from John Doe, card 4532-7562-9102-3456, amount $500" encrypted = client.encrypt(transaction, encryption_key="your-encryption-key") # Store encrypted.text in your database — PCI compliant # Decrypt when authorized access is needed decrypted = client.decrypt(encrypted.text, encryption_key="your-encryption-key") print(decrypted.text) # Original text restored ``` ```typescript TypeScript theme={null} const transaction = 'Payment from John Doe, card 4532-7562-9102-3456, amount $500'; const encrypted = await client.encrypt(transaction, { encryptionKey: 'your-encryption-key', }); // Store encrypted.text in your database const decrypted = await client.decrypt(encrypted.text, { encryptionKey: 'your-encryption-key', }); console.log(decrypted.text); ``` ### Redact from Logs (Req 3) Remove cardholder data from application logs permanently: ```python theme={null} log_entry = "2026-02-15 Payment processed: card 4532-7562-9102-3456 for $250.00" redacted = client.redact(log_entry, policy="pci_dss") # → "2026-02-15 Payment processed: card [REDACTED] for $250.00" # Safe to store in log files — no cardholder data ``` ### Tokenize for AI Processing If your AI chatbot might receive card numbers in customer messages: ```python theme={null} from openai import OpenAI openai_client = OpenAI(api_key="your-openai-key") customer_message = ( "I was charged twice on my card 4532-7562-9102-3456. " "The charges were on 02/10 and 02/11 for $49.99 each." ) # Tokenize before sending to AI tokenized = client.tokenize(customer_message, policy="pci_dss") # → "I was charged twice on my card ..." completion = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "You are a billing support agent."}, {"role": "user", "content": tokenized.text}, ], ) # Restore card details in response restored = client.detokenize( completion.choices[0].message.content, tokenized.mapping, ) print(restored.text) ``` ## Reducing PCI Scope By tokenizing cardholder data with Blindfold *before* it reaches your AI provider or logs: * **AI provider** is out of PCI scope — it never sees real card numbers * **Application logs** are out of scope — redacted data has no cardholder data * **Your PCI audit** is simpler — fewer systems in scope ## PCI DSS Compliance Checklist Use `policy="pci_dss"` on all calls that might contain payment data. Use `blindfold.mask()` before displaying any text that might contain card numbers. Use `blindfold.encrypt()` before storing any text containing card data. Use `blindfold.redact()` to strip cardholder data from application logs. Use `blindfold.tokenize()` before sending customer messages to AI providers. Issue different Blindfold API keys for different applications to enforce access control. Regularly export and review audit logs for compliance documentation. # SOC 2 Compliance Source: https://docs.blindfold.dev/compliance/soc2 How Blindfold supports SOC 2 Trust Services Criteria for AI applications **Service Organization Control 2** (SOC 2) is developed by the American Institute of Certified Public Accountants (AICPA) and is the gold standard for demonstrating security practices to enterprise customers. Unlike certifications, SOC 2 is an **audit report** — an independent auditor evaluates your controls against the Trust Services Criteria and issues a formal report. There are two types of SOC 2 reports: * **Type I** evaluates the design of your controls at a specific point in time * **Type II** evaluates the operating effectiveness of your controls over a period, typically 6-12 months When your AI application handles customer data, SOC 2 demonstrates your commitment to security, availability, and data protection. Blindfold helps you implement the technical controls that auditors look for. ## Who Needs SOC 2 SOC 2 is relevant for: * **SaaS companies** handling customer data * **AI applications** processing sensitive information * **Service providers** to enterprise customers * **Any company** where customers ask "Are you SOC 2 compliant?" SOC 2 is not legally required, but it's increasingly expected by enterprise customers and often a prerequisite for closing deals. ## Trust Services Criteria SOC 2 is organized around five Trust Services Criteria. Security is required; the other four are optional but commonly included. The foundation of every SOC 2 report. Security covers protection against unauthorized access to systems and data. Key controls include firewalls, encryption, access controls, intrusion detection, and vulnerability management. Every SOC 2 audit includes the Security criteria — also known as the Common Criteria (CC). System uptime and performance commitments. Availability criteria cover SLAs, monitoring, disaster recovery, capacity planning, and incident response. Auditors evaluate whether your systems are available for operation and use as committed or agreed upon. Data processing is complete, valid, accurate, and timely. Processing Integrity criteria cover input validation, error handling, reconciliation, and output review. This ensures that your system processes data correctly and as authorized — critical for AI applications that transform sensitive information. Sensitive data is protected throughout its lifecycle. Confidentiality criteria cover encryption at rest and in transit, access restrictions, data classification, and secure disposal. When your AI application handles customer data, confidentiality controls ensure that data is only accessible to authorized parties. Personal information collection, use, retention, disclosure, and disposal. Privacy criteria cover notice, consent, purpose limitation, and data minimization. This criteria aligns closely with privacy regulations like GDPR and CCPA, making it especially relevant for AI applications that process personal data. ## How Blindfold Maps to SOC 2 | Trust Criteria | Requirement | Blindfold Feature | | ---------------------------- | -------------------------- | ----------------------------------------------- | | Security (CC6.1) | Logical access controls | API key authentication, per-tenant isolation | | Security (CC6.7) | Data protection in transit | TLS encryption, tokenization before transfer | | Confidentiality (C1.1) | Identify confidential data | Automatic PII detection with policies | | Confidentiality (C1.2) | Protect confidential data | `tokenize()`, `encrypt()`, `redact()`, `mask()` | | Privacy (P3.1) | Collection limitation | Data minimization via tokenization | | Privacy (P4.1) | Use limitation | PII never reaches AI providers | | Processing Integrity (PI1.1) | Accurate processing | Audit logs track every operation | | Availability (A1.2) | Recovery objectives | Regional redundancy (EU/US endpoints) | ## Blindfold for Your SOC 2 Audit Using Blindfold in your data pipeline strengthens your SOC 2 posture across multiple Trust Services Criteria. ### Audit Logs Every PII detection and protection operation is logged with timestamps, entity types detected, and the method used. These logs provide direct evidence for your auditor — export them from the [Blindfold Dashboard](https://app.blindfold.dev) during audit preparation. ### Data Minimization Tokenization ensures AI providers never receive real PII. Your auditor sees a clear data boundary: sensitive data stays within your controlled environment, while only anonymized tokens like `` cross to third-party AI providers. ### Encryption Blindfold provides AES-256 encryption for sensitive data at rest via `encrypt()`, and all API communication is protected with TLS encryption in transit. ### Access Controls Separate API keys per application enforce logical access boundaries. Per-tenant isolation ensures that one customer's data is never accessible to another. Role-based dashboard access controls who can view audit logs and manage configurations. ## Code Examples ### Data Protection with Audit Trail Tokenize sensitive data before sending it to an AI provider. Every call creates an audit log entry that your SOC 2 auditor can review. ```python Python theme={null} from blindfold import Blindfold from openai import OpenAI blindfold = Blindfold(api_key="your-key") openai_client = OpenAI(api_key="your-openai-key") customer_message = ( "Hi, I'm Alex Chen. My email is alex.chen@example.com " "and my phone number is (555) 123-4567. " "I need to update my billing address to 742 Evergreen Terrace." ) # Tokenize PII — creates an audit log entry tokenized = blindfold.tokenize(customer_message) # → "Hi, I'm . My email is # and my phone number is . # I need to update my billing address to ." # Audit log records: timestamp, 4 entities detected, method: tokenize print(f"Entities detected: {tokenized.entities_count}") for entity in tokenized.detected_entities: print(f" [{entity.type}] → {entity.token}") # Send only tokens to AI provider completion = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": tokenized.text}], ) # Restore real values in the response restored = blindfold.detokenize( completion.choices[0].message.content, tokenized.mapping, ) print(restored.text) ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; import OpenAI from 'openai'; const blindfold = new Blindfold({ apiKey: 'your-key' }); const openai = new OpenAI({ apiKey: 'your-openai-key' }); const customerMessage = "Hi, I'm Alex Chen. My email is alex.chen@example.com " + 'and my phone number is (555) 123-4567. ' + 'I need to update my billing address to 742 Evergreen Terrace.'; // Tokenize PII — creates an audit log entry const tokenized = await blindfold.tokenize(customerMessage); // → "Hi, I'm . My email is // and my phone number is . // I need to update my billing address to ." console.log(`Entities detected: ${tokenized.entitiesCount}`); for (const entity of tokenized.detectedEntities) { console.log(` [${entity.type}] → ${entity.token}`); } // Send only tokens to AI provider const completion = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [{ role: 'user', content: tokenized.text }], }); // Restore real values in the response const restored = await blindfold.detokenize( completion.choices[0].message.content, tokenized.mapping, ); console.log(restored.text); ``` ### Encrypt Sensitive Data at Rest Use `encrypt()` to protect customer data before storing it in your database — satisfying Confidentiality (C1.2) requirements. ```python Python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-key") customer_record = ( "Customer: Alex Chen, email: alex.chen@example.com, " "SSN: 123-45-6789, account balance: $15,230.00" ) # Encrypt PII before storage encrypted = client.encrypt(customer_record, encryption_key="your-encryption-key") # Store encrypted.text in your database — auditor sees encrypted values print(encrypted.text) # → "Customer: aGVsbG8..., email: dGVzdA..., # SSN: c2VjcmV0..., account balance: $15,230.00" # Decrypt when authorized access is needed decrypted = client.decrypt(encrypted.text, encryption_key="your-encryption-key") print(decrypted.text) # Original text restored ``` ```typescript TypeScript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-key' }); const customerRecord = 'Customer: Alex Chen, email: alex.chen@example.com, ' + 'SSN: 123-45-6789, account balance: $15,230.00'; // Encrypt PII before storage const encrypted = await client.encrypt(customerRecord, { encryptionKey: 'your-encryption-key', }); // Store encrypted.text in your database console.log(encrypted.text); // Decrypt when authorized access is needed const decrypted = await client.decrypt(encrypted.text, { encryptionKey: 'your-encryption-key', }); console.log(decrypted.text); // Original text restored ``` ### Complete Data Protection Pipeline Demonstrate multiple SOC 2 controls in a single flow: detection (CC6.1), tokenization (C1.2), AI processing (PI1.1), and restoration — all with a full audit trail. ```python theme={null} from blindfold import Blindfold from openai import OpenAI blindfold = Blindfold(api_key="your-key") openai_client = OpenAI(api_key="your-openai-key") # Incoming customer support message support_ticket = ( "My name is Alex Chen and I'm having trouble with my account. " "My email is alex.chen@example.com, phone (555) 123-4567. " "I was charged $299 on card ending 3456. My address is " "742 Evergreen Terrace, Springfield, IL 62704." ) # Step 1: Detect — identify all PII in the text detected = blindfold.detect(support_ticket) print(f"Found {detected.entities_count} entities:") for entity in detected.detected_entities: print(f" [{entity.type}] {entity.text}") # [Person] Alex Chen # [Email Address] alex.chen@example.com # [Phone Number] (555) 123-4567 # [Credit Card Number] 3456 # [Address] 742 Evergreen Terrace, Springfield, IL 62704 # Step 2: Tokenize — replace PII with tokens tokenized = blindfold.tokenize(support_ticket) print(f"\nTokenized: {tokenized.text}") # "My name is and I'm having trouble with my account. # My email is , phone ..." # Step 3: Send to AI — only anonymized tokens reach the provider completion = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "You are a customer support agent."}, {"role": "user", "content": tokenized.text}, ], ) ai_response = completion.choices[0].message.content # Step 4: Restore — put real values back into the AI response restored = blindfold.detokenize(ai_response, tokenized.mapping) print(f"\nFinal response: {restored.text}") # Audit trail captures every step: # - detect: 5 entities identified (CC6.1, C1.1) # - tokenize: 5 entities replaced (C1.2, P3.1) # - detokenize: response restored (PI1.1) ``` ## Providing Evidence to Auditors During your SOC 2 audit, you can provide the following evidence from Blindfold: * **Audit log exports** from the Blindfold dashboard showing every PII operation with timestamps * **API documentation** demonstrating the data protection controls available * **Policy configurations** showing how data is classified and which entity types are detected * **Encryption key management** documentation for data-at-rest protection Blindfold's audit logs provide evidence for CC7.2 (monitoring), C1.1 (data identification), and P3.2 (collection practices). ## SOC 2 Readiness Checklist Add Blindfold SDK calls before any AI provider interaction or sensitive data storage. This establishes the technical controls auditors evaluate. Select detection policies that match your data types — `default` for general PII, or specialized policies like `gdpr_eu`, `hipaa_us`, or `pci_dss` for regulated data. Every Blindfold API call is automatically logged. Ensure your application routes all sensitive text through Blindfold so the audit trail is complete. Use `blindfold.encrypt()` with AES-256 encryption before storing any text containing sensitive information in your database. Create different API keys for each application or environment (development, staging, production) to enforce logical access controls. Schedule regular exports from the [Blindfold Dashboard](https://app.blindfold.dev) and review them for anomalies or unexpected access patterns. Prepare documentation describing how Blindfold fits into your data pipeline, which protection methods you use, and how audit evidence is collected. # Error Handling Source: https://docs.blindfold.dev/essentials/error-handling HTTP status codes and error responses Blindfold uses standard HTTP status codes to indicate the success or failure of API requests. All error responses include detailed information to help you debug issues. ## HTTP Status Codes ### Success Codes **Meaning**: Request succeeded. **When**: All API methods (tokenize, detokenize, mask, redact, hash, synthesize, encrypt) return 200 on success. **Example Response**: ```json theme={null} { "text": "Protected text with ", "mapping": { "": "john@example.com" }, "entities_count": 1, "detected_entities": [...] } ``` ### Client Error Codes **Meaning**: Malformed request or missing parameters. **Common Causes**: * Missing required `text` parameter * Invalid JSON format * Invalid entity type specified * Invalid configuration parameters * Empty text field **Example Response**: ```json theme={null} { "detail": "Field required", "error": "validation_error", "status_code": 400 } ``` **How to Fix**: * Verify all required fields are present * Check JSON formatting * Ensure `text` field is not empty * Validate entity type names **Meaning**: Missing or invalid API key. **Common Causes**: * Missing `X-API-Key` header * Invalid API key * Expired API key * API key deleted or revoked **Example Response**: ```json theme={null} { "detail": "Invalid or missing API key", "error": "unauthorized", "status_code": 401 } ``` **How to Fix**: * Verify you're sending the `X-API-Key` header * Check your API key is correct * Generate a new API key in the dashboard * Ensure API key hasn't been revoked ```bash theme={null} # Correct header format curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{"text": "Sample text"}' ``` **Meaning**: Rate limit exceeded. **Common Causes**: * Too many requests in short time period * Exceeded plan quota * Burst limit reached **Example Response**: ```json theme={null} { "detail": "Rate limit exceeded. Try again in 60 seconds.", "error": "rate_limit_exceeded", "status_code": 429, "retry_after": 60 } ``` **Plan Limits:** * **Free**: 500K characters/month, 5K chars per request * **Pay As You Go**: Unlimited characters, 500K chars per request **How to Fix**: * Implement exponential backoff * Use the `retry_after` value from response * Batch multiple texts into single requests * Upgrade to Pay As You Go for unlimited usage ### Server Error Codes **Meaning**: Unexpected server-side error. **Common Causes**: * Temporary service disruption * Internal processing error * Database connectivity issue **Example Response**: ```json theme={null} { "detail": "An internal error occurred", "error": "internal_server_error", "status_code": 500, "request_id": "req_abc123xyz" } ``` **How to Fix**: * Retry the request after a few seconds * If error persists, contact support with `request_id` * Check [status page](https://status.blindfold.dev) for service status If you receive 500 errors frequently, contact [support@blindfold.dev](mailto:support@blindfold.dev) with the `request_id`. **Meaning**: Service temporarily unavailable. **Common Causes**: * Scheduled maintenance * System overload * Deployment in progress **Example Response**: ```json theme={null} { "detail": "Service temporarily unavailable", "error": "service_unavailable", "status_code": 503, "retry_after": 120 } ``` **How to Fix**: * Wait and retry after the `retry_after` period * Check maintenance schedule * Implement automatic retry logic ## Error Response Format All error responses follow a consistent format: ```json theme={null} { "detail": "Human-readable error message", "error": "error_code_identifier", "status_code": 400, "request_id": "req_unique_identifier" // Optional, for debugging } ``` ### Fields Explained * **detail**: User-friendly error message explaining what went wrong * **error**: Machine-readable error code for programmatic handling * **status\_code**: HTTP status code * **request\_id**: Unique identifier for the request (present in 5xx errors) ## Handling Errors in Your Code ### Python SDK The Python SDK raises specific exceptions for different error types: ```python theme={null} from blindfold import Blindfold from blindfold.exceptions import ( BlindfoldAPIError, AuthenticationError, RateLimitError, ValidationError ) client = Blindfold(api_key="your-api-key") try: result = client.tokenize("Sample text with PII") except AuthenticationError as e: print(f"Invalid API key: {e}") # Re-authenticate or use different key except RateLimitError as e: print(f"Rate limit exceeded. Retry after {e.retry_after} seconds") # Implement backoff strategy except ValidationError as e: print(f"Invalid input: {e}") # Fix request parameters except BlindfoldAPIError as e: print(f"API error: {e.status_code} - {e.message}") # Handle general API errors ``` ### JavaScript SDK The JavaScript SDK throws typed errors: ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; import { AuthenticationError, RateLimitError, ValidationError, BlindfoldError } from '@blindfold/sdk/errors'; const client = new Blindfold({ apiKey: 'your-api-key' }); try { const result = await client.tokenize("Sample text with PII"); } catch (error) { if (error instanceof AuthenticationError) { console.error('Invalid API key:', error.message); // Handle authentication error } else if (error instanceof RateLimitError) { console.error(`Rate limit exceeded. Retry after ${error.retryAfter}s`); // Implement exponential backoff } else if (error instanceof ValidationError) { console.error('Invalid input:', error.message); // Fix request parameters } else if (error instanceof BlindfoldError) { console.error('API error:', error.statusCode, error.message); // Handle general errors } } ``` ### REST API (cURL) When using the REST API directly, check the HTTP status code: ```bash theme={null} # Using curl with error handling response=$(curl -s -w "\n%{http_code}" -X POST \ https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{"text": "Sample text"}') http_code=$(echo "$response" | tail -n1) body=$(echo "$response" | head -n-1) if [ "$http_code" -eq 200 ]; then echo "Success: $body" elif [ "$http_code" -eq 401 ]; then echo "Authentication failed" elif [ "$http_code" -eq 429 ]; then echo "Rate limit exceeded" else echo "Error $http_code: $body" fi ``` ## Retry Logic ### Exponential Backoff Implement exponential backoff for transient errors (429, 500, 503): ```python theme={null} import time from blindfold import Blindfold from blindfold.exceptions import RateLimitError, BlindfoldAPIError def tokenize_with_retry(text, max_retries=3): client = Blindfold(api_key="your-api-key") for attempt in range(max_retries): try: return client.tokenize(text) except RateLimitError as e: if attempt < max_retries - 1: wait_time = e.retry_after or (2 ** attempt) # Exponential backoff print(f"Rate limited. Retrying in {wait_time}s...") time.sleep(wait_time) else: raise except BlindfoldAPIError as e: if e.status_code >= 500 and attempt < max_retries - 1: wait_time = 2 ** attempt print(f"Server error. Retrying in {wait_time}s...") time.sleep(wait_time) else: raise ``` ### JavaScript Retry Example ```javascript theme={null} async function tokenizeWithRetry(text, maxRetries = 3) { const client = new Blindfold({ apiKey: 'your-api-key' }); for (let attempt = 0; attempt < maxRetries; attempt++) { try { return await client.tokenize(text); } catch (error) { if (error instanceof RateLimitError && attempt < maxRetries - 1) { const waitTime = error.retryAfter || Math.pow(2, attempt) * 1000; console.log(`Rate limited. Retrying in ${waitTime}ms...`); await new Promise(resolve => setTimeout(resolve, waitTime)); } else if (error.statusCode >= 500 && attempt < maxRetries - 1) { const waitTime = Math.pow(2, attempt) * 1000; console.log(`Server error. Retrying in ${waitTime}ms...`); await new Promise(resolve => setTimeout(resolve, waitTime)); } else { throw error; } } } } ``` ## Best Practices Always log the `request_id` for 5xx errors. This helps support diagnose issues quickly. Use exponential backoff for rate limits and server errors. Respect the `retry_after` value. Validate input locally before making API calls to avoid 400 errors. Track error rates in your application. Sudden increases may indicate issues. ## Common Error Scenarios ### Scenario 1: Authentication Failure ```python theme={null} # ❌ Wrong client = Blindfold(api_key="") # Empty API key result = client.tokenize("text") # 401 Unauthorized # ✅ Correct client = Blindfold(api_key="your-valid-api-key") result = client.tokenize("text") ``` ### Scenario 2: Missing Required Field ```bash theme={null} # ❌ Wrong curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{}' # Missing "text" field -> 400 Bad Request # ✅ Correct curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{"text": "Sample text"}' ``` ### Scenario 3: Rate Limit Exceeded ```python theme={null} # ❌ Wrong - No rate limit handling for i in range(1000): client.tokenize(f"Text {i}") # Will hit 429 after ~100 requests # ✅ Correct - With retry logic for i in range(1000): try: result = tokenize_with_retry(f"Text {i}") except RateLimitError: print("Rate limit exceeded even after retries") break ``` ## Getting Help If you encounter persistent errors: Email [support@blindfold.dev](mailto:support@blindfold.dev) with the `request_id` from error responses. Check current service status and maintenance schedules Full API documentation with request/response examples ## See Also Learn about rate limits and quotas Python SDK error handling JavaScript SDK error handling Complete API reference # Policy Management Source: https://docs.blindfold.dev/essentials/policies Pre-configured and custom policies for consistent PII detection across your organization Policies are pre-configured detection rules that combine entity types and confidence thresholds into reusable configurations. They simplify PII detection and ensure consistency across your organization. **Why use policies?** Instead of specifying entities and thresholds in every API call, use a policy name. This ensures consistent detection rules across your entire application and makes compliance easier. ## Understanding Policies A policy defines: * **Entity Types**: Which types of sensitive data to detect (e.g., person, email, SSN) * **Detection Threshold**: Minimum confidence level (0.0-1.0) for detections * **Use Case**: The compliance framework or business need it addresses ### Policy Benefits Same detection rules across all applications and teams Pre-configured for GDPR, HIPAA, PCI DSS standards One parameter instead of listing 15+ entity types Update policy once, apply everywhere instantly ## Global Policies Blindfold provides 5 pre-configured global policies for common use cases and compliance frameworks. ### Available Global Policies **Best for:** General applications, basic privacy protection **Threshold:** 0.30 (more permissive, catches more) **Entity Types (3):** * Person names * Email addresses * Phone numbers **Use when:** You need simple, fast PII detection without regulatory requirements. ```python theme={null} # Quick start with basic protection result = client.tokenize( text="Contact John at john@example.com", policy="basic" ) ``` **Best for:** European data protection, Article 4(1) personal data **Threshold:** 0.35 (balanced) **Entity Types (15+):** * Person, Email, Phone Number, Address * National ID Number, Passport Number * Tax ID, Bank Account, IBAN, Credit Card * Date of Birth, IP Address * Health Insurance Number, Medical Condition **Compliance:** GDPR Article 4(1) - "Personal Data" **Use when:** Processing EU citizen data or operating in the European market. ```python theme={null} # GDPR-compliant detection result = client.tokenize( text="Customer: Maria Schmidt, Email: maria@example.de", policy="gdpr_eu" ) ``` **Best for:** US healthcare, HIPAA Protected Health Information (PHI) **Threshold:** 0.40 (stricter, fewer false positives) **Entity Types (11+):** * Person, Email, Phone Number * Social Security Number * Health Insurance Number, Medical Condition * Medication, Insurance Company * Date of Birth, Address **Compliance:** HIPAA 45 CFR § 164.514(b) - "Protected Health Information" **Use when:** Handling patient data, healthcare records, or medical information. ```python theme={null} # HIPAA-compliant detection result = client.tokenize( text="Patient: John Doe, SSN: 123-45-6789, Diagnosis: Type 2 Diabetes", policy="hipaa_us" ) ``` **Best for:** Payment processing, cardholder data protection **Threshold:** 0.45 (strict, high confidence) **Entity Types (8+):** * Credit Card Number, Credit Card Brand * Credit Card Expiration Date, CVV/CVC * Bank Account Number, IBAN * Person, Email **Compliance:** PCI DSS Requirement 3 - "Protect Stored Cardholder Data" **Use when:** Processing payments, storing transaction data, or handling credit cards. ```python theme={null} # PCI DSS-compliant detection result = client.tokenize( text="Card: 4532-7562-9102-3456, CVV: 123, Exp: 12/25", policy="pci_dss" ) ``` **Best for:** High-security environments, comprehensive PII protection **Threshold:** 0.25 (most permissive, maximum detection) **Entity Types (60+):** * All personal identifiers (Person, Email, Phone) * All government IDs (SSN, Passport, Driver's License, National ID) * All financial data (Credit Cards, Bank Accounts, IBAN, Tax ID) * All healthcare data (Medical Conditions, Medications, Health Insurance) * All digital identifiers (IP Address, Username, Social Media) * All travel data (Flight Numbers, Reservation Numbers) * All additional types (License Plates, Student IDs, Serial Numbers) **Use when:** Maximum security is required, regulatory compliance is critical, or handling highly sensitive data. ```python theme={null} # Maximum protection result = client.tokenize( text="Comprehensive data protection for all PII types", policy="strict" ) ``` ### Policy Comparison | Policy | Entities | Threshold | Speed | Use Case | | ---------- | -------- | --------- | ------------- | ------------------ | | `basic` | 3 | 0.30 | ⚡⚡⚡ Fastest | General apps | | `gdpr_eu` | 15+ | 0.35 | ⚡⚡ Fast | EU data protection | | `hipaa_us` | 11+ | 0.40 | ⚡⚡ Fast | US healthcare | | `pci_dss` | 8+ | 0.45 | ⚡⚡⚡ Very Fast | Payment processing | | `strict` | 60+ | 0.25 | ⚡ Moderate | Maximum security | ## Custom Policies Create custom policies tailored to your specific business needs through the **Blindfold Dashboard**. ### When to Create Custom Policies Your industry requires specific entity types not covered by global policies You need different confidence levels than global policies Only need a few specific entity types from a larger policy Enforce consistent detection rules across development teams ### Creating a Custom Policy Custom policies are created and managed through the **Blindfold Dashboard**: Navigate to [app.blindfold.dev](https://app.blindfold.dev) and sign in Click on **"Policy Configuration"** in the left sidebar Click **"Create Custom Policy"** button * **Name**: Choose a unique policy name (e.g., `internal_hr_policy`) * **Description**: Optional description of the policy's purpose * **Entity Types**: Select which PII types to detect * **Threshold**: Set confidence level (0.0-1.0) Save the policy and use it immediately in your API calls ### Custom Policy Examples ```python Python - HR Department theme={null} # Custom policy for employee data result = client.tokenize( text="Employee: John Doe, SSN: 123-45-6789, DOB: 1990-05-15", policy="internal_hr_policy" # Custom policy created in dashboard ) ``` ```python Python - Customer Support theme={null} # Custom policy for support tickets result = client.tokenize( text="Ticket #12345: Customer john@example.com needs help", policy="support_ticket_policy" # Only detects emails and phone numbers ) ``` ```python Python - Financial Reporting theme={null} # Custom policy for financial reports result = client.tokenize( text="Account: 1234-5678-9012, Transaction: $5,000", policy="finance_reporting_policy" # Bank accounts and transaction IDs ) ``` ```javascript JavaScript - Marketing theme={null} // Custom policy for marketing data const result = await client.tokenize( "Campaign leads: john@example.com, mary@company.com", { policy: "marketing_leads_policy" } // Only emails and names ); ``` ## Using Policies in API Calls ### With SDKs Policies work seamlessly with all Blindfold SDKs: ```python Python SDK theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key") # Use global policy result = client.tokenize( text="Patient data...", policy="hipaa_us" ) # Use custom policy result = client.tokenize( text="Employee data...", policy="my_custom_policy" ) ``` ```javascript JavaScript SDK theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); // Use global policy const result = await client.tokenize( "Patient data...", { policy: "hipaa_us" } ); // Use custom policy const result = await client.tokenize( "Employee data...", { policy: "my_custom_policy" } ); ``` ### With REST API Policies work with all privacy method endpoints: ```bash Tokenize theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "text": "Contact John at john@example.com", "policy": "gdpr_eu" }' ``` ```bash Mask theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/mask \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "text": "Card: 4532-7562-9102-3456", "policy": "pci_dss", "chars_to_show": 4 }' ``` ```bash Redact theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/redact \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "text": "SSN: 123-45-6789", "policy": "hipaa_us" }' ``` ## Best Practices ### 1. Choose the Right Policy Determine compliance needs (GDPR, HIPAA, PCI DSS) and data types Use global policies when they match your requirements Create custom policies for specific business needs ### 2. Policy Naming Conventions For custom policies, use clear, descriptive names: ```text ✅ Good Names theme={null} internal_hr_policy customer_support_pii finance_reporting_data marketing_contact_info legal_document_redaction ``` ```text ❌ Bad Names theme={null} policy1 temp test my_policy custom ``` ### 3. Document Your Policies For each custom policy, document: * **Purpose**: Why the policy exists * **Entity Types**: What it detects * **Threshold**: Confidence level and reasoning * **Use Cases**: Where it should be used * **Owner**: Team or person responsible ### 4. Regular Review * **Quarterly**: Review policy effectiveness * **After incidents**: Update based on false positives/negatives * **Compliance changes**: Adjust when regulations update * **New features**: Update when new entity types are available ## Policy vs. Manual Configuration ### When to Use Policies ✅ **Use policies when:** * You need consistent detection across multiple applications * You're subject to compliance regulations (GDPR, HIPAA, PCI DSS) * Multiple teams use the same detection rules * You want simplified API calls * You need centralized management ### When to Use Manual Configuration ✅ **Use manual configuration (`entities` + `score_threshold`) when:** * One-off or experimental detection * Testing different entity combinations * Highly specialized single-use cases * You need maximum flexibility ```python Policy (Recommended) theme={null} # Consistent, maintainable, compliant result = client.tokenize( text="Your text", policy="gdpr_eu" # One parameter, 15+ entities ) ``` ```python Manual Configuration theme={null} # Flexible but requires maintenance result = client.tokenize( text="Your text", entities=[ "person", "email address", "phone number", "address", "national id number", "passport number", "tax identification number", "bank account number", "iban", "credit card number", "date of birth", "ip address", "health insurance number", "medical condition", "social security number" ], score_threshold=0.35 ) ``` ## Compliance Mapping ### GDPR (General Data Protection Regulation) **Policy:** `gdpr_eu` **Article 4(1) - Personal Data:** Any information relating to an identified or identifiable natural person. **Covered by Blindfold:** * Names, contact details (email, phone, address) * Identification numbers (national ID, passport, tax ID) * Financial data (bank accounts, credit cards) * Health data (medical conditions, health insurance) * Online identifiers (IP addresses) ### HIPAA (Health Insurance Portability and Accountability Act) **Policy:** `hipaa_us` **45 CFR § 164.514(b) - Protected Health Information (PHI):** **18 HIPAA Identifiers Covered:** 1. Names ✅ 2. Geographic subdivisions ✅ (Address) 3. Dates (birth) ✅ 4. Phone numbers ✅ 5. Email addresses ✅ 6. Social Security Numbers ✅ 7. Medical record numbers ✅ 8. Health plan numbers ✅ (Health Insurance Number) 9. Account numbers ✅ (Bank Account) 10. Certificate/license numbers ✅ 11-18. Additional identifiers ✅ ### PCI DSS (Payment Card Industry Data Security Standard) **Policy:** `pci_dss` **Requirement 3 - Protect Stored Cardholder Data:** **Primary Account Number (PAN) Protection:** * Credit card numbers ✅ * CVV/CVC codes ✅ * Expiration dates ✅ * Cardholder names ✅ * Bank account numbers ✅ ## FAQ No, global policies are fixed to ensure compliance standards. However, you can create a custom policy based on a global policy and modify it to your needs. No limit. Create as many custom policies as your organization needs. No, custom policies are tenant-specific. Each organization manages their own policies. Global policies are available to all tenants. API calls using the deleted policy will fail with a 404 error. Ensure you update your applications before deleting a policy. Not directly, but you can create new policies with version numbers in the name (e.g., `hr_policy_v1`, `hr_policy_v2`) and migrate gradually. * **GDPR compliance?** → `gdpr_eu` * **Healthcare data?** → `hipaa_us` * **Payment processing?** → `pci_dss` * **General apps?** → `basic` * **Maximum security?** → `strict` * **Custom needs?** → Create custom policy ## Next Steps Sign in to the dashboard and create a custom policy Browse 60+ entity types available for policies Learn how to use policies in API calls Policy optimization and security tips # Regions Source: https://docs.blindfold.dev/essentials/regions Choose where your data is processed for compliance and latency Blindfold operates PII processing nodes in multiple regions. You can select a region to ensure data residency compliance and minimize latency. ## Available Regions | Region | Endpoint | Location | | -------------------- | ------------------------------ | ------------- | | **EU** (default) | `https://eu-api.blindfold.dev` | Europe | | **US** | `https://us-api.blindfold.dev` | United States | | **Global** (default) | `https://api.blindfold.dev` | Routes to EU | If no region is specified, requests are routed to the EU region by default. ## Selecting a Region ### Python SDK ```python theme={null} from blindfold import Blindfold # EU region (explicit) client = Blindfold(api_key="your-key", region="eu") # US region client = Blindfold(api_key="your-key", region="us") ``` ### JavaScript / TypeScript SDK ```typescript theme={null} import { Blindfold } from '@blindfold/sdk'; // EU region (explicit) const client = new Blindfold({ apiKey: 'your-key', region: 'eu' }); // US region const client = new Blindfold({ apiKey: 'your-key', region: 'us' }); ``` ### CLI ```bash theme={null} # EU region blindfold --region eu tokenize "Contact John Doe at john@example.com" # US region blindfold --region us tokenize "Contact John Doe at john@example.com" # Or set via environment variable export BLINDFOLD_REGION=us blindfold tokenize "Contact John Doe at john@example.com" ``` ### MCP Server Set the `BLINDFOLD_REGION` environment variable: ```json theme={null} { "mcpServers": { "blindfold": { "command": "npx", "args": ["-y", "@blindfold/mcp-server"], "env": { "BLINDFOLD_API_KEY": "your-key", "BLINDFOLD_REGION": "us" } } } } ``` ### Direct API Calls (cURL) ```bash theme={null} # EU region curl -X POST https://eu-api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-key" \ -H "Content-Type: application/json" \ -d '{"text": "Contact John Doe at john@example.com"}' # US region curl -X POST https://us-api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-key" \ -H "Content-Type: application/json" \ -d '{"text": "Contact John Doe at john@example.com"}' ``` ## Data Residency When you select a region, your text data is processed entirely within that region: * **EU region**: PII detection and processing occurs on EU-based servers. * **US region**: PII detection and processing occurs on US-based servers. Your API key works across all regions. You do not need separate API keys per region. ## Priority Order The region is resolved in this order (highest priority first): 1. **Explicit base URL** (`base_url` / `baseUrl` / `--base-url`) - always takes precedence 2. **Region parameter** (`region` / `--region` / `BLINDFOLD_REGION`) 3. **Default** - routes to EU via `api.blindfold.dev` ## Default Behavior | Configuration | Result | | ----------------------------------------------- | ---------------------------------------------- | | No region, no base URL | Routes to `api.blindfold.dev` (EU) | | `region="eu"` | Routes to `eu-api.blindfold.dev` | | `region="us"` | Routes to `us-api.blindfold.dev` | | `base_url="https://custom.dev"` + `region="us"` | Routes to `https://custom.dev` (base URL wins) | # Supported Entities Source: https://docs.blindfold.dev/essentials/supported-entities 60+ PII entity types detected by Blindfold Blindfold automatically detects 60+ types of personally identifiable information (PII) across multiple languages using **natural language entity names** (lowercase). Use entity names in plain English like `"person"`, `"email address"`, `"credit card number"` - no need for uppercase labels. ## Quick Reference ### Personal Information | Entity Name | Examples | Notes | | -------------------------------------- | ------------------------------------------- | --------------------------- | | `person` | John Doe, María García | Full names, nicknames | | `email` / `email address` | [john@example.com](mailto:john@example.com) | All email formats | | `phone number` / `mobile phone number` | +1-555-1234, +34 912 345 678 | International formats | | `landline phone number` | +1-212-555-0100 | Fixed-line numbers | | `fax number` | Fax: (212) 555-0199 | Fax machine numbers | | `address` / `postal code` | 123 Main St, Boston, MA 02101 | Street addresses, ZIP codes | | `date of birth` | 1990-01-15, January 15, 1990 | Birth dates | | `blood type` | A+, O-, AB+ | Blood classification | ### Financial Information | Entity Name | Examples | Notes | | ----------------------------- | --------------------------- | ------------------------------------------- | | `credit card number` | 4532-7562-9102-3456 | All major card brands | | `credit card brand` | Visa, Mastercard, Amex | Card issuer names | | `credit card expiration date` | 12/25, 01/2026 | Card expiry dates | | `cvv` / `cvc` | 123, 4567 | Card verification codes | | `bank account number` | Account: 98765432 | Bank account numbers | | `iban` | GB82 WEST 1234 5698 7654 32 | International bank accounts (70+ countries) | | `tax identification number` | Tax ID: 987654321 | Tax IDs, EIN, etc. | ### Government-Issued IDs | Entity Name | Examples | Notes | | --------------------------------------------- | ---------------------- | -------------------------- | | `social security number` | 123-45-6789 | SSN (US format) | | `passport number` | A12345678, P1234567890 | International passports | | `passport expiration date` | Expires: 01/15/2030 | Passport expiry | | `driver's license number` | DL: A123-456-78-901-0 | Driver's licenses | | `national id number` / `identity card number` | DNI: 12345678A | National ID cards | | `identity document number` | ID: A1234567 | General identity documents | | `cpf` | 123.456.789-10 | Brazilian taxpayer ID | | `cnpj` | 12.345.678/0001-90 | Brazilian company registry | | `birth certificate number` | BC: 123456789 | Birth certificates | | `visa number` | Visa #: 1234567890 | Visa identification | ### Healthcare Information | Entity Name | Examples | Notes | | -------------------------------------------------------- | ----------------------------- | -------------------- | | `health insurance number` / `health insurance id number` | Member ID: ABC123456789 | Health insurance IDs | | `national health insurance number` | NHS: 123 456 7890 (UK) | National health IDs | | `medical condition` | Type 2 Diabetes, Hypertension | Medical diagnoses | | `medication` | Metformin 500mg, Lisinopril | Medication names | | `insurance number` | Policy: INS-123456789 | General insurance | | `insurance company` | Blue Cross Blue Shield, Aetna | Insurance providers | ### Digital & Technical | Entity Name | Examples | Notes | | --------------------- | ----------------------------- | ---------------------- | | `ip address` | 192.168.1.1, 2001:0db8::1 | IPv4 and IPv6 | | `username` | @john\_doe, user123 | Login identifiers | | `social media handle` | @username, @company\_official | Social media usernames | | `digital signature` | Signature: 0x1234abcd | Digital signature IDs | ### Travel & Transactions | Entity Name | Examples | Notes | | --------------------- | ---------------------- | ---------------------- | | `transaction number` | TXN-123456789 | Transaction IDs | | `reservation number` | Booking ref: R-123456 | Booking confirmations | | `flight number` | AA 1234, Flight: BA456 | Airline flight numbers | | `train ticket number` | Ticket: TRN-123456 | Train bookings | ### Registration & Serial Numbers | Entity Name | Examples | Notes | | ----------------------------- | ------------------------ | ---------------------- | | `registration number` | Registration: REG-123456 | General registrations | | `student id number` | Student ID: 123456789 | Student IDs | | `license plate number` | ABC-1234, XYZ 789 | Vehicle license plates | | `vehicle registration number` | VIN: 1HGBH41JXMN109186 | Vehicle registration | | `serial number` | S/N: ABC123456789 | Product serial numbers | ### Organization | Entity Name | Examples | Notes | | -------------- | ----------------------------------------- | -------------------------- | | `organization` | Microsoft Corporation, Harvard University | Company/organization names | ## Usage Examples ### Detect Specific Entities ```python theme={null} # Detect only emails and phone numbers result = client.tokenize( "Contact: John Doe, john@example.com, +1-555-1234", entities=["email address", "phone number"] ) # Output: "Contact: John Doe, , " ``` ### Use Policies (Recommended) Instead of listing entities, use pre-configured policies: ```python theme={null} # GDPR compliance (detects 15+ entity types) result = client.tokenize( "Contact: John Doe, john@example.com, +49 30 12345", policy="gdpr_eu" ) # Healthcare compliance (detects 11+ entity types) result = client.tokenize( "Patient: Jane Smith, SSN: 123-45-6789", policy="hipaa_us" ) ``` **Available Policies:** * `basic` - Names, emails, phones (3 types) * `gdpr_eu` - GDPR compliance (15+ types) * `hipaa_us` - Healthcare compliance (11+ types) * `pci_dss` - Payment cards (8+ types) * `strict` - All entity types (60+) ## Custom Entities Define your own entity types using natural language: ```python theme={null} # E-commerce custom entities result = client.tokenize( "Order #ORD-2024-XYZ, SKU: PROD-789-BLU", entities=["order number", "product sku"] ) # Healthcare custom entities result = client.tokenize( "Patient in Ward 5B, Procedure Code: PROC-456", entities=["ward number", "procedure code"] ) # Mix standard and custom result = client.tokenize( "Customer John Doe (ID: CUST-789) ordered SKU-456", entities=["person", "customer id", "product sku"] ) ``` Custom entities work with **zero-shot learning** - no training required. Just describe what you want to detect in plain English. ## Multilingual Support All entities work across 15+ languages automatically: ```python theme={null} # Detects entities in multiple languages result = client.tokenize( "Cliente: María García, Email: maria@ejemplo.es, Telefon: +49 30 12345" ) # Detects Spanish and German entities automatically ``` Native support for 9 languages plus zero-shot detection for 6+ more ## Need More Entity Types? Contact us at **[hello@blindfold.dev](mailto:hello@blindfold.dev)** to request additional entity types or discuss your specific use case. # Supported Languages Source: https://docs.blindfold.dev/essentials/supported-languages Languages supported by Blindfold's PII detection engine Blindfold's AI-powered detection engine supports PII detection across multiple languages with varying levels of performance. ## Native Language Support (Highest Accuracy) These languages have been specifically trained for PII detection and provide the best accuracy: Primary language with highest accuracy Full support, excellent accuracy Full support, excellent accuracy Full support, excellent accuracy Full support, excellent accuracy Full support, excellent accuracy Full support, excellent accuracy Full support, excellent accuracy Strong support, good accuracy ## Zero-Shot Language Support (High Accuracy) These languages work through our multilingual detection engine without specific training, achieving excellent results: Works great (similar to Polish/Russian) Strong performance Good performance Good performance Good performance Good performance ## Experimental Support These languages are supported but may require additional validation for production use: * **Chinese** - Supported, but PII patterns differ significantly * **Japanese** - Supported, but PII patterns differ significantly * **Arabic** - Supported with testing recommended ## Automatic Language Detection The detection engine automatically identifies the language - no configuration needed. ```python theme={null} # Mix multiple languages in one request response = client.tokenize( "Contact: John Doe, Email: john@example.com, Teléfono: +34 912 345 678" ) # Automatically detects entities in both English and Spanish ``` ```javascript theme={null} // Works seamlessly across languages const response = await client.tokenize( "Nome: Paolo Rossi, E-Mail: paolo@esempio.it, Osoba: Jan Novák" ); // Detects Italian and Czech automatically ``` For best results, use one of the **Native Language Support** languages. Zero-shot languages work well but may have slightly lower confidence scores for complex entity types. ## Language-Specific Examples ### European Mix ```python theme={null} text = """ Cliente: María García (España) Email: maria@ejemplo.es Kunde: Hans Müller (Deutschland) E-Mail: hans@beispiel.de Client: Jean Dupont (France) Courriel: jean@exemple.fr """ response = client.tokenize(text, policy="gdpr_eu") # Detects PII across Spanish, German, and French ``` ### Slavic Languages ```python theme={null} text = """ Osoba: Jan Novák (Česko) E-mail: jan@priklad.cz Osoba: Piotr Kowalski (Polska) E-mail: piotr@przyklad.pl """ response = client.tokenize(text, policy="gdpr_eu") # Works with Czech and Polish ``` ## Need Help? If you're working with a language not listed here or experiencing issues: * **Email**: [hello@blindfold.dev](mailto:hello@blindfold.dev) * **Documentation**: Check our [examples](/examples) for multilingual use cases # Examples Source: https://docs.blindfold.dev/examples Practical examples for integrating Blindfold with OpenAI, Anthropic Claude, Google Gemini, and more Learn how to integrate Blindfold into real-world applications with these practical examples. ## AI Chat with OpenAI Protect user data when building AI chatbots with OpenAI. ```python theme={null} import os from blindfold import Blindfold from openai import OpenAI # Initialize clients blindfold = Blindfold(api_key=os.environ["BLINDFOLD_API_KEY"]) openai_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"]) def secure_chat(user_message: str) -> str: """Process chat message with privacy protection""" # Step 1: Tokenize sensitive data protected = blindfold.tokenize(user_message) print(f"Protected input: {protected.text}") print(f"Detected {protected.entities_count} sensitive entities") # Step 2: Send protected text to OpenAI response = openai_client.chat.completions.create( model="gpt-4", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": protected.text} ] ) ai_response = response.choices[0].message.content # Step 3: Restore original data in AI response final = blindfold.detokenize(ai_response, protected.mapping) return final.text # Usage user_input = "My name is John Doe, email john@example.com. Help me book a flight." response = secure_chat(user_input) print(f"Response: {response}") ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; import OpenAI from 'openai'; // Initialize clients const blindfold = new Blindfold({ apiKey: process.env.BLINDFOLD_API_KEY }); const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); async function secureChat(userMessage) { // Step 1: Tokenize sensitive data const protected = await blindfold.tokenize(userMessage); console.log(`Protected input: ${protected.text}`); console.log(`Detected ${protected.entities_count} sensitive entities`); // Step 2: Send protected text to OpenAI const response = await openai.chat.completions.create({ model: 'gpt-4', messages: [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: protected.text } ] }); const aiResponse = response.choices[0].message.content; // Step 3: Restore original data in AI response const final = await blindfold.detokenize(aiResponse, protected.mapping); return final.text; } // Usage const userInput = "My name is John Doe, email john@example.com. Help me book a flight."; const response = await secureChat(userInput); console.log(`Response: ${response}`); ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; import com.openai.OpenAI; Blindfold blindfold = new Blindfold(System.getenv("BLINDFOLD_API_KEY")); String secureChat(String userMessage) { // Step 1: Tokenize sensitive data var protected_ = blindfold.tokenize(userMessage); System.out.println("Protected input: " + protected_.getText()); System.out.println("Detected " + protected_.getEntitiesCount() + " sensitive entities"); // Step 2: Send protected text to OpenAI // (use your preferred OpenAI Java client) String aiResponse = callOpenAI(protected_.getText()); // Step 3: Restore original data in AI response var final_ = blindfold.detokenize(aiResponse, protected_.getMapping()); return final_.getText(); } // Usage String userInput = "My name is John Doe, email john@example.com. Help me book a flight."; String response = secureChat(userInput); System.out.println("Response: " + response); ``` **What's Protected:** * Personal names (`John Doe` → ``) * Email addresses (`john@example.com` → ``) * Any other PII in user messages **Benefits:** * User data never reaches OpenAI in plain text * Compliant with privacy regulations * Transparent to end users *** ## AI Chat with Anthropic Claude Protect user data when building AI chatbots with Anthropic Claude. ```python theme={null} import os from blindfold import Blindfold import anthropic # Initialize clients blindfold = Blindfold(api_key=os.environ["BLINDFOLD_API_KEY"]) client = anthropic.Anthropic() def secure_chat(user_message: str) -> str: """Process chat message with privacy protection""" # Step 1: Tokenize sensitive data protected = blindfold.tokenize(user_message) print(f"Protected input: {protected.text}") print(f"Detected {protected.entities_count} sensitive entities") # Step 2: Send protected text to Claude response = client.messages.create( model="claude-sonnet-4-20250514", max_tokens=1024, messages=[ {"role": "user", "content": protected.text} ] ) ai_response = response.content[0].text # Step 3: Restore original data in AI response final = blindfold.detokenize(ai_response, protected.mapping) return final.text # Usage user_input = "My name is John Doe, email john@example.com. Help me book a flight." response = secure_chat(user_input) print(f"Response: {response}") ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; import Anthropic from '@anthropic-ai/sdk'; // Initialize clients const blindfold = new Blindfold({ apiKey: process.env.BLINDFOLD_API_KEY }); const anthropic = new Anthropic(); async function secureChat(userMessage) { // Step 1: Tokenize sensitive data const protected = await blindfold.tokenize(userMessage); console.log(`Protected input: ${protected.text}`); console.log(`Detected ${protected.entities_count} sensitive entities`); // Step 2: Send protected text to Claude const response = await anthropic.messages.create({ model: 'claude-sonnet-4-20250514', max_tokens: 1024, messages: [ { role: 'user', content: protected.text } ] }); const aiResponse = response.content[0].text; // Step 3: Restore original data in AI response const final = await blindfold.detokenize(aiResponse, protected.mapping); return final.text; } // Usage const userInput = "My name is John Doe, email john@example.com. Help me book a flight."; const response = await secureChat(userInput); console.log(`Response: ${response}`); ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold blindfold = new Blindfold(System.getenv("BLINDFOLD_API_KEY")); String secureChat(String userMessage) { // Step 1: Tokenize sensitive data var protected_ = blindfold.tokenize(userMessage); System.out.println("Protected input: " + protected_.getText()); System.out.println("Detected " + protected_.getEntitiesCount() + " sensitive entities"); // Step 2: Send protected text to Claude // (use your preferred Anthropic Java client) String aiResponse = callClaude(protected_.getText()); // Step 3: Restore original data in AI response var final_ = blindfold.detokenize(aiResponse, protected_.getMapping()); return final_.getText(); } // Usage String userInput = "My name is John Doe, email john@example.com. Help me book a flight."; String response = secureChat(userInput); System.out.println("Response: " + response); ``` **Benefits:** * User data never reaches Anthropic in plain text * Works with Claude Sonnet, Opus, and Haiku * Same tokenize/detokenize pattern as other providers *** ## Customer Support Ticket Anonymization Anonymize customer support tickets before storing in databases or sending to third-party analytics. ```python theme={null} from blindfold import Blindfold import os client = Blindfold(api_key=os.environ["BLINDFOLD_API_KEY"]) def process_support_ticket(ticket_text: str) -> dict: """Anonymize and process support ticket""" # Redact sensitive data permanently result = client.redact(ticket_text) # Store anonymized ticket ticket_data = { "text": result.text, "pii_detected": result.entities_count, "entity_types": [e.type for e in result.detected_entities] } return ticket_data # Example ticket ticket = """ Customer: Jane Smith Email: jane.smith@email.com Phone: +1-555-9876 Issue: Cannot access account after password reset. SSN for verification: 123-45-6789 """ processed = process_support_ticket(ticket) print(f"Anonymized ticket:\n{processed['text']}") print(f"PII types found: {processed['entity_types']}") # Output: # Anonymized ticket: # Customer: # Email: # Phone: # Issue: Cannot access account after password reset. # SSN for verification: ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: process.env.BLINDFOLD_API_KEY }); async function processSupportTicket(ticketText) { // Redact sensitive data permanently const result = await client.redact(ticketText); // Store anonymized ticket const ticketData = { text: result.text, pii_detected: result.entities_count, entity_types: result.detected_entities.map(e => e.type) }; return ticketData; } // Example ticket const ticket = ` Customer: Jane Smith Email: jane.smith@email.com Phone: +1-555-9876 Issue: Cannot access account after password reset. SSN for verification: 123-45-6789 `; const processed = await processSupportTicket(ticket); console.log(`Anonymized ticket:\n${processed.text}`); console.log(`PII types found: ${processed.entity_types}`); ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold client = new Blindfold(System.getenv("BLINDFOLD_API_KEY")); Map processSupportTicket(String ticketText) { // Redact sensitive data permanently var result = client.redact(ticketText); return Map.of( "text", result.getText(), "pii_detected", result.getEntitiesCount(), "entity_types", result.getDetectedEntities().stream() .map(e -> e.getType()).toList() ); } // Example ticket String ticket = """ Customer: Jane Smith Email: jane.smith@email.com Phone: +1-555-9876 Issue: Cannot access account after password reset. SSN for verification: 123-45-6789 """; var processed = processSupportTicket(ticket); System.out.println("Anonymized ticket:\n" + processed.get("text")); System.out.println("PII types found: " + processed.get("entity_types")); ``` **Use Cases:** * Support ticket systems * Customer feedback collection * Quality assurance reviews * Third-party analytics *** ## Displaying Masked Credit Cards Show partial credit card numbers in user interfaces while protecting full details. ```python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key") def display_payment_info(payment_text: str) -> str: """Mask payment information for display""" result = client.mask( text=payment_text, masking_char="*", chars_to_show=4, from_end=True ) return result.text # Examples card_info = "Card ending in 4532-7562-9102-3456" print(display_payment_info(card_info)) # Output: "Card ending in ***************3456" multiple_cards = """ Primary: 4532-7562-9102-3456 Backup: 5425-2334-3010-9903 """ print(display_payment_info(multiple_cards)) # Output: # Primary: ***************3456 # Backup: ***************9903 ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); async function displayPaymentInfo(paymentText) { const result = await client.mask( paymentText, { masking_char: '*', chars_to_show: 4, from_end: true } ); return result.text; } // Examples const cardInfo = "Card ending in 4532-7562-9102-3456"; console.log(await displayPaymentInfo(cardInfo)); // Output: "Card ending in ***************3456" const multipleCards = ` Primary: 4532-7562-9102-3456 Backup: 5425-2334-3010-9903 `; console.log(await displayPaymentInfo(multipleCards)); // Output: // Primary: ***************3456 // Backup: ***************9903 ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold client = new Blindfold("your-api-key"); String displayPaymentInfo(String paymentText) { var result = client.mask(paymentText, 4, true, "*", null); return result.getText(); } // Examples String cardInfo = "Card ending in 4532-7562-9102-3456"; System.out.println(displayPaymentInfo(cardInfo)); // Output: "Card ending in ***************3456" String multipleCards = """ Primary: 4532-7562-9102-3456 Backup: 5425-2334-3010-9903 """; System.out.println(displayPaymentInfo(multipleCards)); // Output: // Primary: ***************3456 // Backup: ***************9903 ``` **Benefits:** * Users can identify their cards * Full numbers stay protected * Compliant with PCI-DSS *** ## Analytics with Hashed Identifiers Create consistent identifiers for analytics without storing actual PII. ```python theme={null} from blindfold import Blindfold import json client = Blindfold(api_key="your-api-key") def track_user_event(user_email: str, event: str) -> dict: """Track user events with hashed identifiers""" # Hash email for consistent user ID hashed = client.hash( text=f"User: {user_email}", hash_type="sha256", hash_prefix="user_", hash_length=16 ) # Extract hashed ID user_id = hashed.text.replace("User: ", "") # Create analytics event analytics_event = { "user_id": user_id, "event": event, "timestamp": "2024-01-20T10:00:00Z" } return analytics_event # Track events for same user events = [ track_user_event("john@example.com", "page_view"), track_user_event("john@example.com", "button_click"), track_user_event("john@example.com", "purchase") ] # All events have same hashed user_id (deterministic) for event in events: print(json.dumps(event, indent=2)) # Output (same user_id for all): # { # "user_id": "user_a3f8b9c2d4e5f6g7", # "event": "page_view", # ... # } ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); async function trackUserEvent(userEmail, event) { // Hash email for consistent user ID const hashed = await client.hash( `User: ${userEmail}`, { hash_type: 'sha256', hash_prefix: 'user_', hash_length: 16 } ); // Extract hashed ID const userId = hashed.text.replace('User: ', ''); // Create analytics event return { user_id: userId, event: event, timestamp: new Date().toISOString() }; } // Track events for same user const events = await Promise.all([ trackUserEvent('john@example.com', 'page_view'), trackUserEvent('john@example.com', 'button_click'), trackUserEvent('john@example.com', 'purchase') ]); // All events have same hashed user_id (deterministic) events.forEach(event => { console.log(JSON.stringify(event, null, 2)); }); ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold client = new Blindfold("your-api-key"); Map trackUserEvent(String userEmail, String event) { // Hash email for consistent user ID var hashed = client.hash( "User: " + userEmail, "sha256", "user_", 16, null ); String userId = hashed.getText().replace("User: ", ""); return Map.of( "user_id", userId, "event", event, "timestamp", Instant.now().toString() ); } // Track events for same user var event1 = trackUserEvent("john@example.com", "page_view"); var event2 = trackUserEvent("john@example.com", "button_click"); var event3 = trackUserEvent("john@example.com", "purchase"); // All events have same hashed user_id (deterministic) ``` **Benefits:** * Consistent user tracking * No PII in analytics database * GDPR-friendly approach *** ## Generating Test Data Create realistic test data with synthetic PII for development and testing. ```python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key") def generate_test_data(template: str, language: str = "en") -> list[str]: """Generate multiple test data samples""" samples = [] for _ in range(5): result = client.synthesize( text=template, language=language ) samples.append(result.text) return samples # Generate test user profiles template = """ Name: John Doe Email: john.doe@company.com Phone: +1-555-1234 Location: New York Company: TechCorp """ test_profiles = generate_test_data(template) print("Generated Test Profiles:") for i, profile in enumerate(test_profiles, 1): print(f"\n=== Profile {i} ===") print(profile) # Output (synthetic data): # === Profile 1 === # Name: Michael Smith # Email: michael.smith@company.com # Phone: +1-555-9876 # Location: Boston # Company: DataSystems # # === Profile 2 === # Name: Sarah Johnson # Email: sarah.johnson@company.com # ... ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); async function generateTestData(template, language = 'en', count = 5) { const samples = []; for (let i = 0; i < count; i++) { const result = await client.synthesize(template, { language }); samples.push(result.text); } return samples; } // Generate test user profiles const template = ` Name: John Doe Email: john.doe@company.com Phone: +1-555-1234 Location: New York Company: TechCorp `; const testProfiles = await generateTestData(template); console.log('Generated Test Profiles:'); testProfiles.forEach((profile, i) => { console.log(`\n=== Profile ${i + 1} ===`); console.log(profile); }); ``` **Use Cases:** * Development environments * Automated testing * Demo environments * Training datasets *** ## Encrypting Sensitive Configuration Encrypt sensitive configuration values before storing in databases. ```python theme={null} from blindfold import Blindfold import os client = Blindfold(api_key=os.environ["BLINDFOLD_API_KEY"]) # Encryption key (store securely!) ENCRYPTION_KEY = os.environ["ENCRYPTION_KEY"] def encrypt_config(config_text: str) -> str: """Encrypt sensitive configuration""" result = client.encrypt( text=config_text, encryption_key=ENCRYPTION_KEY ) return result.text def decrypt_config(encrypted_text: str) -> str: """Decrypt configuration (use decrypt endpoint)""" # Note: Implement decrypt endpoint call pass # Example: Encrypt API keys before storing config = """ database_url: postgresql://user:pass@host/db api_key: sk-1234567890abcdef secret_token: abc123xyz789 """ encrypted = encrypt_config(config) print("Encrypted configuration:") print(encrypted) # Store encrypted version in database # Later, decrypt when needed ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: process.env.BLINDFOLD_API_KEY }); const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY; async function encryptConfig(configText) { const result = await client.encrypt( configText, { encryption_key: ENCRYPTION_KEY } ); return result.text; } // Example: Encrypt API keys before storing const config = ` database_url: postgresql://user:pass@host/db api_key: sk-1234567890abcdef secret_token: abc123xyz789 `; const encrypted = await encryptConfig(config); console.log('Encrypted configuration:'); console.log(encrypted); // Store encrypted version in database ``` **Benefits:** * Protect secrets at rest * Reversible encryption * Centralized key management *** ## Multi-Language Support & Custom Entities Blindfold automatically detects PII across 6+ languages and supports custom entity types for industry-specific data. ### Automatic Multilingual Detection ```python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key") # Automatic language detection - no configuration needed # Spanish example spanish_text = "Mi nombre es María García, email: maria@ejemplo.es, teléfono: +34 912 345 678" result_es = client.tokenize(spanish_text) print(f"Spanish: {result_es.text}") # Output: "Mi nombre es , email: , teléfono: " # German example german_text = "Ich heiße Hans Müller, E-Mail: hans@beispiel.de, wohne in Berlin" result_de = client.tokenize(german_text) print(f"German: {result_de.text}") # Output: "Ich heiße , E-Mail: , wohne in " # French example french_text = "Je m'appelle Marie Dupont, email: marie@exemple.fr, tél: +33 1 42 86 82 00" result_fr = client.tokenize(french_text) print(f"French: {result_fr.text}") # Output: "Je m'appelle , email: , tél: " # Mixed languages in one request mixed_text = "Contact: John Doe (john@example.com), Client: María García (maria@ejemplo.es)" result_mixed = client.tokenize(mixed_text) print(f"Mixed: {result_mixed.text}") # Automatically detects entities in both English and Spanish ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); // Automatic language detection - no configuration needed // Spanish example const spanishText = "Mi nombre es María García, email: maria@ejemplo.es, teléfono: +34 912 345 678"; const resultEs = await client.tokenize(spanishText); console.log(`Spanish: ${resultEs.text}`); // German example const germanText = "Ich heiße Hans Müller, E-Mail: hans@beispiel.de, wohne in Berlin"; const resultDe = await client.tokenize(germanText); console.log(`German: ${resultDe.text}`); // French example const frenchText = "Je m'appelle Marie Dupont, email: marie@exemple.fr, tél: +33 1 42 86 82 00"; const resultFr = await client.tokenize(frenchText); console.log(`French: ${resultFr.text}`); // Mixed languages in one request const mixedText = "Contact: John Doe (john@example.com), Client: María García (maria@ejemplo.es)"; const resultMixed = await client.tokenize(mixedText); console.log(`Mixed: ${resultMixed.text}`); ``` **Native Language Support (Tier 1 - Highest Accuracy):** * 🇺🇸 English, 🇩🇪 German, 🇫🇷 French, 🇪🇸 Spanish, 🇮🇹 Italian, 🇵🇹 Portuguese, 🇳🇱 Dutch, 🇵🇱 Polish, 🇷🇺 Russian **Zero-Shot Support (Tier 2 - High Accuracy):** * 🇨🇿 Czech, 🇸🇰 Slovak, 🇩🇰 Danish, 🇸🇪 Swedish, 🇳🇴 Norwegian, 🇷🇴 Romanian **Key Features:** * Automatic detection - no language parameter needed * Mix multiple languages in the same request * Works on 15+ languages without configuration ### Custom Entity Detection Define custom entities for industry-specific identifiers using zero-shot learning. ```python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key") # E-commerce example with custom entities order_text = "Order #ORD-2024-XYZ for customer CUST-456, SKU: PROD-789-BLU" result = client.tokenize( order_text, entities=["order number", "customer id", "product sku"] ) print(result.text) # Output: "Order # for customer , SKU: " # Healthcare example with custom entities medical_text = "Patient admitted to Ward 5B, Doctor ID: DOC-123, Procedure Code: PROC-456" result = client.tokenize( medical_text, entities=["ward number", "doctor identifier", "procedure code"] ) print(result.text) # Mix standard and custom entities mixed_text = "Customer John Doe (ID: CUST-789) ordered item SKU-456 on 2024-01-15" result = client.tokenize( mixed_text, entities=["PERSON", "EMAIL_ADDRESS", "customer id", "product sku", "DATE_TIME"] ) print(result.text) # Detects both standard PII (PERSON, DATE_TIME) and custom entities (customer id, product sku) ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); // E-commerce example with custom entities const orderText = "Order #ORD-2024-XYZ for customer CUST-456, SKU: PROD-789-BLU"; const result = await client.tokenize( orderText, { entities: ["order number", "customer id", "product sku"] } ); console.log(result.text); // Healthcare example with custom entities const medicalText = "Patient admitted to Ward 5B, Doctor ID: DOC-123, Procedure Code: PROC-456"; const result2 = await client.tokenize( medicalText, { entities: ["ward number", "doctor identifier", "procedure code"] } ); console.log(result2.text); // Mix standard and custom entities const mixedText = "Customer John Doe (ID: CUST-789) ordered item SKU-456 on 2024-01-15"; const result3 = await client.tokenize( mixedText, { entities: ["PERSON", "EMAIL_ADDRESS", "customer id", "product sku", "DATE_TIME"] } ); console.log(result3.text); ``` **Custom Entity Benefits:** * No training required - describe entities in natural language * Works across any industry or domain * Combine with 40+ pre-trained entity types * Zero-shot detection adapts to your use case *** ## Batch Processing Process multiple texts efficiently in parallel. ```python theme={null} import asyncio from blindfold import AsyncBlindfold async def process_batch(texts: list[str]) -> list: """Process multiple texts concurrently""" async with AsyncBlindfold(api_key="your-api-key") as client: # Process all texts in parallel tasks = [client.tokenize(text) for text in texts] results = await asyncio.gather(*tasks) return results # Example: Process 100 customer messages messages = [ f"Customer {i}: email{i}@example.com" for i in range(100) ] results = asyncio.run(process_batch(messages)) print(f"Processed {len(results)} messages") print(f"Average entities per message: {sum(r.entities_count for r in results) / len(results):.2f}") ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); async function processBatch(texts) { // Process all texts in parallel const results = await Promise.all( texts.map(text => client.tokenize(text)) ); return results; } // Example: Process 100 customer messages const messages = Array.from( { length: 100 }, (_, i) => `Customer ${i}: email${i}@example.com` ); const results = await processBatch(messages); console.log(`Processed ${results.length} messages`); const avgEntities = results.reduce((sum, r) => sum + r.entities_count, 0) / results.length; console.log(`Average entities per message: ${avgEntities.toFixed(2)}`); ``` **Performance Tips:** * Use async/parallel processing for batches * Implement rate limiting * Use connection pooling * Handle errors gracefully *** ## Express.js Middleware Create middleware to automatically protect routes. ```javascript theme={null} import express from 'express'; import { Blindfold } from '@blindfold/sdk'; const app = express(); const client = new Blindfold({ apiKey: process.env.BLINDFOLD_API_KEY }); // Middleware to protect request bodies const protectPII = async (req, res, next) => { try { if (req.body && req.body.text) { const protected = await client.tokenize(req.body.text); // Store mapping in session for later detokenization req.session.tokenMapping = protected.mapping; // Replace text with protected version req.body.text = protected.text; req.body.pii_detected = protected.entities_count; } next(); } catch (error) { res.status(500).json({ error: 'Failed to protect data' }); } }; // Apply middleware to specific routes app.post('/api/chat', express.json(), protectPII, async (req, res) => { // req.body.text is now protected // Process with AI... res.json({ message: 'Processed securely' }); }); app.listen(3000); ``` *** ## Best Practices Summary ### 1. Always Use Environment Variables ```bash theme={null} export BLINDFOLD_API_KEY="your-key-here" export ENCRYPTION_KEY="your-encryption-key" ``` ### 2. Handle Errors Gracefully ```python theme={null} try: result = client.tokenize(text) except AuthenticationError: # Handle auth error pass except NetworkError: # Retry with exponential backoff pass ``` ### 3. Store Mappings Securely * Use encrypted session storage * Implement TTL for mappings * Clear mappings after use ### 4. Use Appropriate Methods * **Tokenize**: When you need to restore data later * **Mask**: For UI display * **Redact**: For permanent removal * **Hash**: For analytics identifiers * **Synthesize**: For test data ### 5. Monitor Usage * Track API usage in dashboard * Set up rate limit alerts * Monitor error rates ## Cookbook Complete, runnable examples you can clone and use as a starting point. Each example is a self-contained project with setup instructions. Tokenize user messages before GPT, detokenize responses TypeScript/Node.js OpenAI integration PII-safe chains with RunnableLambda PII-safe LangChain.js chains with RunnableLambda EU region, gdpr\_eu policy, batch processing EU region, gdpr\_eu policy — TypeScript Multi-turn chat with hipaa\_us policy, PHI redaction Multi-turn healthcare chatbot — TypeScript AI writes analysis code from tokenized data, E2B runs it on real data AI data analyst with E2B sandbox — TypeScript Auto-tokenize request bodies in FastAPI Auto-tokenize request bodies in Express.js PII-safe RAG with ChromaDB — redact at ingestion, tokenize at query TypeScript RAG pipeline with ChromaDB and PII protection BlindfoldPIITransformer + blindfold\_protect() with FAISS LangChain.js RAG with inline PII protection Custom BlindfoldNodePostprocessor for LlamaIndex LlamaIndex.TS RAG with PII protection GDPR multi-turn EU support chatbot with gdpr\_eu policy TypeScript GDPR multi-turn EU support chatbot ## Need More Examples? Can't find what you're looking for? Check out: Detailed Python SDK documentation Complete JavaScript SDK guide Sync and async Java client HTTP API reference Email us for custom integration help # FAQ Source: https://docs.blindfold.dev/faq Frequently Asked Questions about Blindfold ## General Questions **Your data never leaves your control.** * Text is processed in real-time and not stored * PII mappings are returned to you (not stored by us) * No training on your data * EU data residency (GDPR compliant) * SOC 2 compliant infrastructure **Data flow:** 1. You send text → 2. We detect PII → 3. Return protected text → 4. Data deleted We only store metadata (request counts, API usage) for billing purposes. **Very high accuracy across 60+ entity types:** * **Email addresses**: \~99% accuracy * **Phone numbers**: \~95% accuracy * **Names**: \~90-95% accuracy (varies by language) * **Credit cards**: \~98% accuracy (with Luhn validation) * **Medical records**: \~92% accuracy Detection uses GLiNER, a state-of-the-art AI model trained specifically for PII detection. **Tip**: Use `policy="strict"` for maximum detection or adjust `score_threshold` for your needs. **15+ languages with automatic detection:** **Native Support (Highest Accuracy):** * English, German, French, Spanish, Italian, Portuguese, Dutch, Polish, Russian **Zero-Shot Support (High Accuracy):** * Czech, Slovak, Danish, Swedish, Norwegian, Romanian **Experimental:** * Chinese, Japanese, Arabic No configuration needed - the engine automatically detects the language. Complete language support details **Yes! Use zero-shot detection with natural language descriptions:** ```python theme={null} # Detect custom entities result = client.tokenize( "Order #ORD-2024-XYZ, SKU: PROD-789", entities=["order number", "product sku"] ) ``` **No training required** - just describe what you want to detect in plain English: * `"order number"`, `"booking reference"`, `"employee id"` * `"internal code"`, `"project name"`, `"case number"` * Industry-specific identifiers Mix custom entities with standard ones for complete protection. **Policies are pre-configured entity sets for compliance:** | Policy | Entity Count | Use Case | | ---------- | ------------ | ----------------------------------- | | `basic` | 3 types | General PII (names, emails, phones) | | `gdpr_eu` | 15+ types | European data protection | | `hipaa_us` | 11+ types | US healthcare compliance | | `pci_dss` | 8+ types | Payment card industry | | `strict` | 60+ types | Maximum protection | **Use policies instead of listing entities manually:** ```python theme={null} # ✅ Easy with policy result = client.tokenize(text, policy="gdpr_eu") # ❌ Manual (harder to maintain) result = client.tokenize(text, entities=["person", "email", ...15 more]) ``` **Several strategies to reduce false positives:** **1. Increase Detection Threshold** ```python theme={null} # Only detect high-confidence matches result = client.tokenize( text, entities=["person", "email address"], score_threshold=0.80 # Higher threshold for fewer false positives ) ``` **2. Filter Specific Entity Types** ```python theme={null} # Only detect specific entities result = client.tokenize( text, entities=["email address", "phone number"] # Skip names ) ``` **3. Post-Process Results** ```python theme={null} # Review detected entities before using for entity in result.detected_entities: if entity.score < 0.70: # Skip low-confidence detections continue ``` **4. Use Allowlists** ```python theme={null} # Skip known safe values (implement client-side) safe_values = ["John Doe", "support@company.com"] if original_value not in safe_values: # Apply protection ``` ## Technical Questions **Limits by plan:** | | Free | Pay As You Go | | ------------------------ | ------------ | ----------------- | | **Characters** | 500K / month | Unlimited | | **Max text per request** | 5K chars | 500K chars | | **Price** | \$0 | \$0.50 / 1M chars | **Handling rate limits:** ```python theme={null} import time try: result = client.tokenize(text) except APIError as e: if e.status_code == 429: # Rate limited - wait and retry time.sleep(60) result = client.tokenize(text) ``` Contact us for enterprise limits: [hello@blindfold.dev](mailto:hello@blindfold.dev) **Not recommended - API keys should stay server-side.** **❌ Bad (API key exposed):** ```javascript theme={null} // Client-side code - NEVER do this const client = new Blindfold({ apiKey: 'sk-...' }); ``` **✅ Good (Server-side API route):** ```javascript theme={null} // Client fetch('/api/protect', { method: 'POST', body: JSON.stringify({ text: userInput }) }); // Server (Next.js API route) import { Blindfold } from '@blindfold/sdk'; export async function POST(req) { const client = new Blindfold({ apiKey: process.env.BLINDFOLD_API_KEY // Server-side only }); const { text } = await req.json(); const result = await client.tokenize(text); return Response.json(result); } ``` Use edge functions, serverless functions, or backend API routes. **Use the mapping returned from tokenize():** ```python theme={null} # Step 1: Tokenize protected = client.tokenize("John Doe, john@example.com") print(protected.text) # "< person_1>, " print(protected.mapping) # {"": "John Doe", "": "john@example.com"} # Step 2: Send protected text to AI ai_response = send_to_ai(protected.text) # Step 3: Detokenize AI response original = client.detokenize( text=ai_response, mapping=protected.mapping ) print(original.text) # "Hello John Doe, I received your message at john@example.com" ``` **Important:** * Store `mapping` securely (Redis, encrypted DB, session) * Set expiration (e.g., 24 hours) * Without mapping, data cannot be restored **Choose the right method for your use case:** | Method | Reversible | Example | Use Case | | -------------- | ---------- | ------------------- | ----------------------- | | **Tokenize** | ✅ Yes | `` | AI processing, chatbots | | **Mask** | ❌ No | `***3456` | Display to users | | **Redact** | ❌ No | \`\` (removed) | Permanent removal | | **Hash** | ❌ No | `ID_a3f8b9` | Analytics, matching | | **Encrypt** | ✅ Yes | `gAAAAABh...` | Secure storage | | **Synthesize** | ❌ No | `Jane Smith` (fake) | Testing, demos | **Example workflows:** ```python theme={null} # AI Chatbot → Use tokenize (reversible) protected = client.tokenize(user_input) ai_response = send_to_ai(protected.text) final = client.detokenize(ai_response, protected.mapping) # Display to User → Use mask (show last 4) masked = client.mask("Card: 4532-7562-9102-3456") # "Card: ***************3456" # Audit Logs → Use redact (permanent) logged = client.redact("User SSN: 123-45-6789") # "User SSN: " # Analytics → Use hash (consistent IDs) hashed = client.hash("user@example.com") # "ID_a3f8b9c2d4e5f6g7" (always same for same input) ``` **Yes! Blindfold is provider-agnostic.** The pattern is always the same: tokenize, send to AI, detokenize. * ✅ OpenAI (GPT-4o, GPT-4, o1) * ✅ Anthropic (Claude Sonnet, Opus, Haiku) * ✅ Google (Gemini 2.5 Flash, Pro) * ✅ AWS Bedrock, Azure OpenAI * ✅ LangChain, LlamaIndex, Vercel AI SDK * ✅ Cohere, Hugging Face, self-hosted models * ✅ Any LLM API ```python theme={null} from blindfold import Blindfold from openai import OpenAI bf = Blindfold() client = OpenAI() safe = bf.tokenize(user_input) response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": safe.text}] ) result = bf.detokenize(response.choices[0].message.content, safe.mapping) ``` ```python theme={null} from blindfold import Blindfold import anthropic bf = Blindfold() client = anthropic.Anthropic() safe = bf.tokenize(user_input) response = client.messages.create( model="claude-sonnet-4-20250514", max_tokens=1024, messages=[{"role": "user", "content": safe.text}] ) result = bf.detokenize(response.content[0].text, safe.mapping) ``` ```python theme={null} from blindfold import Blindfold from google import genai bf = Blindfold() client = genai.Client() safe = bf.tokenize(user_input) response = client.models.generate_content( model="gemini-2.5-flash", contents=safe.text ) result = bf.detokenize(response.text, safe.mapping) ``` ```python theme={null} from blindfold import Blindfold bf = Blindfold() safe = bf.tokenize(user_input) response = your_ai_provider.chat(safe.text) result = bf.detokenize(response, safe.mapping) ``` Code examples for every major AI provider and framework **Yes! All SDKs include local mode** with 80+ regex-based entity types, zero dependencies, and no API key required. In local mode, **no data ever leaves your infrastructure** — everything runs in-process with no network calls. ```python theme={null} from blindfold import Blindfold # No API key needed client = Blindfold() result = client.tokenize("Contact john@example.com or call +1-555-1234") ``` **Local mode vs Cloud API:** | | Local Mode | Cloud API | | ----------------------- | -------------------------------- | ------------------------------ | | **Entity types** | 80+ (regex-based) | 60+ NLP + 80+ regex | | **API key** | Not needed | Required | | **Data privacy** | Never leaves your infrastructure | Processed in EU/US, not stored | | **Names & addresses** | Not supported | NLP-powered detection | | **Compliance policies** | Not available | GDPR, HIPAA, PCI DSS | | **Audit logs** | Not available | Full audit trail | **Upgrade path:** When you need NLP-powered detection (names, addresses, organizations), compliance policies, or audit logs, add an API key to switch to the Cloud API. ## Compliance & Privacy **Yes, Blindfold is GDPR compliant:** * ✅ EU data residency (servers in EU) * ✅ No data storage (real-time processing) * ✅ Data Processing Agreement (DPA) available * ✅ Regular security audits **Using Blindfold helps YOU be GDPR compliant:** * Prevents PII from reaching third-party AI providers * Meets "data minimization" requirements * Supports "right to be forgotten" * Enables lawful AI processing Contact us for DPA: [hello@blindfold.dev](mailto:hello@blindfold.dev) **Yes, for healthcare applications:** * ✅ Use `policy="hipaa_us"` for healthcare data * ✅ Detects PHI (Protected Health Information) * ✅ Business Associate Agreement (BAA) available * ✅ Encrypted data transmission **Protected entities:** * Names, SSN, medical record numbers * Health insurance IDs * Medical conditions, medications * Dates of birth ```python theme={null} # HIPAA-compliant processing result = client.tokenize( patient_data, policy="hipaa_us" ) ``` Contact us for BAA: [hello@blindfold.dev](mailto:hello@blindfold.dev) **Yes, DPAs are available for all paid plans.** **What's included:** * Data processing terms * Security measures * Subprocessor list * Your rights and obligations * Incident response procedures **To request a DPA:** * Email: [hello@blindfold.dev](mailto:hello@blindfold.dev) * Subject: "DPA Request" * Include: Company name, plan tier Standard DPAs provided within 2 business days. ## Pricing & Plans **Yes! Free tier includes:** * ✅ 500K characters per month * ✅ All 60+ entity types * ✅ All global policies * ✅ 18 languages supported * ✅ 3 team members, 2 API keys * ✅ Dashboard & audit logs **Perfect for:** * Testing and development * Proof of concepts * Small projects Get started in 5 minutes **Usage is measured in input characters processed:** * Each API call counts the number of characters in the `text` field * Batch requests count total characters across all texts * Policy management and dashboard usage are free **Example:** * "Hello, my name is John Doe" = 26 characters * A 1,000-word email ≈ 5,000 characters **Free plan:** 500K characters/month included. **Pay As You Go:** \$0.50 per 1M characters, no limit. Billed monthly via Stripe. ## Still Have Questions? Email us at **[hello@blindfold.dev](mailto:hello@blindfold.dev)** - we typically respond within 24 hours # Getting Started Source: https://docs.blindfold.dev/getting-started Complete guide to integrating Blindfold with your AI application This guide walks you through integrating Blindfold with an AI application from start to finish. By the end, you'll have a working chatbot that protects user PII before sending data to OpenAI. **Estimated time:** 15-20 minutes ## What You'll Build A privacy-preserving AI chatbot that: 1. Accepts user input with sensitive data 2. Detects and tokenizes PII automatically 3. Sends protected text to OpenAI 4. Restores original data in the response 5. Handles errors gracefully ## Prerequisites * Python 3.8+, Node.js 16+, or Java 11+ installed * OpenAI API key ([get one here](https://platform.openai.com/api-keys)) * Blindfold API key ([sign up](https://app.blindfold.dev)) **Local mode is free forever.** All SDKs include local mode with 86 regex-based entity types and all 8 operations — no API key, no signup, no network calls, no data leaves your infrastructure. Just install the SDK and use `Blindfold()` with no arguments. You only need the Cloud API below if you want NLP-powered detection (names, addresses, organizations) and compliance policies. ## Step 1: Install Dependencies ```bash theme={null} pip install blindfold-sdk openai python-dotenv ``` ```bash theme={null} npm install @blindfold/sdk openai dotenv ``` ```xml theme={null} dev.blindfold blindfold-sdk 1.0.0 ``` ## Step 2: Set Up Environment Variables Create a `.env` file in your project root: ```bash theme={null} # .env BLINDFOLD_API_KEY=your_blindfold_api_key_here OPENAI_API_KEY=your_openai_api_key_here ``` Never commit `.env` files to version control. Add `.env` to your `.gitignore` file. ## Step 3: Create the Privacy-Preserving Chatbot Create `privacy_chatbot.py`: ```python theme={null} import os from blindfold import Blindfold from openai import OpenAI from dotenv import load_dotenv # Load environment variables load_dotenv() # Initialize clients blindfold = Blindfold(api_key=os.getenv("BLINDFOLD_API_KEY")) openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) def chat_with_privacy(user_message: str) -> str: """ Process user message with PII protection """ print(f"\n👤 User: {user_message}") # Step 1: Tokenize sensitive data using GDPR policy try: protected = blindfold.tokenize( text=user_message, policy="gdpr_eu" # GDPR-compliant detection ) print(f"🔒 Protected: {protected.text}") print(f"🏷️ Detected {protected.entities_count} PII items") except Exception as e: print(f"❌ Error tokenizing: {e}") return "Sorry, I couldn't process your message securely." # Step 2: Send protected text to OpenAI try: completion = openai_client.chat.completions.create( model="gpt-4", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": protected.text} ] ) ai_response = completion.choices[0].message.content print(f"🤖 AI (protected): {ai_response}") except Exception as e: print(f"❌ Error calling OpenAI: {e}") return "Sorry, I encountered an error with the AI service." # Step 3: Restore original data in response try: final_response = blindfold.detokenize( text=ai_response, mapping=protected.mapping ) print(f"✅ Final response: {final_response.text}") return final_response.text except Exception as e: print(f"❌ Error detokenizing: {e}") # If detokenization fails, return protected response return ai_response # Example usage if __name__ == "__main__": # Test with sensitive data messages = [ "My name is John Doe and my email is john@example.com", "I live at 123 Main Street, Boston, MA 02101", "My phone number is +1-555-123-4567" ] for message in messages: response = chat_with_privacy(message) print("-" * 80) ``` Run it: ```bash theme={null} python privacy_chatbot.py ``` Create `privacy-chatbot.js`: ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; import OpenAI from 'openai'; import dotenv from 'dotenv'; // Load environment variables dotenv.config(); // Initialize clients const blindfold = new Blindfold({ apiKey: process.env.BLINDFOLD_API_KEY }); const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); async function chatWithPrivacy(userMessage) { console.log(`\n👤 User: ${userMessage}`); // Step 1: Tokenize sensitive data using GDPR policy let protected; try { protected = await blindfold.tokenize(userMessage, { policy: "gdpr_eu" // GDPR-compliant detection }); console.log(`🔒 Protected: ${protected.text}`); console.log(`🏷️ Detected ${protected.entities_count} PII items`); } catch (error) { console.error(`❌ Error tokenizing: ${error.message}`); return "Sorry, I couldn't process your message securely."; } // Step 2: Send protected text to OpenAI let aiResponse; try { const completion = await openai.chat.completions.create({ model: "gpt-4", messages: [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: protected.text } ] }); aiResponse = completion.choices[0].message.content; console.log(`🤖 AI (protected): ${aiResponse}`); } catch (error) { console.error(`❌ Error calling OpenAI: ${error.message}`); return "Sorry, I encountered an error with the AI service."; } // Step 3: Restore original data in response try { const finalResponse = await blindfold.detokenize( aiResponse, protected.mapping ); console.log(`✅ Final response: ${finalResponse.text}`); return finalResponse.text; } catch (error) { console.error(`❌ Error detokenizing: ${error.message}`); // If detokenization fails, return protected response return aiResponse; } } // Example usage async function main() { const messages = [ "My name is John Doe and my email is john@example.com", "I live at 123 Main Street, Boston, MA 02101", "My phone number is +1-555-123-4567" ]; for (const message of messages) { await chatWithPrivacy(message); console.log("-".repeat(80)); } } main().catch(console.error); ``` Run it: ```bash theme={null} node privacy-chatbot.js ``` ## Step 4: Understanding the Output When you run the chatbot, you'll see: ``` 👤 User: My name is John Doe and my email is john@example.com 🔒 Protected: My name is and my email is 🏷️ Detected 2 PII items 🤖 AI (protected): Hello ! I received your email at . ✅ Final response: Hello John Doe! I received your email at john@example.com. ``` **What happened:** 1. ✅ PII detected and tokenized 2. ✅ OpenAI never saw real names or emails 3. ✅ User receives personalized response 4. ✅ GDPR compliance maintained ## Step 5: Add Different Privacy Methods ### Masking (Show Last 4 Digits) ```python theme={null} # Python result = blindfold.mask( "Credit card: 4532-7562-9102-3456", policy="pci_dss" ) # Output: "Credit card: ***************3456" ``` ```javascript theme={null} // JavaScript const result = await blindfold.mask( "Credit card: 4532-7562-9102-3456", { policy: "pci_dss" } ); // Output: "Credit card: ***************3456" ``` ### Redaction (Permanent Removal) ```python theme={null} # Python result = blindfold.redact( "Patient: Jane Smith, SSN: 123-45-6789", policy="hipaa_us" ) # Output: "Patient: , SSN: " ``` ```javascript theme={null} // JavaScript const result = await blindfold.redact( "Patient: Jane Smith, SSN: 123-45-6789", { policy: "hipaa_us" } ); // Output: "Patient: , SSN: " ``` ## Step 6: Production Best Practices ### Store Mappings Securely ```python theme={null} import redis import json redis_client = redis.Redis(host='localhost', port=6379) # After tokenizing protected = blindfold.tokenize(user_message, policy="gdpr_eu") # Store mapping with expiration (24 hours) session_id = "user_session_123" redis_client.setex( f"mapping:{session_id}", 86400, # 24 hours json.dumps(protected.mapping) ) # Later, retrieve for detokenization mapping = json.loads(redis_client.get(f"mapping:{session_id}")) original = blindfold.detokenize(ai_response, mapping) ``` ```javascript theme={null} import { createClient } from 'redis'; const redis = createClient(); await redis.connect(); // After tokenizing const protected = await blindfold.tokenize(userMessage, { policy: "gdpr_eu" }); // Store mapping with expiration (24 hours) const sessionId = "user_session_123"; await redis.setEx( `mapping:${sessionId}`, 86400, // 24 hours JSON.stringify(protected.mapping) ); // Later, retrieve for detokenization const mapping = JSON.parse(await redis.get(`mapping:${sessionId}`)); const original = await blindfold.detokenize(aiResponse, mapping); ``` ### Handle Errors Gracefully ```python theme={null} # Python from blindfold import Blindfold, AuthenticationError, APIError try: result = blindfold.tokenize(text, policy="gdpr_eu") except AuthenticationError: # Invalid API key - notify admin logger.error("Blindfold API key is invalid") return "Service temporarily unavailable" except APIError as e: # API error with status code logger.error(f"Blindfold API error ({e.status_code}): {e.message}") return "Unable to process request securely" except Exception as e: # Unexpected error logger.error(f"Unexpected error: {e}") return "An error occurred" ``` ```javascript theme={null} // JavaScript import { Blindfold, AuthenticationError, APIError } from '@blindfold/sdk'; try { const result = await blindfold.tokenize(text, { policy: "gdpr_eu" }); } catch (error) { if (error instanceof AuthenticationError) { // Invalid API key - notify admin logger.error("Blindfold API key is invalid"); return "Service temporarily unavailable"; } else if (error instanceof APIError) { // API error with status code logger.error(`Blindfold API error (${error.statusCode}): ${error.message}`); return "Unable to process request securely"; } else { // Unexpected error logger.error(`Unexpected error: ${error.message}`); return "An error occurred"; } } ``` ### Use Async for Better Performance ```python theme={null} # Python import asyncio from blindfold import AsyncBlindfold async def process_batch(messages): async with AsyncBlindfold(api_key=api_key) as client: # Process multiple messages concurrently tasks = [ client.tokenize(msg, policy="gdpr_eu") for msg in messages ] results = await asyncio.gather(*tasks) return results ``` ```javascript theme={null} // JavaScript async function processBatch(messages) { // Process multiple messages concurrently const promises = messages.map(msg => blindfold.tokenize(msg, { policy: "gdpr_eu" }) ); const results = await Promise.all(promises); return results; } ``` ## Next Steps See all 60+ entity types Learn about GDPR, HIPAA, PCI DSS policies Production deployment tips More integration examples ## Troubleshooting ### "Invalid API key" error * Check your `.env` file has the correct API key * Verify the API key in your dashboard * Ensure `load_dotenv()` (Python) or `dotenv.config()` (JavaScript) is called ### Entities not detected * Try lowering the threshold: `score_threshold=0.25` * Use `policy="strict"` for maximum detection * Check if text is in a supported language ### Performance is slow * Use async methods for concurrent requests * Batch multiple tokenize calls together * Consider caching results for duplicate text ## Get Help Questions? Contact **[hello@blindfold.dev](mailto:hello@blindfold.dev)** # Introduction Source: https://docs.blindfold.dev/index Open source PII detection SDK for AI applications — protect sensitive data before sending to OpenAI, Anthropic Claude, Google Gemini, or any LLM ## What is Blindfold? **Open source PII SDKs for AI applications.** Protect sensitive data before sending to OpenAI, Anthropic Claude, Google Gemini, or any LLM. Install the SDK, detect and tokenize PII locally — no API key, no signup, no network calls. Free forever. Need NLP-powered detection (names, addresses, organizations), compliance policies, or audit logs? Upgrade to the Cloud API. 86 regex entity types, all 8 operations, zero network calls — your data never leaves your infrastructure 60+ NLP entity types, custom entities, compliance policies, audit logs — pay only for what you use Tokenize PII before sending to AI, restore original data after Meet GDPR, HIPAA, PCI DSS, and EU AI Act requirements ## How It Works Your application sends user data to Blindfold PII is replaced with tokens like ``, `` Protected text goes to OpenAI, Anthropic Claude, Google Gemini, or any LLM without exposing PII Convert AI response back to original data ## Privacy Methods Reversible tokens for AI processing Show last 4 digits (e.g., `***3456`) Permanent removal Consistent IDs for analytics Fake data for testing AES-256 encryption ## Works With GPT-4o, GPT-4, o1 Sonnet, Opus, Haiku Gemini 2.5 Flash, Pro Official integration Node postprocessor generateText, streamText All Bedrock models Provider-agnostic SDK ## What Can Blindfold Protect? Names, emails, SSNs, credit cards, medical records, passports, and more English, Spanish, German, French, Italian, and 10+ more Define your own using natural language descriptions Pre-configured for GDPR, HIPAA, PCI DSS compliance ## Start in 5 Minutes (Free) Install the SDK and start detecting PII immediately — no signup, no API key, free forever. ```bash theme={null} pip install blindfold-sdk ``` ```bash theme={null} npm install @blindfold/sdk ``` ```xml theme={null} dev.blindfold:blindfold-sdk ``` ```bash theme={null} go get github.com/blindfold-dev/Blindfold/packages/go-sdk ``` ```bash theme={null} dotnet add package Blindfold.Sdk ``` ```bash theme={null} curl https://api.blindfold.dev ``` Try local mode instantly or set up the Cloud API in under 5 minutes ## Popular Use Cases Tokenize PII before OpenAI, Anthropic Claude, or Google Gemini processes user messages Redact PII at ingestion, tokenize at query time — PII never reaches your vector DB or LLM Protect sensitive data in multi-step agent workflows (CrewAI, LangChain agents, custom) Meet GDPR, HIPAA, PCI DSS, and EU AI Act requirements with built-in policies ## Documentation Complete guide with async support Node.js and browser support Sync and async clients, Maven/Gradle Zero dependencies, context-aware async/await, net6.0/net8.0 Use with any programming language 60+ entity types detected 15+ supported languages Real-world code examples ## Need Help? Questions? Contact us at **[hello@blindfold.dev](mailto:hello@blindfold.dev)** # AI Integrations Source: https://docs.blindfold.dev/integrations Protect PII before sending to OpenAI, Anthropic Claude, Google Gemini, LangChain, LlamaIndex, Vercel AI SDK, AWS Bedrock, Azure OpenAI, or any LLM Blindfold is provider-agnostic. The pattern is always the same: **tokenize** sensitive data, send safe text to your AI provider, then **detokenize** the response to restore original values. ## OpenAI ```python theme={null} from blindfold import Blindfold from openai import OpenAI bf = Blindfold() # Free local mode, or add api_key="..." for NLP openai = OpenAI() # Tokenize PII safe = bf.tokenize("My name is John Smith, email john@acme.com") # Send to GPT — PII never reaches OpenAI response = openai.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": safe.text}] ) # Restore original data result = bf.detokenize(response.choices[0].message.content, safe.mapping) print(result.text) ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; import OpenAI from 'openai'; const bf = new Blindfold(); // Free local mode const openai = new OpenAI(); // Tokenize PII const safe = await bf.tokenize("My name is John Smith, email john@acme.com"); // Send to GPT — PII never reaches OpenAI const response = await openai.chat.completions.create({ model: 'gpt-4o', messages: [{ role: 'user', content: safe.text }] }); // Restore original data const result = bf.detokenize(response.choices[0].message.content, safe.mapping); console.log(result.text); ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold bf = new Blindfold(); // Free local mode // Tokenize PII var safe = bf.tokenize("My name is John Smith, email john@acme.com"); // Send to GPT — PII never reaches OpenAI String aiResponse = callOpenAI(safe.getText()); // Restore original data var result = bf.detokenize(aiResponse, safe.getMapping()); System.out.println(result.getText()); ``` ## Anthropic Claude ```python theme={null} from blindfold import Blindfold import anthropic bf = Blindfold() client = anthropic.Anthropic() safe = bf.tokenize("My name is John Smith, email john@acme.com") response = client.messages.create( model="claude-sonnet-4-20250514", max_tokens=1024, messages=[{"role": "user", "content": safe.text}] ) result = bf.detokenize(response.content[0].text, safe.mapping) print(result.text) ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; import Anthropic from '@anthropic-ai/sdk'; const bf = new Blindfold(); const anthropic = new Anthropic(); const safe = await bf.tokenize("My name is John Smith, email john@acme.com"); const response = await anthropic.messages.create({ model: 'claude-sonnet-4-20250514', max_tokens: 1024, messages: [{ role: 'user', content: safe.text }] }); const result = bf.detokenize(response.content[0].text, safe.mapping); console.log(result.text); ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold bf = new Blindfold(); var safe = bf.tokenize("My name is John Smith, email john@acme.com"); // Send to Claude via your preferred Anthropic Java client String aiResponse = callClaude(safe.getText()); var result = bf.detokenize(aiResponse, safe.getMapping()); System.out.println(result.getText()); ``` ## Google Gemini ```python theme={null} from blindfold import Blindfold from google import genai bf = Blindfold() client = genai.Client() safe = bf.tokenize("My name is John Smith, email john@acme.com") response = client.models.generate_content( model="gemini-2.5-flash", contents=safe.text ) result = bf.detokenize(response.text, safe.mapping) print(result.text) ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; import { GoogleGenAI } from '@google/genai'; const bf = new Blindfold(); const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY }); const safe = await bf.tokenize("My name is John Smith, email john@acme.com"); const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: safe.text }); const result = bf.detokenize(response.text, safe.mapping); console.log(result.text); ``` ## Vercel AI SDK ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; import { generateText } from 'ai'; import { openai } from '@ai-sdk/openai'; const bf = new Blindfold(); const safe = await bf.tokenize("My name is John Smith, email john@acme.com"); const { text } = await generateText({ model: openai('gpt-4o'), prompt: safe.text }); const result = bf.detokenize(text, safe.mapping); console.log(result.text); ``` ## AWS Bedrock ```python theme={null} from blindfold import Blindfold import boto3 import json bf = Blindfold() bedrock = boto3.client("bedrock-runtime", region_name="us-east-1") safe = bf.tokenize("My name is John Smith, email john@acme.com") response = bedrock.invoke_model( modelId="anthropic.claude-sonnet-4-20250514-v1:0", body=json.dumps({ "anthropic_version": "bedrock-2023-05-31", "max_tokens": 1024, "messages": [{"role": "user", "content": safe.text}] }) ) body = json.loads(response["body"].read()) result = bf.detokenize(body["content"][0]["text"], safe.mapping) print(result.text) ``` ## Azure OpenAI ```python theme={null} from blindfold import Blindfold from openai import AzureOpenAI bf = Blindfold() client = AzureOpenAI( azure_endpoint="https://your-resource.openai.azure.com", api_version="2024-02-15-preview" ) safe = bf.tokenize("My name is John Smith, email john@acme.com") response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": safe.text}] ) result = bf.detokenize(response.choices[0].message.content, safe.mapping) print(result.text) ``` ## Framework Integrations Official `langchain-blindfold` package with BlindfoldPIITransformer and RunnableLambda support Official `guardrails-blindfold` validator for PII protection in Guardrails pipelines Official Blindfold MCP server for Claude Desktop and any MCP client ## CrewAI ```python theme={null} from blindfold import Blindfold from crewai import Agent, Task, Crew bf = Blindfold() user_input = "Analyze the account for John Smith, SSN 123-45-6789" safe = bf.tokenize(user_input) analyst = Agent( role="Data Analyst", goal="Analyze user accounts", backstory="You are a helpful analyst." ) task = Task( description=safe.text, # PII-free input agent=analyst, expected_output="Account analysis" ) crew = Crew(agents=[analyst], tasks=[task]) output = crew.kickoff() result = bf.detokenize(output.raw, safe.mapping) print(result.text) ``` ## Works with any provider The pattern is always the same regardless of provider: ```python theme={null} from blindfold import Blindfold bf = Blindfold() # Free local mode, or add api_key="..." for NLP # 1. Tokenize PII safe = bf.tokenize(user_input) # "Hi, I'm John Smith" → "Hi, I'm " # 2. Send to any AI provider response = your_ai_provider.chat(safe.text) # 3. Restore original data result = bf.detokenize(response, safe.mapping) ``` Start protecting PII in 5 minutes — install the SDK, no signup required for local mode # Detection Source: https://docs.blindfold.dev/methods/detection Detect PII in text without modifying it ## What is Detection? Detection is a read-only analysis method that identifies sensitive data in text without transforming it. The original text is not modified — you only receive a list of detected entities with their types, positions, and confidence scores. **Example:** ``` Input: "Contact John Doe at john@example.com" Output: [{type: "Person", text: "John Doe", start: 8, end: 16, score: 0.99}, {type: "Email Address", text: "john@example.com", start: 20, end: 36, score: 0.98}] ``` ## How It Works 1. **Detection**: Blindfold identifies sensitive entities in your text 2. **Report**: Returns entity types, positions, confidence scores, and matched text 3. **No transformation**: The original text is not modified, masked, or returned ## When to Use Detection Detection is ideal when you need to: ### 1. Data Loss Prevention (DLP) Monitor what sensitive data flows through your AI agents or applications. ```python theme={null} # Check if user input contains sensitive data before processing result = client.detect(user_input, policy="strict") if result.entities_count > 0: log_violation(user_id, result.detected_entities) block_or_alert() ``` **Why this matters:** * Know what PII is flowing through your systems * Enforce data handling policies automatically * Create audit trails for compliance ### 2. Compliance Monitoring Continuously scan data streams to detect policy violations. ```python theme={null} # Scan customer support messages for HIPAA violations result = client.detect(support_message, policy="hipaa_us") critical_types = {"Social Security Number", "Medical Condition", "Medication"} found_types = {e.type for e in result.detected_entities} if found_types & critical_types: alert_compliance_team(found_types) ``` ### 3. Data Auditing Understand what PII exists in your datasets before processing. ```python theme={null} # Audit a batch of records for record in records: result = client.detect(record) for entity in result.detected_entities: audit_log.append({ "type": entity.type, "confidence": entity.score }) ``` ### 4. Pre-Processing Checks Decide which privacy method to apply based on what's detected. ```python theme={null} # Route to different processing based on detected PII result = client.detect(text, policy="strict") entity_types = {e.type for e in result.detected_entities} if "Credit Card Number" in entity_types: # Mask credit cards processed = client.mask(text, policy="pci_dss") elif "Social Security Number" in entity_types: # Redact SSNs completely processed = client.redact(text, policy="hipaa_us") else: # Tokenize everything else processed = client.tokenize(text) ``` ## When NOT to Use Detection Detection is **not suitable** when: ### 1. You Need to Transform the Text If you need to remove, mask, or replace PII, use the appropriate method directly. ```python theme={null} # Detection only tells you WHAT is there — it doesn't change anything result = client.detect("SSN: 123-45-6789") # result.detected_entities → [{type: "Social Security Number", ...}] # But the text is unchanged! # Use redact, mask, tokenize, etc. to actually transform redacted = client.redact("SSN: 123-45-6789") ``` ### 2. You Already Know You Want a Specific Method If you know you want tokenization or redaction, call that method directly — it already returns detected entities in its response. ## Key Features Text is analyzed but never modified No transformation overhead — fastest method Use GDPR, HIPAA, PCI DSS, or custom policies Detects all supported PII types ## Quick Start ```python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key") result = client.detect( "Patient Jane Smith (DOB: 1985-04-12, SSN: 123-45-6789) prescribed Metformin", policy="hipaa_us" ) print(f"Found {result.entities_count} entities") for entity in result.detected_entities: print(f"- {entity.type}: {entity.text} (confidence: {entity.score:.2f})") # - Person: Jane Smith (confidence: 0.99) # - Date of Birth: 1985-04-12 (confidence: 0.94) # - Social Security Number: 123-45-6789 (confidence: 0.97) # - Medication: Metformin (confidence: 0.99) ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); const result = await client.detect( "Patient Jane Smith (DOB: 1985-04-12, SSN: 123-45-6789) prescribed Metformin", { policy: "hipaa_us" } ); console.log(`Found ${result.entities_count} entities`); result.detected_entities.forEach(entity => { console.log(`- ${entity.type}: ${entity.text} (confidence: ${entity.score.toFixed(2)})`); }); ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold client = new Blindfold("your-api-key"); var result = client.detect( "Patient Jane Smith (DOB: 1985-04-12, SSN: 123-45-6789) prescribed Metformin" ); System.out.println("Found " + result.getEntitiesCount() + " entities"); for (var entity : result.getDetectedEntities()) { System.out.printf("- %s: %s (confidence: %.2f)%n", entity.getType(), entity.getText(), entity.getScore()); } // - Person: Jane Smith (confidence: 0.99) // - Date of Birth: 1985-04-12 (confidence: 0.94) // - Social Security Number: 123-45-6789 (confidence: 0.97) // - Medication: Metformin (confidence: 0.99) ``` ```bash theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/detect \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "text": "Patient Jane Smith (DOB: 1985-04-12, SSN: 123-45-6789) prescribed Metformin", "policy": "hipaa_us" }' # Response { "entities_count": 4, "detected_entities": [ { "type": "Person", "text": "Jane Smith", "start": 8, "end": 18, "score": 0.99 }, { "type": "Date of Birth", "text": "1985-04-12", "start": 25, "end": 35, "score": 0.94 }, { "type": "Social Security Number", "text": "123-45-6789", "start": 42, "end": 53, "score": 0.97 }, { "type": "Medication", "text": "Metformin", "start": 66, "end": 75, "score": 0.99 } ] } ``` ## Configuration Options ### Filter Specific Entity Types Only detect specific types of sensitive data: ```python theme={null} result = client.detect( "John Doe (SSN: 123-45-6789) paid with card 4532-7562-9102-3456", entities=["social security number", "credit card number"] ) # Only SSN and credit card entities returned ``` ### Adjust Confidence Threshold Control detection sensitivity: ```python theme={null} # Only high-confidence detections result = client.detect( text="Maybe email: test@test", score_threshold=0.8 ) ``` ## Common Patterns ### DLP Agent Gate Block sensitive data from reaching AI models: ```python theme={null} def safe_ai_call(user_message: str) -> str: """Only send to AI if no critical PII detected""" scan = client.detect(user_message, policy="strict") critical = {"Social Security Number", "Credit Card Number"} found = {e.type for e in scan.detected_entities} if found & critical: return "I cannot process messages containing SSNs or credit card numbers." return call_ai_model(user_message) ``` ### Compliance Dashboard Aggregate PII detection across your application: ```python theme={null} def log_pii_detection(user_id: str, text: str) -> None: """Log PII detections for compliance reporting""" result = client.detect(text, policy="gdpr_eu") if result.entities_count > 0: compliance_db.insert({ "user_id": user_id, "timestamp": datetime.utcnow(), "entity_types": [e.type for e in result.detected_entities], "entity_count": result.entities_count, }) ``` ## Learn More Full Python SDK documentation Complete JavaScript guide Sync and async Java client HTTP API reference for /detect Practical integration examples ## Compare with Other Methods Reversible replacement (restore later) Permanent removal of PII Partial visibility for users Consistent identifiers for tracking # Encryption Source: https://docs.blindfold.dev/methods/encryption Encrypt sensitive data using AES encryption ## What is Encryption? Encryption is a reversible privacy protection method that transforms sensitive data into encrypted ciphertext using AES (Advanced Encryption Standard). The data can be decrypted later using the same encryption key. **Example:** ``` Input: "API Key: sk-1234567890abcdef" Output: "API Key: gAAAAABh3K7x9p2Q..." # With key, can decrypt back to original Decrypt: "API Key: sk-1234567890abcdef" ``` ## How It Works 1. **Detection**: Blindfold identifies sensitive entities in your text 2. **Encryption**: Each entity is encrypted using AES-256 encryption 3. **Key-Based**: Encryption uses your provided key or tenant-specific default 4. **Reversible**: Data can be decrypted using the same key ## When to Use Encryption Encryption is ideal when you need to: ### 1. Secure Storage of Sensitive Configuration Encrypt API keys, tokens, and secrets before storing in databases. ```python theme={null} # Encrypt before storing config = "Database password: my_secret_pass123" encrypted = client.encrypt( config, encryption_key="your-secure-key-min-16-chars" ) # Store encrypted version database.save('config', encrypted.text) # Later, decrypt when needed # (Note: decrypt endpoint needs to be implemented) ``` **Why this matters:** * Secrets protected at rest * Can be decrypted when needed * Centralized key management ### 2. Protect Data in Transit Encrypt sensitive data before sending through untrusted channels. ```python theme={null} # Encrypt before sending message = "Credit card: 4532-7562-9102-3456" encrypted = client.encrypt(message, encryption_key=SHARED_KEY) # Send encrypted version send_to_partner(encrypted.text) # Partner decrypts with same key ``` ### 3. Temporary Data Protection Protect data temporarily while it's being processed. ```python theme={null} # Encrypt user data during processing user_data = client.encrypt( sensitive_user_info, encryption_key=SESSION_KEY ) # Process encrypted data process_queue.add(user_data.text) # Decrypt when ready to use ``` ### 4. Compliance Requirements Meet encryption requirements for regulatory compliance (HIPAA, PCI-DSS, etc.). ```python theme={null} # Encrypt medical records patient_record = "Patient SSN: 123-45-6789, Diagnosis: ..." encrypted = client.encrypt( patient_record, encryption_key=HIPAA_KEY ) # Store in HIPAA-compliant manner secure_db.save(encrypted.text) ``` ## When NOT to Use Encryption Encryption is **not suitable** when: ### 1. You Don't Need Reversibility If you never need the original data, use **Redaction** or **Hashing**. ```python theme={null} # Bad - unnecessary encryption encrypted = client.encrypt("Log entry with john@example.com") # Never decrypted # Good - use redaction redacted = client.redact("Log entry with john@example.com") ``` ### 2. Users Need to See Partial Data For UI display, use **Masking** instead. ```python theme={null} # Bad - user can't see anything useful encrypted = client.encrypt("Card: 4532-7562-9102-3456") # Output: "Card: gAAAAABh..." # Good - show last 4 digits masked = client.mask("Card: 4532-7562-9102-3456") # Output: "Card: ***************3456" ``` ### 3. Key Management is Too Complex If managing encryption keys is challenging, use **Tokenization**. ```python theme={null} # Complex - need to manage encryption keys encrypted = client.encrypt(data, encryption_key=KEY) # Must securely store KEY and manage rotation # Simpler - Blindfold manages tokens protected = client.tokenize(data) # Just store the mapping securely ``` ## Key Features Decrypt data using the encryption key Industry-standard encryption algorithm Use your own encryption keys Strong encryption for sensitive data ## Quick Start ```python theme={null} from blindfold import Blindfold import os client = Blindfold(api_key="your-api-key") # Define encryption key (min 16 characters) ENCRYPTION_KEY = os.environ["ENCRYPTION_KEY"] # Encrypt sensitive data result = client.encrypt( text="API Key: sk-1234567890abcdef, Secret: my_secret", encryption_key=ENCRYPTION_KEY ) print(result.text) # "API Key: gAAAAABh..., Secret: gAAAAABh..." print(f"Encrypted {result.entities_count} entities") # "Encrypted 2 entities" # Check what was encrypted for entity in result.detected_entities: print(f"- {entity.type}: {entity.text}") # - API_KEY: sk-1234567890abcdef # - PASSWORD: my_secret # To decrypt, use the same key with decrypt endpoint # (Note: decrypt endpoint needs to be implemented) ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); // Define encryption key (min 16 characters) const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY; // Encrypt sensitive data const result = await client.encrypt( "API Key: sk-1234567890abcdef, Secret: my_secret", { encryption_key: ENCRYPTION_KEY } ); console.log(result.text); // "API Key: gAAAAABh..., Secret: gAAAAABh..." console.log(`Encrypted ${result.entities_count} entities`); // "Encrypted 2 entities" // Check what was encrypted result.detected_entities.forEach(entity => { console.log(`- ${entity.type}: ${entity.text}`); }); // - API_KEY: sk-1234567890abcdef // - PASSWORD: my_secret // To decrypt, use the same key with decrypt endpoint ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold client = new Blindfold("your-api-key"); // Define encryption key (min 16 characters) String encryptionKey = System.getenv("ENCRYPTION_KEY"); // Encrypt sensitive data var result = client.encrypt( "API Key: sk-1234567890abcdef, Secret: my_secret", encryptionKey ); System.out.println(result.getText()); // "API Key: gAAAAABh..., Secret: gAAAAABh..." System.out.println("Encrypted " + result.getEntitiesCount() + " entities"); // "Encrypted 2 entities" // Check what was encrypted for (var entity : result.getDetectedEntities()) { System.out.println("- " + entity.getType() + ": " + entity.getText()); } // - API_KEY: sk-1234567890abcdef // - PASSWORD: my_secret ``` ```bash theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/encrypt \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "text": "API Key: sk-1234567890abcdef, Secret: my_secret", "encryption_key": "your-secure-key-min-16-chars" }' # Response { "text": "API Key: gAAAAABh3K7x..., Secret: gAAAAABh3K8y...", "entities_count": 2, "detected_entities": [ { "type": "API_KEY", "text": "sk-1234567890abcdef", "score": 0.85 }, { "type": "PASSWORD", "text": "my_secret", "score": 0.75 } ] } ``` ## Configuration Options ### Encryption Key Provide your own encryption key (minimum 16 characters): ```python theme={null} # Custom encryption key ENCRYPTION_KEY = "my-very-secure-encryption-key-123" result = client.encrypt( text=sensitive_data, encryption_key=ENCRYPTION_KEY ) # Default tenant key (if not provided) result = client.encrypt(text=sensitive_data) # Uses default key based on tenant ID ``` **Key Requirements:** * Minimum 16 characters * Store securely (environment variables, key vault) * Use different keys for different environments (dev, prod) * Implement key rotation policy ### Filter Entity Types Only encrypt specific types of data: ```python theme={null} # Only encrypt API keys and passwords result = client.encrypt( "API Key: sk-123, Email: john@example.com, Password: secret", encryption_key=KEY, entities=["API_KEY", "PASSWORD"] ) # Email is NOT encrypted ``` ### Adjust Confidence Threshold Control detection sensitivity: ```python theme={null} # Only high-confidence encryption result = client.encrypt( text="Maybe secret: xyz123", encryption_key=KEY, score_threshold=0.8 ) ``` ## Encryption Algorithm Blindfold uses **AES-256** encryption with the following process: 1. **Key Derivation**: Your encryption key is derived using PBKDF2 2. **Encryption**: Data is encrypted using Fernet (symmetric encryption) 3. **Secure**: Industry-standard cryptography from `cryptography` library **Technical Details:** * Algorithm: AES-256 in CBC mode * Key derivation: PBKDF2-HMAC-SHA256 * Iterations: 100,000 * Output: Base64-encoded ciphertext ## Common Patterns ### Encrypt Configuration Secrets ```python theme={null} def store_config(config_data: dict): """Encrypt and store configuration""" # Serialize config config_text = json.dumps(config_data) # Encrypt sensitive values encrypted = client.encrypt( config_text, encryption_key=CONFIG_KEY ) # Store encrypted config config_db.save('app_config', encrypted.text) # Usage config = { 'database_url': 'postgresql://user:pass@host/db', 'api_key': 'sk-1234567890', 'secret_token': 'abc123xyz' } store_config(config) ``` ### Secure Message Queue ```python theme={null} def queue_sensitive_message(message: str): """Encrypt message before queueing""" encrypted = client.encrypt( message, encryption_key=QUEUE_KEY ) # Queue encrypted message message_queue.push(encrypted.text) # Worker decrypts when processing def process_message(encrypted_message): # Decrypt using same key decrypted = decrypt(encrypted_message, QUEUE_KEY) process(decrypted) ``` ### Temporary Storage ```python theme={null} def cache_sensitive_data(user_id: str, data: str): """Cache encrypted data temporarily""" encrypted = client.encrypt( data, encryption_key=CACHE_KEY ) # Cache with TTL redis.setex( f"user:{user_id}:data", 300, # 5 minutes encrypted.text ) # Retrieve and decrypt def get_cached_data(user_id: str): encrypted = redis.get(f"user:{user_id}:data") if encrypted: return decrypt(encrypted, CACHE_KEY) return None ``` ## Common Use Cases Encrypt secrets before storing in databases: ```python theme={null} # Store encrypted secrets def save_secret(name: str, value: str): encrypted = client.encrypt( value, encryption_key=SECRETS_KEY ) secrets_db.insert({ 'name': name, 'value': encrypted.text, 'encrypted': True }) save_secret('database_password', 'my_db_pass') save_secret('api_token', 'token_12345') ``` **Benefits**: Secrets encrypted at rest, can be decrypted when needed Exchange data securely with partners: ```python theme={null} # Encrypt before sending def send_secure_data(data, recipient): encrypted = client.encrypt( data, encryption_key=SHARED_KEYS[recipient] ) api.send_to(recipient, encrypted.text) send_secure_data("Sensitive customer data", "partner_a") ``` **Benefits**: Data protected in transit, only recipient can decrypt Encrypt backups before storage: ```python theme={null} # Encrypt backup data def create_encrypted_backup(): backup_data = generate_backup() encrypted = client.encrypt( backup_data, encryption_key=BACKUP_KEY ) # Store encrypted backup backup_storage.save(encrypted.text) create_encrypted_backup() ``` **Benefits**: Backups protected, can restore when needed Encrypt medical records for compliance: ```python theme={null} # Encrypt patient data def store_patient_record(record): encrypted = client.encrypt( record, encryption_key=HIPAA_KEY ) hipaa_db.insert({ 'data': encrypted.text, 'encrypted_at': datetime.now() }) patient = "Patient: John Doe, SSN: 123-45-6789, Diagnosis: ..." store_patient_record(patient) ``` **Benefits**: HIPAA encryption requirements met ## Best Practices ### 1. Secure Key Management Store encryption keys securely: ```python theme={null} # Good - use environment variables ENCRYPTION_KEY = os.environ['ENCRYPTION_KEY'] # Good - use key management service from cloud_kms import get_key ENCRYPTION_KEY = get_key('encryption-key-prod') # Bad - hardcoded in code ENCRYPTION_KEY = "my-key-123" # Never do this! ``` ### 2. Different Keys for Different Purposes Use separate keys for different use cases: ```python theme={null} CONFIG_KEY = os.environ['CONFIG_ENCRYPTION_KEY'] DATA_KEY = os.environ['DATA_ENCRYPTION_KEY'] BACKUP_KEY = os.environ['BACKUP_ENCRYPTION_KEY'] # Encrypt config with config key encrypted_config = client.encrypt(config, encryption_key=CONFIG_KEY) # Encrypt data with data key encrypted_data = client.encrypt(data, encryption_key=DATA_KEY) ``` ### 3. Implement Key Rotation Regularly rotate encryption keys: ```python theme={null} def rotate_encryption_key(): """Rotate encryption key for all encrypted data""" OLD_KEY = os.environ['OLD_ENCRYPTION_KEY'] NEW_KEY = os.environ['NEW_ENCRYPTION_KEY'] # Decrypt with old key, encrypt with new key for record in encrypted_records: decrypted = decrypt(record.data, OLD_KEY) re_encrypted = client.encrypt(decrypted, encryption_key=NEW_KEY) update_record(record.id, re_encrypted.text) ``` ### 4. Document Encryption Usage Track what's encrypted and with which key: ```python theme={null} encrypted_data = { 'data': encrypted.text, 'encrypted': True, 'key_version': 'v2', # Track key version 'encrypted_at': datetime.now(), 'algorithm': 'AES-256' } ``` ## Security Considerations Important encryption considerations: * **Key security**: Encryption is only as secure as key management * **Key loss**: Lost keys mean permanently lost data * **Key exposure**: Exposed keys compromise all encrypted data * **Algorithm**: Uses AES-256, industry-standard encryption * **Not obfuscation**: Encryption is cryptographic protection, not hiding * **Compliance**: Check if AES-256 meets your compliance requirements ## Learn More Full Python SDK documentation Complete JavaScript guide Sync and async Java client HTTP API reference for /encrypt Practical integration examples ## Compare with Other Methods Reversible with mapping (simpler key management) Partial visibility (no encryption) Permanent removal (not reversible) One-way transformation (not reversible) # Hashing Source: https://docs.blindfold.dev/methods/hashing Create consistent identifiers without exposing original data ## What is Hashing? Hashing is a privacy protection method that replaces sensitive data with deterministic hash values. The same input always produces the same hash, making it perfect for analytics and user tracking without storing actual PII. **Example:** ``` Input: "User: john@example.com purchased item" Output: "User: ID_a3f8b9c2d4e5f6g7 purchased item" # Same input always produces same hash Input: "User: john@example.com logged in" Output: "User: ID_a3f8b9c2d4e5f6g7 logged in" ``` ## How It Works 1. **Detection**: Blindfold identifies sensitive entities in your text 2. **Hashing**: Each entity is hashed using SHA-256, MD5, or other algorithms 3. **Prefix Addition**: Optional prefix (e.g., `ID_`, `USER_`) is added 4. **Deterministic**: Same value always produces the same hash ## When to Use Hashing Hashing is ideal when you need to: ### 1. Analytics Without PII Track user behavior without storing email addresses or names. ```python theme={null} # Hash user email for analytics event = "User john@example.com completed checkout" hashed = client.hash(event, hash_type="sha256", hash_prefix="user_") analytics.track(hashed.text) # "User user_a3f8b9c2d4e5f6g7 completed checkout" ``` **Why this matters:** * Same user has same ID across all events * No PII in analytics database * Can still calculate user-level metrics ### 2. User Tracking Across Systems Create consistent user identifiers without sharing PII between systems. ```python theme={null} # System A: Hash user email user_id = client.hash("john@example.com", hash_prefix="uid_").text # System B: Same hash for same user # Both systems can track the same user without sharing the email ``` **Use cases:** * Multi-platform tracking * Cross-service analytics * Data sharing between departments ### 3. Data Matching Without Exposure Match records across databases without exposing the matching key. ```python theme={null} # Database A customer_id = client.hash("john@example.com", hash_prefix="cust_").text # Database B (can match using hash, not email) if hash_exists_in_db(customer_id): # Match found, no PII shared link_records(customer_id) ``` ### 4. Compliance-Friendly User IDs Create pseudonymous identifiers that comply with GDPR and privacy regulations. ```python theme={null} # Generate pseudonymous ID result = client.hash( f"User: {user_email}", hash_type="sha256", hash_prefix="user_" ) # Use as consistent user ID user_id = result.text.replace("User: ", "") ``` ## When NOT to Use Hashing Hashing is **not suitable** when: ### 1. You Need to Restore Original Data Hashing is one-way. Use **Tokenization** instead. ```python theme={null} # Bad - can't restore hashed = client.hash("john@example.com") # No way to get "john@example.com" back # Good - use tokenization protected = client.tokenize("john@example.com") original = client.detokenize(protected.text, protected.mapping) ``` ### 2. Users Need to Recognize Data If users need to identify their own information, use **Masking**. ```python theme={null} # Bad - user can't recognize this hashed = client.hash("Card: 4532-7562-9102-3456") # Output: "Card: ID_x7f9a3c4b2e8d5f1" # Good - show last 4 digits masked = client.mask("Card: 4532-7562-9102-3456") # Output: "Card: ***************3456" ``` ### 3. Hashes Could Be Rainbow-Attacked Don't hash easily guessable values without salt. ```python theme={null} # Risky - simple values can be brute-forced client.hash("1") # Easy to reverse client.hash("yes") # Easy to reverse # Better - add salt or use different method client.tokenize("1") # Random tokens ``` ## Key Features Same input always produces same hash Cannot reverse hash to get original MD5, SHA-1, SHA-256, SHA-384, SHA-512 Choose prefix and hash length ## Quick Start ```python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key") # Basic hashing result = client.hash( text="User john@example.com purchased item", hash_type="sha256", hash_prefix="user_", hash_length=16 ) print(result.text) # "User user_a3f8b9c2d4e5f6g7 purchased item" # Same input, same output result2 = client.hash( text="User john@example.com purchased item", hash_type="sha256", hash_prefix="user_", hash_length=16 ) print(result.text == result2.text) # True - deterministic! # Different algorithm md5_result = client.hash( text="john@example.com", hash_type="md5", hash_prefix="id_" ) ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); // Basic hashing const result = await client.hash( "User john@example.com purchased item", { hash_type: 'sha256', hash_prefix: 'user_', hash_length: 16 } ); console.log(result.text); // "User user_a3f8b9c2d4e5f6g7 purchased item" // Same input, same output const result2 = await client.hash( "User john@example.com purchased item", { hash_type: 'sha256', hash_prefix: 'user_', hash_length: 16 } ); console.log(result.text === result2.text); // true - deterministic! // Different algorithm const md5Result = await client.hash( "john@example.com", { hash_type: 'md5', hash_prefix: 'id_' } ); ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold client = new Blindfold("your-api-key"); // Basic hashing var result = client.hash( "User john@example.com purchased item", "sha256", "user_", 16, null ); System.out.println(result.getText()); // "User user_a3f8b9c2d4e5f6g7 purchased item" // Same input, same output var result2 = client.hash( "User john@example.com purchased item", "sha256", "user_", 16, null ); System.out.println(result.getText().equals(result2.getText())); // true - deterministic! // Different algorithm var md5Result = client.hash( "john@example.com", "md5", "id_", 0, null ); ``` ```bash theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/hash \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "text": "User john@example.com purchased item", "hash_type": "sha256", "hash_prefix": "user_", "hash_length": 16 }' # Response { "text": "User user_a3f8b9c2d4e5f6g7 purchased item", "entities_count": 1, "detected_entities": [ { "type": "EMAIL_ADDRESS", "text": "john@example.com", "score": 1.0 } ] } ``` ## Configuration Options ### Hash Algorithm Choose from multiple hashing algorithms: ```python theme={null} # SHA-256 (recommended, secure) client.hash(text, hash_type="sha256") # MD5 (fast, less secure) client.hash(text, hash_type="md5") # SHA-512 (most secure, longer) client.hash(text, hash_type="sha512") # SHA-1, SHA-224, SHA-384 also available ``` **Algorithm Comparison:** | Algorithm | Length | Speed | Security | Use Case | | --------- | --------- | ------- | --------- | ----------------- | | MD5 | 32 chars | Fastest | Low | Non-sensitive IDs | | SHA-1 | 40 chars | Fast | Medium | General use | | SHA-256 | 64 chars | Medium | High | **Recommended** | | SHA-384 | 96 chars | Slow | Very High | High security | | SHA-512 | 128 chars | Slowest | Highest | Maximum security | ### Hash Prefix Add a prefix to identify hash type: ```python theme={null} # User IDs client.hash(email, hash_prefix="user_") # user_a3f8b9... # Customer IDs client.hash(email, hash_prefix="cust_") # cust_a3f8b9... # Session IDs client.hash(session, hash_prefix="sess_") # sess_a3f8b9... # No prefix client.hash(email, hash_prefix="") # a3f8b9... ``` ### Hash Length Control how much of the hash to use: ```python theme={null} # Short (16 characters) - compact client.hash(text, hash_length=16) # a3f8b9c2d4e5f6g7 # Medium (32 characters) - balanced client.hash(text, hash_length=32) # a3f8b9c2d4e5f6g7h8i9j0k1l2m3n4o5 # Full hash (default) client.hash(text, hash_length=64) # full SHA-256 hash ``` Shorter hashes are easier to work with but have higher collision risk. Use at least 16 characters for production. ### Filter Entity Types Only hash specific types of data: ```python theme={null} result = client.hash( "User john@example.com from IP 192.168.1.1", entities=["EMAIL_ADDRESS"], # Only hash emails hash_prefix="user_" ) # Output: "User user_a3f8b9c2... from IP 192.168.1.1" ``` ## Common Patterns ### User Tracking in Analytics ```python theme={null} def track_user_event(user_email: str, event: str, properties: dict): """Track user event with hashed identifier""" # Create consistent user ID hashed = client.hash( f"User: {user_email}", hash_type="sha256", hash_prefix="user_", hash_length=16 ) user_id = hashed.text.replace("User: ", "") # Track event analytics.track(user_id, event, properties) # Usage track_user_event("john@example.com", "page_view", {"page": "/dashboard"}) track_user_event("john@example.com", "button_click", {"button": "submit"}) # Both events have same user_id: user_a3f8b9c2d4e5f6g7 ``` ### Cross-Platform User Matching ```python theme={null} def create_universal_id(email: str) -> str: """Create universal user ID that works across platforms""" result = client.hash( email, hash_type="sha256", hash_prefix="uid_", hash_length=20 ) return result.text # Platform A uid_a = create_universal_id("john@example.com") platform_a_db.save(uid_a, user_data) # Platform B uid_b = create_universal_id("john@example.com") # uid_a == uid_b, can match records without sharing email ``` ### Pseudonymous Database IDs ```python theme={null} def generate_pseudonymous_id(pii_value: str) -> str: """Generate GDPR-compliant pseudonymous identifier""" result = client.hash( pii_value, hash_type="sha256", hash_prefix="pseudo_", hash_length=24 ) return result.text # Store with pseudonymous ID user_id = generate_pseudonymous_id("john@example.com") database.insert({ 'id': user_id, 'preferences': {...}, 'activity': [...] }) ``` ## Common Use Cases Track users without storing email or names: ```python theme={null} # Hash user identifier for analytics def log_page_view(user_email, page_url): hashed = client.hash( user_email, hash_type="sha256", hash_prefix="user_" ) analytics.page_view({ 'user_id': hashed.text, 'page': page_url, 'timestamp': datetime.now() }) log_page_view("john@example.com", "/products") # Analytics: user_id="user_a3f8b9...", page="/products" ``` **Benefits**: User-level analytics without PII, GDPR compliant Assign users to test groups consistently: ```python theme={null} def get_ab_test_variant(user_email): """Consistently assign user to A/B test variant""" hashed = client.hash(user_email, hash_length=8) # Use hash to determine variant hash_int = int(hashed.text[:8], 16) variant = 'A' if hash_int % 2 == 0 else 'B' return variant # Same user always gets same variant variant1 = get_ab_test_variant("john@example.com") # 'A' variant2 = get_ab_test_variant("john@example.com") # 'A' (same) ``` **Benefits**: Consistent variants, no PII stored, reproducible Share data between teams without exposing PII: ```python theme={null} # Marketing hashes customer emails def prepare_for_warehouse(customer_data): for customer in customer_data: customer['id'] = client.hash( customer['email'], hash_prefix="c_" ).text del customer['email'] # Remove PII return customer_data # Analytics team can match using hash # No access to actual emails ``` **Benefits**: Data sharing without PII exposure, compliance maintained Find duplicates without comparing raw data: ```python theme={null} def check_duplicate(email): """Check if user already exists using hash""" hashed = client.hash(email, hash_prefix="user_") if database.exists(hashed.text): return True, "User already registered" else: database.insert(hashed.text) return False, "New user" # Check without storing actual email is_duplicate, message = check_duplicate("john@example.com") ``` **Benefits**: Duplicate detection without storing PII ## Best Practices ### 1. Use Strong Algorithms Prefer SHA-256 or higher for security: ```python theme={null} # Good - strong algorithm client.hash(text, hash_type="sha256") # Acceptable for non-sensitive data client.hash(text, hash_type="md5") # Not recommended for sensitive data # (MD5 has known vulnerabilities) ``` ### 2. Use Consistent Parameters Keep hash parameters consistent across your application: ```python theme={null} # Good - create a helper function def create_user_hash(identifier): return client.hash( identifier, hash_type="sha256", hash_prefix="user_", hash_length=20 ).text # Use everywhere user_id = create_user_hash(email) ``` ### 3. Document Your Hashing Strategy Clearly document what gets hashed and how: ```python theme={null} # hash_config.py HASH_CONFIG = { 'users': { 'algorithm': 'sha256', 'prefix': 'user_', 'length': 20 }, 'sessions': { 'algorithm': 'sha256', 'prefix': 'sess_', 'length': 16 } } ``` ### 4. Consider Rainbow Table Attacks For highly sensitive data, add application-level salt: ```python theme={null} # Add salt before hashing APP_SALT = os.environ['APP_HASH_SALT'] def secure_hash(value): salted = f"{value}{APP_SALT}" return client.hash(salted, hash_type="sha256") ``` ## Security Considerations Important hashing considerations: * **One-way only**: Cannot reverse hash to original * **Rainbow tables**: Simple values can be brute-forced * **Collision risk**: Shorter hashes have higher collision risk * **Algorithm choice**: Use SHA-256 or higher for sensitive data * **Not encryption**: Hashing is not the same as encryption ## Learn More Full Python SDK documentation Complete JavaScript guide Sync and async Java client HTTP API reference for /hash Practical integration examples ## Compare with Other Methods Reversible replacement (restore later) Partial visibility for users Complete permanent removal Reversible with encryption key # Masking Source: https://docs.blindfold.dev/methods/masking Partially hide sensitive data while maintaining usability ## What is Masking? Masking is a privacy protection method that partially hides sensitive data by replacing most characters with a masking character (typically `*`), while keeping a few characters visible for identification purposes. **Example:** ``` Input: "Card: 4532-7562-9102-3456" Output: "Card: ***************3456" Input: "Email: john.doe@company.com" Output: "Email: joh******************" ``` ## How It Works 1. **Detection**: Blindfold identifies sensitive entities in your text 2. **Partial Replacement**: Most characters are replaced with masking characters 3. **Selective Visibility**: A configurable number of characters remain visible 4. **Direction Control**: Choose to show characters from the beginning or end ## When to Use Masking Masking is ideal when you need to: ### 1. Display Payment Information Show payment methods in user interfaces without exposing full details. ```python theme={null} result = client.mask( "Card ending in 4532-7562-9102-3456", masking_char="*", chars_to_show=4, from_end=True ) # Output: "Card ending in ***************3456" ``` **Why this matters:** * Users can identify their card (last 4 digits) * Full card number stays protected * PCI-DSS compliant display ### 2. Show Partial Email Addresses Display enough to identify the account without exposing the full email. ```python theme={null} result = client.mask( "Account: john.doe@company.com", masking_char="*", chars_to_show=3, from_end=False ) # Output: "Account: joh******************" ``` **Use cases:** * Account recovery confirmation * Security notifications * Multi-account selection ### 3. Protect Phone Numbers Show country code or last digits for verification. ```python theme={null} result = client.mask( "Contact: +1-555-1234", masking_char="X", chars_to_show=2, from_end=True ) # Output: "Contact: +1-555-XX34" ``` ### 4. Display User Information in Admin Panels Allow admins to identify users without seeing full sensitive data. ```python theme={null} user_info = """ Name: John Doe Email: john.doe@company.com SSN: 123-45-6789 """ masked = client.mask(user_info, chars_to_show=4, from_end=True) # Admins see partially masked information ``` ## When NOT to Use Masking Masking is **not suitable** when: ### 1. You Need to Restore Original Data Masking is irreversible. Use **Tokenization** instead. ```python theme={null} # Bad - can't restore masked = client.mask("john@example.com") # No way to get "john@example.com" back # Good - use tokenization protected = client.tokenize("john@example.com") original = client.detokenize(protected.text, protected.mapping) ``` ### 2. You Need Complete Removal If no part should be visible, use **Redaction**. ```python theme={null} # Bad - still shows part of SSN masked = client.mask("SSN: 123-45-6789") # Output: "SSN: **********89" # Good - complete removal redacted = client.redact("SSN: 123-45-6789") # Output: "SSN: " ``` ### 3. Data is for Processing (Not Display) For data processing by systems, use **Tokenization** or **Redaction**. ```python theme={null} # Bad - processing masked data is unreliable masked = client.mask(api_key) send_to_api(masked.text) # API won't work with ***key # Good - tokenize for processing protected = client.tokenize(api_key) ``` ## Key Features Choose how many characters to show (1-10+) Show characters from start or end Use \*, X, #, or any character Works with emails, cards, SSNs, phones, etc. ## Quick Start ```python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key") # Basic masking (show last 4) result = client.mask( text="Credit card: 4532-7562-9102-3456", masking_char="*", chars_to_show=4, from_end=True ) print(result.text) # "Credit card: ***************3456" # Custom mask character result = client.mask( text="SSN: 123-45-6789", masking_char="X", chars_to_show=4, from_end=True ) print(result.text) # "SSN: XXXXXXX6789" # Show from beginning result = client.mask( text="Email: john.doe@company.com", masking_char="*", chars_to_show=3, from_end=False ) print(result.text) # "Email: joh******************" ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); // Basic masking (show last 4) const result = await client.mask( "Credit card: 4532-7562-9102-3456", { masking_char: '*', chars_to_show: 4, from_end: true } ); console.log(result.text); // "Credit card: ***************3456" // Custom mask character const result2 = await client.mask( "SSN: 123-45-6789", { masking_char: 'X', chars_to_show: 4, from_end: true } ); console.log(result2.text); // "SSN: XXXXXXX6789" // Show from beginning const result3 = await client.mask( "Email: john.doe@company.com", { masking_char: '*', chars_to_show: 3, from_end: false } ); console.log(result3.text); // "Email: joh******************" ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold client = new Blindfold("your-api-key"); // Basic masking (show last 4) var result = client.mask( "Credit card: 4532-7562-9102-3456", 4, true, "*", null ); System.out.println(result.getText()); // "Credit card: ***************3456" // Custom mask character var result2 = client.mask( "SSN: 123-45-6789", 4, true, "X", null ); System.out.println(result2.getText()); // "SSN: XXXXXXX6789" // Show from beginning var result3 = client.mask( "Email: john.doe@company.com", 3, false, "*", null ); System.out.println(result3.getText()); // "Email: joh******************" ``` ```bash theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/mask \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "text": "Credit card: 4532-7562-9102-3456", "masking_char": "*", "chars_to_show": 4, "from_end": true }' # Response { "text": "Credit card: ***************3456", "entities_count": 1, "detected_entities": [ { "type": "CREDIT_CARD", "text": "4532-7562-9102-3456", "score": 1.0 } ] } ``` ## Configuration Options ### Masking Character Choose which character to use for masking: ```python theme={null} # Asterisks (default) client.mask(text, masking_char="*") # ***3456 # X marks client.mask(text, masking_char="X") # XXX3456 # Dashes client.mask(text, masking_char="-") # ---3456 # Dots client.mask(text, masking_char=".") # ...3456 ``` ### Characters to Show Control how many characters remain visible: ```python theme={null} # Show last 4 (common for cards) client.mask(text, chars_to_show=4) # ***************3456 # Show last 2 (for phone numbers) client.mask(text, chars_to_show=2) # *********34 # Show first 3 (for emails) client.mask(text, chars_to_show=3, from_end=False) # joh*************** ``` ### Direction Choose to show characters from the start or end: ```python theme={null} # Show from end (default) - good for cards, phones client.mask(text, from_end=True) # ***3456 # Show from start - good for emails, names client.mask(text, from_end=False) # joh*** ``` ### Filter Entity Types Only mask specific types of data: ```python theme={null} result = client.mask( "Card: 4532-7562-9102-3456, Email: john@example.com", entities=["CREDIT_CARD"], # Only mask cards chars_to_show=4, from_end=True ) # Output: "Card: ***************3456, Email: john@example.com" ``` ## Common Patterns ### Payment Card Display Standard pattern for showing payment cards: ```python theme={null} def display_payment_method(card_number): """Display card with last 4 digits visible""" result = client.mask( f"Card: {card_number}", masking_char="*", chars_to_show=4, from_end=True ) return result.text # Usage display_payment_method("4532-7562-9102-3456") # "Card: ***************3456" ``` ### Email Display Show beginning of email for identification: ```python theme={null} def display_email(email): """Show first 3 characters of email""" result = client.mask( email, masking_char="*", chars_to_show=3, from_end=False ) return result.text # Usage display_email("john.doe@company.com") # "joh******************" ``` ### Phone Number Display Show last 2 or 4 digits: ```python theme={null} def display_phone(phone): """Show last 2 digits of phone""" result = client.mask( phone, masking_char="X", chars_to_show=2, from_end=True ) return result.text # Usage display_phone("+1-555-1234") # "+1-555-XX34" ``` ## Common Use Cases Show saved payment methods to customers: ```python theme={null} # Display stored cards cards = [ "4532-7562-9102-3456", "5425-2334-3010-9903" ] for card in cards: masked = client.mask(card, chars_to_show=4, from_end=True) print(f"Card ending in {masked.text[-4:]}") ``` **Benefits**: Users can identify their cards, PCI compliance maintained Confirm user identity by showing partial email: ```python theme={null} def show_recovery_email(email): masked = client.mask( email, chars_to_show=3, from_end=False ) return f"We'll send a code to {masked.text}" show_recovery_email("john.doe@company.com") # "We'll send a code to joh******************" ``` **Benefits**: User knows which account, email address not exposed Show user information to admins without full PII: ```python theme={null} def display_user_info(user_data): masked = client.mask( user_data, chars_to_show=4, from_end=True ) return masked.text user = "Email: john@example.com, Phone: +1-555-1234" print(display_user_info(user)) # Shows partially masked information ``` **Benefits**: Admins can identify users, reduced PII exposure Notify users about security events without exposing full details: ```python theme={null} def send_security_alert(phone_number): masked = client.mask( phone_number, chars_to_show=2, from_end=True ) return f"Security alert sent to phone ending in {masked.text[-2:]}" send_security_alert("+1-555-1234") # "Security alert sent to phone ending in 34" ``` **Benefits**: User can verify it's their number, privacy maintained ## Best Practices ### 1. Follow Industry Standards Use established patterns for different data types: ```python theme={null} # Credit cards: Show last 4 client.mask(card, chars_to_show=4, from_end=True) # Emails: Show first 3 client.mask(email, chars_to_show=3, from_end=False) # Phones: Show last 2-4 client.mask(phone, chars_to_show=2, from_end=True) # SSNs: Show last 4 client.mask(ssn, chars_to_show=4, from_end=True) ``` ### 2. Balance Security and Usability Show enough for identification, not more: ```python theme={null} # Good - enough to identify client.mask(card, chars_to_show=4) # ***3456 # Risky - too much visible client.mask(card, chars_to_show=12) # 4532-7562-9103456 ``` ### 3. Use Consistent Masking Be consistent across your application: ```python theme={null} # Create a helper function def mask_pii(text, entity_type): if entity_type == "card": return client.mask(text, chars_to_show=4, from_end=True) elif entity_type == "email": return client.mask(text, chars_to_show=3, from_end=False) # etc. ``` ### 4. Document Your Masking Rules Make it clear what's shown and what's hidden: ```python theme={null} # Add tooltips or help text "Card ending in ***3456 (only last 4 digits shown)" "Email: joh*** (only first 3 characters shown)" ``` ## Security Considerations Masking reduces but does not eliminate risk. Consider: * **Not reversible**: Once masked, data cannot be restored * **Partial exposure**: Some characters remain visible * **Pattern recognition**: Repeated masking may reveal patterns * **Compliance**: Check if masking meets your regulatory requirements ## Learn More Full Python SDK documentation Complete JavaScript guide Sync and async Java client HTTP API reference for /mask Practical integration examples ## Compare with Other Methods Reversible replacement with tokens Complete permanent removal Deterministic identifiers AES encryption with key # Redaction Source: https://docs.blindfold.dev/methods/redaction Permanently remove sensitive data from text ## What is Redaction? Redaction is a permanent privacy protection method that completely removes sensitive data from text. The detected sensitive information is deleted and cannot be restored. **Example:** ``` Input: "My name is John Doe and SSN is 123-45-6789" Output: "My name is and SSN is " ``` ## How It Works 1. **Detection**: Blindfold identifies sensitive entities in your text 2. **Complete Removal**: Each detected entity is completely removed from the text 3. **Permanent**: Original values are discarded and cannot be recovered 4. **Clean Output**: Text flows naturally with sensitive data removed ## When to Use Redaction Redaction is ideal when you need to: ### 1. Permanent Data Anonymization Remove PII from logs, support tickets, or archives that will be stored long-term. ```python theme={null} # Redact support ticket before archiving ticket = "Customer John Doe (john@example.com) reported an issue with order #12345" redacted = client.redact(ticket) # Store safely archive_db.save(redacted.text) # "Customer () reported an issue with order #12345" ``` **Why this matters:** * Compliant long-term storage * No risk of data breach exposing PII * Meets "right to be forgotten" requirements ### 2. Third-Party Analytics Share data with analytics platforms without exposing sensitive information. ```python theme={null} # Redact before sending to analytics event = "User john.doe@company.com completed purchase" redacted = client.redact(event) # Send to analytics analytics.track(redacted.text) # "User completed purchase" ``` **Use cases:** * Google Analytics * Mixpanel, Amplitude * Custom analytics platforms * Business intelligence tools ### 3. Public Disclosure Prepare data for public release or legal disclosure. ```python theme={null} # Redact before publishing document = """ Incident involving John Smith (SSN: 123-45-6789) Contact: john@example.com, Phone: +1-555-1234 """ redacted = client.redact(document) # All PII removed, safe for public release ``` ### 4. Log Sanitization Remove sensitive data from application logs. ```python theme={null} # Redact logs before storage log_entry = "User login: john@example.com from IP 192.168.1.100" redacted = client.redact(log_entry) logger.info(redacted.text) # "User login: from IP " ``` ### 5. GDPR Compliance Implement "right to be forgotten" by permanently removing user data. ```python theme={null} # User requests data deletion user_records = fetch_user_records(user_id) # Redact instead of delete (keeps records for analysis) for record in user_records: redacted = client.redact(record) update_record(record.id, redacted.text) ``` ## When NOT to Use Redaction Redaction is **not suitable** when: ### 1. You Need to Restore Data Later Redaction is permanent. Use **Tokenization** instead. ```python theme={null} # Bad - can't restore redacted = client.redact("Contact john@example.com") # No way to get "john@example.com" back # Good - use tokenization protected = client.tokenize("Contact john@example.com") original = client.detokenize(protected.text, protected.mapping) ``` ### 2. Users Need to Identify the Data If users need to recognize their own data, use **Masking**. ```python theme={null} # Bad - user can't identify their card redacted = client.redact("Card: 4532-7562-9102-3456") # Output: "Card: " # Good - show last 4 digits masked = client.mask("Card: 4532-7562-9102-3456") # Output: "Card: ***************3456" ``` ### 3. You Need Consistent Identifiers For analytics with user tracking, use **Hashing**. ```python theme={null} # Bad - can't track same user across events redacted1 = client.redact("User: john@example.com") # "User: " redacted2 = client.redact("User: jane@example.com") # "User: " # Both look the same, can't distinguish users # Good - same user gets same hash hash1 = client.hash("User: john@example.com") # ID_a3f8b9... hash2 = client.hash("User: john@example.com") # ID_a3f8b9... (same) ``` ## Key Features Data is completely removed and cannot be recovered Sensitive text is deleted, not replaced Meets data minimization requirements Removes all detected PII types ## Quick Start ```python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key") # Basic redaction result = client.redact( "Contact John Doe at john@example.com or call +1-555-1234" ) print(result.text) # "Contact at or call " print(f"Redacted {result.entities_count} entities") # "Redacted 3 entities" # Check what was redacted for entity in result.detected_entities: print(f"- {entity.type}: {entity.text} (removed)") # - PERSON: John Doe (removed) # - EMAIL_ADDRESS: john@example.com (removed) # - PHONE_NUMBER: +1-555-1234 (removed) ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); // Basic redaction const result = await client.redact( "Contact John Doe at john@example.com or call +1-555-1234" ); console.log(result.text); // "Contact at or call " console.log(`Redacted ${result.entities_count} entities`); // "Redacted 3 entities" // Check what was redacted result.detected_entities.forEach(entity => { console.log(`- ${entity.type}: ${entity.text} (removed)`); }); // - PERSON: John Doe (removed) // - EMAIL_ADDRESS: john@example.com (removed) // - PHONE_NUMBER: +1-555-1234 (removed) ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold client = new Blindfold("your-api-key"); // Basic redaction var result = client.redact( "Contact John Doe at john@example.com or call +1-555-1234" ); System.out.println(result.getText()); // "Contact at or call " System.out.println("Redacted " + result.getEntitiesCount() + " entities"); // "Redacted 3 entities" // Check what was redacted for (var entity : result.getDetectedEntities()) { System.out.println("- " + entity.getType() + ": " + entity.getText() + " (removed)"); } // - PERSON: John Doe (removed) // - EMAIL_ADDRESS: john@example.com (removed) // - PHONE_NUMBER: +1-555-1234 (removed) ``` ```bash theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/redact \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "text": "Contact John Doe at john@example.com or call +1-555-1234" }' # Response { "text": "Contact at or call ", "entities_count": 3, "detected_entities": [ { "type": "PERSON", "text": "John Doe", "start": 8, "end": 16, "score": 0.95 }, { "type": "EMAIL_ADDRESS", "text": "john@example.com", "start": 20, "end": 36, "score": 1.0 }, { "type": "PHONE_NUMBER", "text": "+1-555-1234", "start": 48, "end": 59, "score": 0.85 } ] } ``` ## Configuration Options ### Filter Specific Entity Types Only redact specific types of sensitive data: ```python theme={null} # Only redact SSNs and credit cards result = client.redact( "John Doe (SSN: 123-45-6789) paid with card 4532-7562-9102-3456", entities=["US_SSN", "CREDIT_CARD"] ) # Output: "John Doe (SSN: ) paid with card " # Name is NOT redacted ``` ### Adjust Confidence Threshold Control detection sensitivity: ```python theme={null} # Only high-confidence redactions result = client.redact( text="Maybe email: test@test", score_threshold=0.8 # High confidence only ) # Low-confidence detections are skipped ``` ## Common Patterns ### Log Sanitization Automatically redact logs before storage: ```python theme={null} def safe_log(message: str, level: str = "info"): """Log messages with automatic PII redaction""" redacted = client.redact(message) if level == "info": logger.info(redacted.text) elif level == "error": logger.error(redacted.text) # Usage safe_log("User john@example.com failed to login from 192.168.1.100") # Logs: "User failed to login from " ``` ### Support Ticket Archival Redact tickets before long-term storage: ```python theme={null} def archive_ticket(ticket_data: dict): """Archive support ticket with redacted PII""" # Redact sensitive fields ticket_data['description'] = client.redact( ticket_data['description'] ).text ticket_data['customer_notes'] = client.redact( ticket_data['customer_notes'] ).text # Store safely archive_db.insert(ticket_data) # Usage ticket = { 'id': 12345, 'description': 'Customer John Doe (john@example.com) needs help', 'customer_notes': 'My SSN is 123-45-6789' } archive_ticket(ticket) # All PII removed before storage ``` ### Analytics Event Tracking Send events to analytics without PII: ```python theme={null} def track_event(event_name: str, properties: dict): """Track analytics event with redacted PII""" # Redact all string properties safe_properties = {} for key, value in properties.items(): if isinstance(value, str): safe_properties[key] = client.redact(value).text else: safe_properties[key] = value # Send to analytics analytics.track(event_name, safe_properties) # Usage track_event("user_signup", { "email": "john@example.com", "source": "landing_page", "age": 25 }) # Analytics receives: email="", source="landing_page", age=25 ``` ## Common Use Cases Maintain audit logs without storing PII: ```python theme={null} # Log user actions without PII def log_user_action(user_email, action): redacted = client.redact(f"{user_email} performed {action}") compliance_log.write(redacted.text) log_user_action("john@example.com", "password_reset") # Logs: " performed password_reset" ``` **Benefits**: Audit trail maintained, no PII storage, GDPR compliant Collect feedback without storing customer PII: ```python theme={null} # Redact customer feedback before storage def save_feedback(feedback_text, rating): redacted = client.redact(feedback_text) feedback_db.insert({ 'text': redacted.text, 'rating': rating, 'date': datetime.now() }) save_feedback( "Great service! Contact me at john@example.com", 5 ) # Stores: "Great service! Contact me at " ``` **Benefits**: Feedback preserved, PII removed, safe for analysis Share error reports without exposing user data: ```python theme={null} # Redact error reports before sending to bug tracker def report_error(error_message, user_context): redacted_message = client.redact(error_message) redacted_context = client.redact(user_context) bug_tracker.create_issue({ 'title': redacted_message.text, 'description': redacted_context.text }) report_error( "Database error for user john@example.com", "User IP: 192.168.1.100, Session: abc123" ) # Bug report contains no real PII ``` **Benefits**: Developers get context, user privacy protected Create shareable datasets from sensitive data: ```python theme={null} # Prepare dataset for public release def create_public_dataset(private_records): public_records = [] for record in private_records: redacted = client.redact(record) public_records.append(redacted.text) return public_records # Original: ["John Doe, john@example.com, +1-555-1234", ...] # Public: [", , ", ...] ``` **Benefits**: Data useful for research, no privacy violations ## Best Practices ### 1. Redact Early Redact sensitive data as early as possible in your pipeline: ```python theme={null} # Good - redact immediately user_input = request.get_json()['message'] safe_message = client.redact(user_input).text process_message(safe_message) # Bad - redact late (PII may leak in logs, errors, etc.) user_input = request.get_json()['message'] process_message(user_input) # PII exposed during processing redacted = client.redact(result) ``` ### 2. Log What Was Redacted Keep audit trails of redaction events: ```python theme={null} result = client.redact(text) # Log redaction metadata audit_log.info({ 'action': 'redaction', 'entities_redacted': result.entities_count, 'entity_types': [e.type for e in result.detected_entities], 'timestamp': datetime.now() }) ``` ### 3. Review Redaction Policies Regularly review what gets redacted: ```python theme={null} # Monitor redaction statistics def analyze_redactions(timeframe): stats = { 'total_redactions': 0, 'entity_types': {} } for event in get_redaction_events(timeframe): stats['total_redactions'] += event.entities_count for entity in event.detected_entities: stats['entity_types'][entity.type] = \ stats['entity_types'].get(entity.type, 0) + 1 return stats ``` ### 4. Combine with Other Methods Use redaction alongside other privacy methods: ```python theme={null} # Redact for long-term storage, tokenize for processing def process_and_store(data): # Tokenize for processing protected = client.tokenize(data) result = process_with_ai(protected.text) # Redact for storage redacted = client.redact(result) database.save(redacted.text) ``` ## Security Considerations Important redaction considerations: * **Permanent**: Redacted data cannot be recovered * **Complete removal**: Text is completely deleted, leaving gaps * **Context flow**: May affect readability with removed text * **Not reversible**: Unlike encryption, redaction cannot be undone * **Review before production**: Test redaction on sample data first ## Learn More Full Python SDK documentation Complete JavaScript guide Sync and async Java client HTTP API reference for /redact Practical integration examples ## Compare with Other Methods Reversible replacement (restore later) Partial visibility for users Consistent identifiers for tracking Replace with fake realistic data # Synthesis Source: https://docs.blindfold.dev/methods/synthesis Replace real data with realistic fake data ## What is Synthesis? Synthesis is a privacy protection method that replaces real sensitive data with realistic fake data generated by Faker library. The fake data looks authentic but contains no real PII. **Example:** ``` Input: "John Doe lives in New York and works at Microsoft" Output: "Michael Smith lives in Boston and works at TechCorp" ``` ## How It Works 1. **Detection**: Blindfold identifies sensitive entities in your text 2. **Generation**: For each entity, realistic fake data is generated based on type 3. **Replacement**: Real data is replaced with synthetic data 4. **Language Support**: Fake data matches the specified language locale ## When to Use Synthesis Synthesis is ideal when you need to: ### 1. Generate Test Data Create realistic test data for development and testing environments. ```python theme={null} # Generate test user profiles template = "Name: John Doe, Email: john@example.com, Phone: +1-555-1234" for i in range(10): result = client.synthesize(template, language="en") print(result.text) # Output (examples): # "Name: Michael Smith, Email: michael@example.net, Phone: +1-555-9876" # "Name: Sarah Johnson, Email: sarah@example.org, Phone: +1-555-4567" # ... 10 unique profiles ``` **Why this matters:** * Realistic test data without PII * Repeatable test scenarios * No risk of exposing real user data ### 2. Demo Environments Populate demo environments with realistic but fake data. ```python theme={null} # Create demo customer data customer_template = """ Customer: Jane Smith Email: jane@company.com Location: New York Company: TechCorp """ demo_customer = client.synthesize(customer_template, language="en") load_into_demo_db(demo_customer.text) ``` **Use cases:** * Product demos * Sales presentations * Training environments * Screenshots and marketing ### 3. Realistic Training Data Create training datasets that look real but contain no actual PII. ```python theme={null} # Generate training data for ML models training_examples = [] for _ in range(1000): synthetic = client.synthesize( "Patient John Doe, age 45, diagnosed with diabetes", language="en" ) training_examples.append(synthetic.text) # Train model on synthetic data ``` ### 4. Data Sharing for Testing Share realistic data with partners or vendors for integration testing. ```python theme={null} # Create synthetic data for vendor testing test_data = client.synthesize( production_data_sample, language="en" ) # Safe to share - no real PII send_to_vendor(test_data.text) ``` ## When NOT to Use Synthesis Synthesis is **not suitable** when: ### 1. You Need Original Data Back Synthesis is irreversible. Use **Tokenization** instead. ```python theme={null} # Bad - can't restore synthetic = client.synthesize("john@example.com") # No way to get "john@example.com" back # Good - use tokenization protected = client.tokenize("john@example.com") original = client.detokenize(protected.text, protected.mapping) ``` ### 2. Users Need to Recognize Their Data Users won't recognize synthesized data. Use **Masking**. ```python theme={null} # Bad - user won't recognize their card synthetic = client.synthesize("Card: 4532-7562-9102-3456") # Output: "Card: 5678-1234-9012-3456" (completely different) # Good - show last 4 of real card masked = client.mask("Card: 4532-7562-9102-3456") # Output: "Card: ***************3456" ``` ### 3. You Need Consistent Identifiers Each synthesis generates different data. Use **Hashing**. ```python theme={null} # Bad - different each time synth1 = client.synthesize("john@example.com") # michael@example.com synth2 = client.synthesize("john@example.com") # sarah@example.org # Good - same hash every time hash1 = client.hash("john@example.com") # ID_a3f8b9... hash2 = client.hash("john@example.com") # ID_a3f8b9... (same) ``` ## Key Features Generated data looks authentic Supports 8 languages with locale-specific data Generates appropriate data for each entity type Uses Faker library for quality fake data ## Quick Start ```python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key") # Basic synthesis result = client.synthesize( text="John Doe lives in New York and works at Microsoft", language="en" ) print(result.text) # "Michael Smith lives in Boston and works at TechCorp" # (example output - will vary) # Generate multiple variations template = "Customer: Jane Doe, Email: jane@example.com" for i in range(3): result = client.synthesize(template, language="en") print(f"{i+1}. {result.text}") # Output (examples): # 1. Customer: Sarah Johnson, Email: sarah@example.org # 2. Customer: Michael Brown, Email: michael@example.net # 3. Customer: Emily Davis, Email: emily@example.com ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); // Basic synthesis const result = await client.synthesize( "John Doe lives in New York and works at Microsoft", { language: 'en' } ); console.log(result.text); // "Michael Smith lives in Boston and works at TechCorp" // (example output - will vary) // Generate multiple variations const template = "Customer: Jane Doe, Email: jane@example.com"; for (let i = 0; i < 3; i++) { const result = await client.synthesize(template, { language: 'en' }); console.log(`${i+1}. ${result.text}`); } // Output (examples): // 1. Customer: Sarah Johnson, Email: sarah@example.org // 2. Customer: Michael Brown, Email: michael@example.net // 3. Customer: Emily Davis, Email: emily@example.com ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold client = new Blindfold("your-api-key"); // Basic synthesis var result = client.synthesize( "John Doe lives in New York and works at Microsoft", "en", null ); System.out.println(result.getText()); // "Michael Smith lives in Boston and works at TechCorp" // (example output - will vary) // Generate multiple variations String template = "Customer: Jane Doe, Email: jane@example.com"; for (int i = 0; i < 3; i++) { var r = client.synthesize(template, "en", null); System.out.println((i + 1) + ". " + r.getText()); } // 1. Customer: Sarah Johnson, Email: sarah@example.org // 2. Customer: Michael Brown, Email: michael@example.net // 3. Customer: Emily Davis, Email: emily@example.com ``` ```bash theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/synthesize \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "text": "John Doe lives in New York and works at Microsoft", "language": "en" }' # Response (example - will vary) { "text": "Michael Smith lives in Boston and works at TechCorp", "entities_count": 3, "detected_entities": [ { "type": "PERSON", "text": "John Doe", "score": 0.95 }, { "type": "LOCATION", "text": "New York", "score": 0.90 }, { "type": "ORGANIZATION", "text": "Microsoft", "score": 0.85 } ] } ``` ## Supported Languages Generate locale-specific fake data for different languages: ```python theme={null} result = client.synthesize( "John Doe from New York", language="en" ) # "Michael Smith from Boston" ``` ```python theme={null} result = client.synthesize( "Jan Novák z Prahy", language="cs" ) # "Petr Dvořák z Brna" ``` ```python theme={null} result = client.synthesize( "Hans Müller aus Berlin", language="de" ) # "Klaus Schmidt aus München" ``` ```python theme={null} result = client.synthesize( "Marie Dupont de Paris", language="fr" ) # "Sophie Martin de Lyon" ``` ```python theme={null} result = client.synthesize( "Juan García de Madrid", language="es" ) # "Carlos López de Barcelona" ``` ```python theme={null} result = client.synthesize( "Marco Rossi da Roma", language="it" ) # "Giuseppe Bianchi da Milano" ``` ```python theme={null} result = client.synthesize( "Jan Kowalski z Warszawy", language="pl" ) # "Piotr Nowak z Krakowa" ``` ```python theme={null} result = client.synthesize( "Ján Kováč z Bratislavy", language="sk" ) # "Peter Horváth z Košíc" ``` **Supported Languages:** * `en` - English (US) * `cs` - Czech * `de` - German * `fr` - French * `es` - Spanish * `it` - Italian * `pl` - Polish * `sk` - Slovak ## Entity Types and Fake Data Different entity types generate different kinds of fake data: | Entity Type | Example Input | Example Output | | --------------- | ------------------------------------------- | ------------------------------------------------- | | `PERSON` | John Doe | Michael Smith | | `EMAIL_ADDRESS` | [john@example.com](mailto:john@example.com) | [michael@example.net](mailto:michael@example.net) | | `PHONE_NUMBER` | +1-555-1234 | +1-555-9876 | | `LOCATION` | New York | Boston | | `ORGANIZATION` | Microsoft | TechCorp | | `CREDIT_CARD` | 4532-7562-9102-3456 | 5678-1234-9012-3456 | | `DATE_TIME` | 2024-01-15 | 2023-11-22 | | `IP_ADDRESS` | 192.168.1.1 | 10.0.0.5 | | `URL` | [https://example.com](https://example.com) | [https://test-site.org](https://test-site.org) | ## Common Patterns ### Generate Test Users ```python theme={null} def generate_test_users(count: int) -> list: """Generate realistic test user profiles""" template = """ Name: John Doe Email: john.doe@company.com Phone: +1-555-1234 Location: New York """ users = [] for _ in range(count): result = client.synthesize(template, language="en") users.append(result.text) return users # Usage test_users = generate_test_users(100) # 100 unique, realistic user profiles ``` ### Populate Demo Database ```python theme={null} def populate_demo_db(template_data: list): """Fill demo database with synthetic data""" for template in template_data: synthetic = client.synthesize(template, language="en") # Parse and insert demo_db.insert(parse_profile(synthetic.text)) # Usage templates = load_production_templates() populate_demo_db(templates) ``` ### Create Training Dataset ```python theme={null} def create_training_data(examples: list, count: int): """Generate training data from examples""" training_set = [] for example in examples: for _ in range(count): synthetic = client.synthesize(example, language="en") training_set.append(synthetic.text) return training_set # Usage examples = ["Patient John Doe diagnosed with condition X", ...] training_data = create_training_data(examples, 100) # 100 synthetic examples per template ``` ## Common Use Cases Generate test data for automated test suites: ```python theme={null} def test_user_registration(): # Generate unique test user test_user = client.synthesize( "Name: John Doe, Email: john@test.com", language="en" ).text # Use in test response = api.register_user(test_user) assert response.status_code == 200 ``` **Benefits**: Fresh test data each run, no PII in test environments Create realistic demo data: ```python theme={null} # Generate demo customers def setup_demo_environment(): templates = [ "Enterprise customer: Company X, contact: john@x.com", "Small business: Company Y, contact: jane@y.com" ] for template in templates: synthetic = client.synthesize(template) create_demo_account(synthetic.text) ``` **Benefits**: Realistic demos without real customer data Generate data for performance testing: ```python theme={null} def load_test_data_generator(count: int): """Generate data for load testing""" template = "User: john@example.com, Session: abc123" test_data = [] for _ in range(count): synthetic = client.synthesize(template) test_data.append(synthetic.text) return test_data # Generate 10,000 test records load_data = load_test_data_generator(10000) ``` **Benefits**: Large-scale test data without PII concerns Create safe data for screenshots and marketing materials: ```python theme={null} def prepare_screenshot_data(): """Generate data for product screenshots""" user_data = client.synthesize( "User: Jane Doe, Email: jane@company.com", language="en" ) # Use in screenshot - safe for public release return user_data.text ``` **Benefits**: No privacy risks in public materials ## Best Practices ### 1. Use Templates Create templates for consistent synthetic data: ```python theme={null} # Define templates TEMPLATES = { 'user': "Name: {name}, Email: {email}, Phone: {phone}", 'company': "Company: {company}, Location: {location}" } # Generate from templates def generate_user(): return client.synthesize(TEMPLATES['user'], language="en") ``` ### 2. Locale-Specific Data Use appropriate language for your audience: ```python theme={null} # European demo environment if region == "EU": # Generate German data demo_data = client.synthesize(template, language="de") elif region == "US": # Generate US data demo_data = client.synthesize(template, language="en") ``` ### 3. Document Synthetic Data Use Clearly mark synthetic data in your systems: ```python theme={null} synthetic_user = { 'name': result.text, 'is_synthetic': True, # Mark as synthetic 'generated_at': datetime.now() } ``` ### 4. Combine with Other Methods Use synthesis alongside other privacy methods: ```python theme={null} # Synthesis for testing test_data = client.synthesize(template) # Tokenization for production prod_data = client.tokenize(real_user_input) ``` ## Learn More Full Python SDK documentation Complete JavaScript guide Sync and async Java client HTTP API reference for /synthesize Practical integration examples ## Compare with Other Methods Reversible replacement (restore later) Partial visibility for users Complete permanent removal Consistent identifiers for analytics # Tokenization Source: https://docs.blindfold.dev/methods/tokenization Replace sensitive data with reversible tokens ## What is Tokenization? Tokenization is a reversible privacy protection method that replaces sensitive data with placeholder tokens (e.g., ``, ``). The original values are stored in a mapping that allows you to restore the data later. **Example:** ``` Input: "Contact John Doe at john@example.com" Output: "Contact at " Mapping: { "": "John Doe", "": "john@example.com" } ``` ## How It Works 1. **Detection**: Blindfold's AI engine scans your text and identifies sensitive entities (names, emails, phone numbers, etc.) 2. **Replacement**: Each detected entity is replaced with a unique token based on its type 3. **Mapping**: A mapping dictionary is created to link tokens back to original values 4. **Detokenization**: Later, you can use the mapping to restore the original data ## When to Use Tokenization Tokenization is ideal when you need to: ### 1. Protect Data Sent to AI Models Send user data to OpenAI, Anthropic, or other LLMs without exposing sensitive information. ```python theme={null} # Tokenize before sending to AI protected = client.tokenize("My email is john@example.com") ai_response = openai.chat(protected.text) # Restore original data in the response final = client.detokenize(ai_response, protected.mapping) ``` **Why this matters:** * AI providers log conversations * Prevents PII from being stored in third-party systems * Maintains compliance with privacy regulations ### 2. Temporary Data Anonymization Anonymize data for processing, then restore it afterward. ```python theme={null} # Process data anonymously protected = client.tokenize(user_message) processed = process_in_third_party_service(protected.text) # Restore when needed final = client.detokenize(processed, protected.mapping) ``` ### 3. Data Sharing with External Partners Share data with partners or contractors without exposing real PII. ```python theme={null} # Share tokenized data protected = client.tokenize(customer_data) send_to_partner(protected.text) # Partner processes tokenized data # You can restore when getting results back ``` ### 4. Development and Testing Use tokenized production data in development environments. ```python theme={null} # Tokenize production data for dev environment protected = client.tokenize(production_data) load_into_dev_database(protected.text) ``` ## When NOT to Use Tokenization Tokenization is **not suitable** when: ### 1. You Don't Need to Restore Data If you never need the original values, use **Redaction** or **Hashing** instead. ```python theme={null} # Bad - unnecessary tokenization protected = client.tokenize(log_message) # Never use the mapping # Good - use redaction redacted = client.redact(log_message) ``` ### 2. You Need Partial Visibility If users need to see part of the data (like last 4 digits of a card), use **Masking**. ```python theme={null} # Bad - completely hidden protected = client.tokenize("Card: 4532-7562-9102-3456") # Output: "Card: " # Good - show last 4 digits masked = client.mask("Card: 4532-7562-9102-3456") # Output: "Card: ***************3456" ``` ### 3. You Need Consistent Identifiers For analytics or tracking, use **Hashing** to get deterministic identifiers. ```python theme={null} # Bad - different tokens each time token1 = client.tokenize("john@example.com") # token2 = client.tokenize("john@example.com") # (different!) # Good - same hash every time hash1 = client.hash("john@example.com") # ID_a3f8b9c2... hash2 = client.hash("john@example.com") # ID_a3f8b9c2... (same!) ``` ## Key Features Restore original data anytime using the mapping Different tokens for different entity types (PERSON, EMAIL, etc.) Same value gets same token within one request Automatically detects names, emails, SSNs, cards, and more ## Token Format Tokens follow a predictable format: `` * ``, `` - Person names * ``, `` - Email addresses * `` - Phone numbers * `` - Credit card numbers * `` - Social Security Numbers * And 50+ more types... ## Quick Start ```python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key") # Tokenize response = client.tokenize( "My email is john@example.com and phone is +1-555-1234" ) print(response.text) # "My email is and phone is " print(response.mapping) # {'': 'john@example.com', '': '+1-555-1234'} # Detokenize original = client.detokenize( "Contact ", response.mapping ) print(original.text) # "Contact john@example.com" ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key' }); // Tokenize const response = await client.tokenize( "My email is john@example.com and phone is +1-555-1234" ); console.log(response.text); // "My email is and phone is " console.log(response.mapping); // {'': 'john@example.com', '': '+1-555-1234'} // Detokenize const original = await client.detokenize( "Contact ", response.mapping ); console.log(original.text); // "Contact john@example.com" ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold client = new Blindfold("your-api-key"); // Tokenize var response = client.tokenize( "My email is john@example.com and phone is +1-555-1234" ); System.out.println(response.getText()); // "My email is and phone is " System.out.println(response.getMapping()); // {=john@example.com, =+1-555-1234} // Detokenize var original = client.detokenize( "Contact ", response.getMapping() ); System.out.println(original.getText()); // "Contact john@example.com" ``` ```bash theme={null} # Tokenize curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "text": "My email is john@example.com and phone is +1-555-1234" }' # Response includes mapping for detokenization { "text": "My email is and phone is ", "mapping": { "": "john@example.com", "": "+1-555-1234" } } # Detokenize curl -X POST https://api.blindfold.dev/api/public/v1/detokenize \ -H "X-API-Key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "text": "Contact ", "mapping": { "": "john@example.com" } }' ``` ## Configuration Options ### Filter Specific Entity Types Only detect and tokenize specific types of sensitive data: ```python theme={null} response = client.tokenize( "John Doe lives at 123 Main St, email: john@example.com", config={ "entities": ["EMAIL_ADDRESS"] # Only tokenize emails } ) # Output: "John Doe lives at 123 Main St, email: " ``` ### Adjust Confidence Threshold Control detection sensitivity (0.0 - 1.0): ```python theme={null} response = client.tokenize( text="Maybe email: test@test", config={ "score_threshold": 0.8 # Only high-confidence detections } ) ``` * **Lower threshold (0.3)**: More detections, may include false positives * **Higher threshold (0.8)**: Fewer detections, only very confident matches ## Security Best Practices ### 1. Store Mappings Securely Treat mappings like passwords - store them encrypted: ```python theme={null} # Store mapping in encrypted session session['token_mapping'] = encrypt(protected.mapping) # Later, decrypt and detokenize mapping = decrypt(session['token_mapping']) final = client.detokenize(text, mapping) ``` ### 2. Implement Mapping TTL Don't store mappings forever: ```python theme={null} # Set expiration on mapping storage redis.setex( f"mapping:{session_id}", 3600, # 1 hour TTL json.dumps(protected.mapping) ) ``` ### 3. Clear Mappings After Use Delete mappings when no longer needed: ```python theme={null} # Process and clean up protected = client.tokenize(user_input) ai_response = process_with_ai(protected.text) final = client.detokenize(ai_response, protected.mapping) # Clear the mapping del protected.mapping # or delete from storage ``` ## Common Use Cases Protect user conversations with AI models: ```python theme={null} # 1. Tokenize user input protected = client.tokenize(user_message) # 2. Send to AI (protected) ai_response = openai.chat(protected.text) # 3. Restore original data final = client.detokenize(ai_response, protected.mapping) ``` **Benefits**: No PII reaches AI provider, full compliance maintained Share data with vendors without exposing PII: ```python theme={null} # Tokenize before sending to vendor protected = client.tokenize(customer_data) vendor_api.process(protected.text) # Restore results from vendor results = vendor_api.get_results() final = client.detokenize(results, protected.mapping) ``` **Benefits**: Vendors never see real PII, easier compliance Use production-like data safely in dev: ```python theme={null} # Tokenize production data protected = client.tokenize(prod_customer_records) # Load into dev database dev_db.insert(protected.text) # Developers work with realistic but safe data ``` **Benefits**: Realistic testing without PII exposure risk Log events without storing sensitive data: ```python theme={null} # Tokenize before logging protected = client.tokenize(event_details) # Log safely logger.info(f"User action: {protected.text}") # Store mapping separately if needed for investigation audit_store.save_mapping(event_id, protected.mapping) ``` **Benefits**: Logs are safe to store, can restore if needed ## Learn More Full Python SDK documentation Complete JavaScript guide Sync and async Java client HTTP API reference for /tokenize Practical integration examples ## Compare with Other Methods Not sure if tokenization is right for you? Compare with alternatives: Partial visibility (e.g., \*\*\*\*3456) Permanent removal Consistent identifiers for analytics AES encryption with key # Quickstart Source: https://docs.blindfold.dev/quickstart Start protecting PII before sending to OpenAI, Anthropic Claude, Google Gemini, or any LLM Start detecting PII in under 5 minutes. Local mode is **free forever** — no signup, no API key, no network calls. ## Try It Instantly (Free, No API Key) All SDKs include **local mode** with 86 regex-based entity types and all 8 operations (detect, tokenize, redact, mask, hash, encrypt, synthesize, detokenize). Your data never leaves your infrastructure. You only need an API key if you want NLP-powered detection via the Cloud API. ```bash theme={null} pip install blindfold-sdk ``` ```python theme={null} from blindfold import Blindfold # No API key needed — runs entirely in-process client = Blindfold() result = client.tokenize("Contact john@example.com or call +1-555-1234") print(result.text) # "Contact or call " ``` ```bash theme={null} npm install @blindfold/sdk ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; // No API key needed — runs entirely in-process const client = new Blindfold(); const result = await client.tokenize("Contact john@example.com or call +1-555-1234"); console.log(result.text); // "Contact or call " ``` ```xml theme={null} dev.blindfold blindfold-sdk 1.0.0 ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; // No API key needed — runs entirely in-process Blindfold client = new Blindfold(); var result = client.tokenize("Contact john@example.com or call +1-555-1234"); System.out.println(result.getText()); // "Contact or call " ``` ```bash theme={null} go get github.com/blindfold-dev/Blindfold/packages/go-sdk ``` ```go theme={null} import blindfold "github.com/blindfold-dev/Blindfold/packages/go-sdk" // No API key needed — runs entirely in-process client := blindfold.New() result, _ := client.Tokenize(ctx, "Contact john@example.com or call +1-555-1234") fmt.Println(result.Text) // "Contact or call " ``` ```bash theme={null} dotnet add package Blindfold.Sdk ``` ```csharp theme={null} using Blindfold.Sdk; // No API key needed — runs entirely in-process using var client = new BlindfoldClient(); var result = await client.TokenizeAsync("Contact john@example.com or call +1-555-1234"); Console.WriteLine(result.Text); // "Contact or call " ``` **Local mode is free forever.** No data leaves your infrastructure — everything runs in-process with zero network calls. Supports 86 regex-based entity types (emails, phones, credit cards, SSNs, IBANs, and more) and all 8 privacy operations. Need NLP-powered detection (names, addresses, organizations), compliance policies, or audit logs? Continue below to set up the optional Cloud API. *** ## Step 1: Create an Account Sign up for a Blindfold account to get started. Create your free account at app.blindfold.dev After signing up, you will be automatically logged into the dashboard. ## Step 2: Generate an API Key Once logged in, navigate to the API Keys section to create your first API key. In the dashboard, click on **API Keys** in the sidebar navigation. Click the **Create API Key** button. Give your API key a descriptive name (e.g., "Development", "Production App"). Copy the generated API key and store it securely. You will not be able to see it again. Keep your API key secure and never commit it to version control. Use environment variables to store your keys. ## Step 3: Make Your First API Call Choose your preferred integration method and make your first request. Install the Python SDK and tokenize your first text. ```bash theme={null} pip install blindfold-sdk ``` ```python theme={null} from blindfold import Blindfold # Initialize the client client = Blindfold(api_key="your-api-key-here") # Tokenize text with sensitive data response = client.tokenize( "My email is john@example.com and phone is +1-555-1234" ) print(response.text) # Output: "My email is and phone is " print(response.mapping) # Output: {'': 'john@example.com', '': '+1-555-1234'} ``` The SDK automatically handles API authentication and request formatting. Install the JavaScript SDK and tokenize your first text. ```bash theme={null} npm install @blindfold/sdk ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; // Initialize the client const client = new Blindfold({ apiKey: 'your-api-key-here' }); // Tokenize text with sensitive data const response = await client.tokenize( "My email is john@example.com and phone is +1-555-1234" ); console.log(response.text); // Output: "My email is and phone is " console.log(response.mapping); // Output: {'': 'john@example.com', '': '+1-555-1234'} ``` The SDK works in both Node.js and browser environments. Install the Java SDK and tokenize your first text. ```xml theme={null} dev.blindfold blindfold-sdk 1.0.0 ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; // Initialize the client Blindfold client = new Blindfold("your-api-key-here"); // Tokenize text with sensitive data var response = client.tokenize( "My email is john@example.com and phone is +1-555-1234" ); System.out.println(response.getText()); // Output: "My email is and phone is " System.out.println(response.getMapping()); // Output: {=john@example.com, =+1-555-1234} ``` The SDK works with Java 11+ and has no external HTTP dependencies. Install the Go SDK and tokenize your first text. ```bash theme={null} go get github.com/blindfold-dev/Blindfold/packages/go-sdk ``` ```go theme={null} import blindfold "github.com/blindfold-dev/Blindfold/packages/go-sdk" // Initialize the client client := blindfold.New(blindfold.WithAPIKey("your-api-key-here")) // Tokenize text with sensitive data result, err := client.Tokenize(ctx, "My email is john@example.com and phone is +1-555-1234", ) fmt.Println(result.Text) // Output: "My email is and phone is " fmt.Println(result.Mapping) // Output: map[:john@example.com :+1-555-1234] ``` The SDK has zero external dependencies — uses only the Go standard library. Install the .NET SDK and tokenize your first text. ```bash theme={null} dotnet add package Blindfold.Sdk ``` ```csharp theme={null} using Blindfold.Sdk; // Initialize the client using var client = new BlindfoldClient("your-api-key-here"); // Tokenize text with sensitive data var result = await client.TokenizeAsync( "My email is john@example.com and phone is +1-555-1234" ); Console.WriteLine(result.Text); // Output: "My email is and phone is " Console.WriteLine(result.Mapping); // Output: {: john@example.com, : +1-555-1234} ``` The SDK targets net6.0, net8.0, and netstandard2.1. Zero external dependencies. Make a direct API call using cURL or any HTTP client. ```bash theme={null} curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "My email is john@example.com and phone is +1-555-1234" }' ``` **Response:** ```json theme={null} { "text": "My email is and phone is ", "mapping": { "": "john@example.com", "": "+1-555-1234" }, "entities_count": 2, "detected_entities": [ { "type": "EMAIL_ADDRESS", "text": "john@example.com", "start": 12, "end": 28, "score": 1.0 }, { "type": "PHONE_NUMBER", "text": "+1-555-1234", "start": 42, "end": 53, "score": 0.85 } ] } ``` Replace `your-api-key-here` with your actual API key from Step 2. **Data Residency**: Need your data processed in a specific region? Use `region="eu"` or `region="us"` when initializing the client. See [Regions](/essentials/regions) for details. ## Step 4: Restore Original Data (Detokenize) After sending tokenized data to AI or processing, you can restore the original values using the mapping. ```python theme={null} from blindfold import Blindfold client = Blindfold(api_key="your-api-key-here") # Step 1: Tokenize sensitive data protected = client.tokenize( "Contact John Doe at john@example.com or call +1-555-1234" ) print(protected.text) # "Contact at or call " # Step 2: Send to AI (protected data only) ai_response = f"We received your request: {protected.text}" # AI never sees real PII! # Step 3: Restore original data original = client.detokenize( text=ai_response, mapping=protected.mapping ) print(original) # "We received your request: Contact John Doe at john@example.com or call +1-555-1234" ``` Store the mapping securely. Without it, you cannot restore original values. ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const client = new Blindfold({ apiKey: 'your-api-key-here' }); // Step 1: Tokenize sensitive data const protected = await client.tokenize( "Contact John Doe at john@example.com or call +1-555-1234" ); console.log(protected.text); // "Contact at or call " // Step 2: Send to AI (protected data only) const aiResponse = `We received your request: ${protected.text}`; // AI never sees real PII! // Step 3: Restore original data const original = await client.detokenize( aiResponse, protected.mapping ); console.log(original); // "We received your request: Contact John Doe at john@example.com or call +1-555-1234" ``` ```java theme={null} import dev.blindfold.sdk.Blindfold; Blindfold client = new Blindfold("your-api-key-here"); // Step 1: Tokenize sensitive data var protected_ = client.tokenize( "Contact John Doe at john@example.com or call +1-555-1234" ); System.out.println(protected_.getText()); // "Contact at or call " // Step 2: Send to AI (protected data only) String aiResponse = "We received your request: " + protected_.getText(); // AI never sees real PII! // Step 3: Restore original data var original = client.detokenize(aiResponse, protected_.getMapping()); System.out.println(original.getText()); // "We received your request: Contact John Doe at john@example.com or call +1-555-1234" ``` ```go theme={null} import blindfold "github.com/blindfold-dev/Blindfold/packages/go-sdk" client := blindfold.New(blindfold.WithAPIKey("your-api-key-here")) // Step 1: Tokenize sensitive data protected, _ := client.Tokenize(ctx, "Contact John Doe at john@example.com or call +1-555-1234", ) fmt.Println(protected.Text) // "Contact at or call " // Step 2: Send to AI (protected data only) aiResponse := fmt.Sprintf("We received your request: %s", protected.Text) // Step 3: Restore original data original := client.Detokenize(aiResponse, protected.Mapping) fmt.Println(original.Text) // "We received your request: Contact John Doe at john@example.com or call +1-555-1234" ``` ```csharp theme={null} using Blindfold.Sdk; using var client = new BlindfoldClient("your-api-key-here"); // Step 1: Tokenize sensitive data var safe = await client.TokenizeAsync( "Contact John Doe at john@example.com or call +1-555-1234" ); Console.WriteLine(safe.Text); // "Contact at or call " // Step 2: Send to AI (protected data only) var aiResponse = $"We received your request: {safe.Text}"; // Step 3: Restore original data var original = client.Detokenize(aiResponse, safe.Mapping); Console.WriteLine(original.Text); // "We received your request: Contact John Doe at john@example.com or call +1-555-1234" ``` ```bash theme={null} # Step 1: Tokenize curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "Contact John Doe at john@example.com or call +1-555-1234" }' # Save the mapping from response # { # "text": "Contact at or call ", # "mapping": { # "": "John Doe", # "": "john@example.com", # "": "+1-555-1234" # } # } # Step 2: Send tokenized text to AI (not shown) # Step 3: Detokenize to restore original curl -X POST https://api.blindfold.dev/api/public/v1/detokenize \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "We received: Contact at ", "mapping": { "": "John Doe", "": "john@example.com" } }' # Response: # { # "text": "We received: Contact John Doe at john@example.com" # } ``` **Complete Privacy Flow**: Tokenize → Process with AI → Detokenize This ensures AI providers never see real PII, meeting GDPR and EU AI Act requirements. ## Response Format All responses include: * `text` - Protected text * `entities_count` - Number of PII items found * `detected_entities` - Details about what was found * `mapping` - Token mapping (tokenize only) ## Use Policies for Easy Compliance Instead of specifying entities manually, use pre-configured compliance policies: ```python theme={null} # GDPR compliance (European data) response = client.tokenize( "Contact: John Doe, john@example.com, +49 30 12345", policy="gdpr_eu" ) # HIPAA compliance (Healthcare data) response = client.tokenize( "Patient: Jane Smith, SSN: 123-45-6789", policy="hipaa_us" ) ``` ```javascript theme={null} // GDPR compliance (European data) const response = await client.tokenize( "Contact: John Doe, john@example.com, +49 30 12345", { policy: "gdpr_eu" } ); // HIPAA compliance (Healthcare data) const response2 = await client.tokenize( "Patient: Jane Smith, SSN: 123-45-6789", { policy: "hipaa_us" } ); ``` ```java theme={null} // GDPR compliance (European data) var response = client.tokenize( "Contact: John Doe, john@example.com, +49 30 12345" ); // HIPAA compliance (Healthcare data) var response2 = client.tokenize( "Patient: Jane Smith, SSN: 123-45-6789" ); ``` ```go theme={null} // GDPR compliance (European data) result, _ := client.Tokenize(ctx, "Contact: John Doe, john@example.com, +49 30 12345", blindfold.WithCallPolicy("gdpr_eu"), ) // HIPAA compliance (Healthcare data) result2, _ := client.Tokenize(ctx, "Patient: Jane Smith, SSN: 123-45-6789", blindfold.WithCallPolicy("hipaa_us"), ) ``` ```csharp theme={null} // GDPR compliance (European data) var result = await client.TokenizeAsync( "Contact: John Doe, john@example.com, +49 30 12345", policy: "gdpr_eu" ); // HIPAA compliance (Healthcare data) var result2 = await client.TokenizeAsync( "Patient: Jane Smith, SSN: 123-45-6789", policy: "hipaa_us" ); ``` ```bash theme={null} # GDPR compliance curl -X POST https://api.blindfold.dev/api/public/v1/tokenize \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json" \ -d '{ "text": "Contact: John Doe, john@example.com", "policy": "gdpr_eu" }' ``` **Available Policies:** * `basic` - Names, emails, phones * `gdpr_eu` - GDPR compliance * `hipaa_us` - Healthcare compliance * `pci_dss` - Payment card compliance * `strict` - Maximum protection ## Next Steps Now that you have made your first API call, explore more features: Learn about all Python SDK features and methods. Explore JavaScript/TypeScript SDK capabilities. Sync and async clients for Java 11+. Zero-dependency SDK with context support. async/await for .NET 6, 8, and Standard 2.1. Complete API endpoint documentation. OpenAI, Anthropic Claude, Gemini, LangChain, and more. Real-world use cases and integration patterns. ## Need Help? Contact us at [support@blindfold.dev](mailto:support@blindfold.dev) for support and questions. # RAG Pipeline Protection Source: https://docs.blindfold.dev/rag Protect PII in Retrieval-Augmented Generation pipelines with selective ingestion redaction and query-time tokenization Learn how to build RAG pipelines where personal data never reaches your LLM provider. Blindfold provides two protection layers: **selective ingestion redaction** (strip contact info before indexing, keep names for searchability) and **query-time tokenization** (protect context and questions before the LLM, restore real data in responses). ## Why RAG Needs PII Protection RAG pipelines are the #1 pattern where PII leaks into LLMs. Documents retrieved from your knowledge base — support tickets, customer records, internal reports — often contain personal data. When those documents are embedded, stored, and retrieved, the PII flows through multiple systems: 1. **Retrieval results** — documents with PII are injected into LLM prompts 2. **LLM provider logs** — your provider sees the full prompt, including retrieved PII The privacy boundary is at the **LLM API call**, not the vector store. Your vector store is internal infrastructure; the LLM provider is an external third party. Blindfold protects data at both layers: selectively strip contact info from documents before they enter the vector store, and tokenize everything before it reaches the LLM. ## Security Trade-offs There is no one-size-fits-all approach to PII in RAG pipelines. The right choice depends on your threat model: | Approach | Names in vector store | Name-based search | PII at LLM boundary | Complexity | | ------------------------------------- | --------------------- | ------------------------ | ------------------- | ---------- | | **Selective redaction** (recommended) | Yes | Yes | No (tokenized) | Low | | **Full redaction** | No | No — content-based only | No | Low | | **Tokenize with stored mapping** | No (tokens only) | Yes (via reverse lookup) | No | High | ### Selective Redaction (Recommended) Redact **contact info** (emails, phones, IBANs) at ingestion — **keep person names** for searchability. At query time, search with the original question (names match), then tokenize context + question in a single call before the LLM. This is the approach used in all cookbook examples and described below. ### Full Redaction Redact **all PII** at ingestion. Strongest privacy — no personal data anywhere — but you lose the ability to search by name. The vector store can only match based on surrounding content. ### Tokenize with Stored Mapping (Advanced) Tokenize at ingestion and store the mapping. Build a reverse lookup to translate real names in queries to tokens. No PII in the vector store **and** name-based search works. See the [advanced section below](#advanced-tokenize-with-stored-mapping) for details. ## Two Protection Layers ### Layer 1: Selective Ingestion Redaction Redact contact info from documents before embedding and indexing. Names are kept so the vector store can match name-based queries. ```python theme={null} from blindfold import Blindfold blindfold = Blindfold(api_key="your-api-key") documents = [ "Customer John Smith (john@example.com) reported a billing error.", "Maria Garcia (+34 612 345 678) requested a data export.", ] safe_documents = [] for doc in documents: # Redact contact info only — keep names searchable result = blindfold.redact(doc, entities=["email address", "phone number"]) safe_documents.append(result.text) # "Customer John Smith ([EMAIL_ADDRESS]) reported a billing error." # Index safe_documents into your vector store ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; const blindfold = new Blindfold({ apiKey: 'your-api-key' }); const documents = [ 'Customer John Smith (john@example.com) reported a billing error.', 'Maria Garcia (+34 612 345 678) requested a data export.', ]; const safeDocuments = []; for (const doc of documents) { // Redact contact info only — keep names searchable const result = await blindfold.redact(doc, { entities: ['email address', 'phone number'], }); safeDocuments.push(result.text); } // Index safeDocuments into your vector store ``` ```python theme={null} from langchain_blindfold import BlindfoldPIITransformer from langchain_core.documents import Document # Redact contact info only — keep names searchable transformer = BlindfoldPIITransformer( pii_method="redact", entities=["email address", "phone number"], ) docs = [ Document(page_content="Customer John Smith (john@example.com) reported a billing error."), Document(page_content="Maria Garcia (+34 612 345 678) requested a data export."), ] safe_docs = transformer.transform_documents(docs) # Index safe_docs into your vector store ``` **Why keep names?** At ingestion, person names are replaced with `[PERSON]`. At query time, names are tokenized to ``. Neither placeholder matches the other — so searching for "Hans Mueller" cannot find `[PERSON]` in the vector store. Keeping names at ingestion solves this and lets users search by name. Contact info (emails, phones) is rarely searched for and should always be redacted. ### Layer 2: Query-Time Tokenization After retrieval, tokenize the context and question **in a single call** before they reach the LLM. Then detokenize the response to restore real data. ```python theme={null} from blindfold import Blindfold from openai import OpenAI blindfold = Blindfold(api_key="your-api-key") openai_client = OpenAI() question = "What happened with John Smith's billing issue?" # Step 1: Search with original question — names match in vector store results = collection.query(query_texts=[question], n_results=3) context = "\n\n".join(results["documents"][0]) # Step 2: Single tokenize call — consistent token numbering prompt_text = f"Context:\n{context}\n\nQuestion: {question}" tokenized = blindfold.tokenize(prompt_text) # Step 3: Send to LLM — no PII in the prompt response = openai_client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "Answer using the provided context."}, {"role": "user", "content": tokenized.text}, ], ) ai_response = response.choices[0].message.content # Step 4: Detokenize — restore real names in the response final = blindfold.detokenize(ai_response, tokenized.mapping) print(final.text) ``` ```javascript theme={null} import { Blindfold } from '@blindfold/sdk'; import OpenAI from 'openai'; const blindfold = new Blindfold({ apiKey: 'your-api-key' }); const openai = new OpenAI(); const question = "What happened with John Smith's billing issue?"; // Step 1: Search with original question — names match const results = await collection.query({ queryTexts: [question], nResults: 3, }); const context = results.documents[0].join('\n\n'); // Step 2: Single tokenize call — consistent token numbering const promptText = `Context:\n${context}\n\nQuestion: ${question}`; const tokenized = await blindfold.tokenize(promptText); // Step 3: Send to LLM — no PII const response = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [ { role: 'system', content: 'Answer using the provided context.' }, { role: 'user', content: tokenized.text }, ], }); const aiResponse = response.choices[0].message.content; // Step 4: Detokenize const final = blindfold.detokenize(aiResponse, tokenized.mapping); console.log(final.text); ``` ```python theme={null} from blindfold import Blindfold from langchain_openai import ChatOpenAI from langchain_core.runnables import RunnableLambda blindfold_client = Blindfold(api_key="your-api-key") def retrieve_and_tokenize(question: str) -> dict: # Retrieve with original question — names match docs = retriever.invoke(question) context = "\n\n".join(doc.page_content for doc in docs) # Single tokenize call — consistent token numbering prompt_text = f"Context:\n{context}\n\nQuestion: {question}" tokenized = blindfold_client.tokenize(prompt_text) return {"tokenized_text": tokenized.text, "mapping": tokenized.mapping} chain = RunnableLambda(retrieve_and_tokenize) | ... # LLM + detokenize ``` **Why a single tokenize call?** If you tokenize the context and question separately, each call produces independent token numbering. Context might map `` to "Hans Mueller" while the question maps `` to "Marie Dupont" — creating mapping conflicts. A single call on the combined text ensures consistent numbering. ## Protection Method Comparison Choose the right protection method for your RAG use case: | Method | Reversible | Best for | Example output | | ------------ | -------------- | --------------------------------------- | --------------------------------- | | **Redact** | No | Ingestion — permanent PII removal | `[PERSON]`, `[EMAIL_ADDRESS]` | | **Tokenize** | Yes | Queries — protect input, restore output | ``, `` | | **Encrypt** | Yes (with key) | Regulated data requiring audit trail | `ENC_a8f3b2...` | | **Hash** | No | Analytics — consistent pseudonymous IDs | `HASH_a3f8b9c2d4e5` | **Recommended pattern:** Use `redact` with `entities` at ingestion time (Layer 1) to strip contact info while keeping names. At query time (Layer 2), search with the original question and `tokenize` the combined context + question before the LLM call. This gives you searchability by name and full PII protection at the LLM boundary. ## Advanced: Tokenize with Stored Mapping For the strongest privacy with full searchability — no PII in the vector store **and** name-based search — tokenize at ingestion and store the mapping. This is the most complete architecture but requires managing a mapping store. **How it works:** 1. **Ingestion**: `tokenize()` each document → store tokenized text in vector store + store mapping securely 2. **Query**: Build a reverse lookup from stored mappings. Replace real names in the query with their tokens before searching 3. **LLM**: Tokenized context + tokenized query → LLM sees only tokens 4. **Response**: Detokenize using stored mappings ```python theme={null} from blindfold import Blindfold blindfold = Blindfold(api_key="your-api-key") # === Ingestion === documents = [...] mapping_store = {} # In production: encrypted DB or secrets manager for doc in documents: result = blindfold.tokenize(doc) # Store tokenized text in vector store vectorstore.add(result.text) # Store mapping securely (keyed by doc ID or merged globally) mapping_store.update(result.mapping) # Build reverse lookup: real value → token reverse_lookup = {v: k for k, v in mapping_store.items()} # === Query === question = "What happened with Hans Mueller?" # Replace known real values with their tokens for real_value, token in reverse_lookup.items(): question = question.replace(real_value, token) # question: "What happened with ?" # Search with tokenized query — tokens match tokens in vector store results = vectorstore.query(question, n_results=3) # Context is already tokenized, question is already tokenized # Send directly to LLM — no PII response = llm.generate(context=results, question=question) # Detokenize for the user final = blindfold.detokenize(response, mapping_store) ``` **Trade-offs:** * Requires managing a mapping store (encrypted DB, secrets manager) * Reverse lookup needs exact string matching (partial names may not match) * More complex than the selective-redaction approach * But: **strongest privacy with full searchability** — no PII in the vector store at all `detokenize()` is a free local operation — no API call. This means the mapping store is the only infrastructure you need to manage. ## Policy Recommendations Match your compliance policy to your use case: | Use case | Policy | Region | Key entities detected | | ---------------- | ---------- | ------ | -------------------------------------------------- | | General RAG | `basic` | — | Names, emails, phones, addresses, credit cards | | EU customer data | `gdpr_eu` | `eu` | Names, emails, IBANs, national IDs, DOB, addresses | | US healthcare | `hipaa_us` | `us` | All 18 HIPAA identifiers (SSN, MRN, DOB, etc.) | | Payment data | `pci_dss` | — | Credit cards, CVVs, expiration dates | | Maximum coverage | `strict` | — | All supported entity types, lowest threshold | ```python theme={null} # GDPR-compliant RAG — redact contact info, keep names blindfold = Blindfold(api_key="your-key", region="eu") result = blindfold.redact(document, policy="gdpr_eu", entities=[ "email address", "phone number", "iban", "credit card number", "address", "date of birth", "national id number", ]) # HIPAA-compliant RAG blindfold = Blindfold(api_key="your-key", region="us") result = blindfold.redact(document, policy="hipaa_us") ``` ## Performance Tips * **Batch redaction at ingestion** — use `blindfold.redact_batch()` for processing multiple documents in one API call * **Async processing** — use `AsyncBlindfold` for concurrent document processing during ingestion * **Detokenization is free** — `detokenize()` is a local string replacement, no API call required * **Cache redacted documents** — once documents are redacted and indexed, no further Blindfold calls are needed for retrieval ## Cookbook Examples Complete, runnable examples for every RAG framework: Selective redaction + search-first tokenization TypeScript OpenAI + ChromaDB RAG pipeline BlindfoldPIITransformer + retrieve-then-tokenize LangChain.js RAG with inline PII protection Retrieve-then-tokenize with LlamaIndex LlamaIndex.TS with single tokenize call Multi-turn EU support chatbot with gdpr\_eu policy TypeScript multi-turn EU support chatbot ### Strategy Deep-Dives Standalone examples for each ingestion strategy — compare trade-offs side by side: Keep names, redact contact info — simplest approach TypeScript version of the selective redact strategy Tokenize everything, store per-document mappings TypeScript version of the stored mapping strategy Same person = same token everywhere — best search quality TypeScript version of the consistent registry strategy All 3 strategies side by side with CLI selection TypeScript version — all 3 strategies with CLI selection ### Role-Based Access Control (RBAC) Use Blindfold policies to implement role-based PII control — same vector store, different privacy levels per user role: Doctor, nurse, billing, researcher — each role sees different PII levels TypeScript version of the role-based PII control example # CLI Source: https://docs.blindfold.dev/sdks/cli Official Blindfold CLI ```bash theme={null} npm install -g @blindfold/cli ``` ```bash theme={null} blindfold detect "Email john@acme.com, SSN 123-45-6789" # no API key needed blindfold redact --file sensitive-data.txt --quiet > clean.txt ``` All commands, flags, input methods, output formats, and examples. # .NET SDK Source: https://docs.blindfold.dev/sdks/dotnet-sdk Official .NET SDK for Blindfold — detect, tokenize, mask, redact, hash, encrypt, and synthesize PII ## Installation ```bash theme={null} dotnet add package Blindfold.Sdk ``` **Zero external dependencies** — uses only built-in .NET libraries (System.Text.Json). Targets `net6.0`, `net8.0`, and `netstandard2.1`. ## Quick Start (Local Mode) No API key needed — runs entirely in-process with 86 regex-based entity types. ```csharp theme={null} using Blindfold.Sdk; using var client = new BlindfoldClient(); // no API key needed var result = await client.DetectAsync("Email john@acme.com, SSN 123-45-6789"); foreach (var entity in result.DetectedEntities) { Console.WriteLine($"{entity.Type}: {entity.Text}"); } // Email Address: john@acme.com // Social Security Number: 123-45-6789 ``` ## Cloud API Setup For NLP-powered detection (names, addresses, organizations), compliance policies, and audit logs: ```csharp theme={null} using Blindfold.Sdk; // Simple initialization using var client = new BlindfoldClient("your-api-key"); // Full configuration using var client = new BlindfoldClient(new BlindfoldOptions { ApiKey = "your-api-key", Region = "eu", // "eu" (default) or "us" MaxRetries = 3, Timeout = TimeSpan.FromSeconds(30), UserId = "user-123", // optional user tracking }); ``` ## Methods All methods are async with `Async` suffix and accept an optional `CancellationToken` parameter. The client implements `IDisposable`. ### DetectAsync Identify PII without modifying the text. ```csharp theme={null} var result = await client.DetectAsync("Contact John Doe at john@example.com"); Console.WriteLine(result.EntitiesCount); // 2 foreach (var entity in result.DetectedEntities) { Console.WriteLine($"{entity.Type}: {entity.Text} ({entity.Score:F2})"); } ``` ### TokenizeAsync / Detokenize Replace PII with reversible tokens, then restore. ```csharp theme={null} // Tokenize var response = await client.TokenizeAsync( "Contact John Doe at john@example.com" ); Console.WriteLine(response.Text); // "Contact at " Console.WriteLine(response.Mapping); // {: John Doe, : john@example.com} // Detokenize (sync — runs client-side, no API call) var original = client.Detokenize( response.Text, response.Mapping ); Console.WriteLine(original.Text); // "Contact John Doe at john@example.com" ``` ### RedactAsync Permanently remove PII from text. ```csharp theme={null} var result = await client.RedactAsync( "Patient Jane Smith, SSN: 123-45-6789" ); Console.WriteLine(result.Text); // "Patient , SSN: " ``` ### MaskAsync Partially hide PII while keeping some characters visible. ```csharp theme={null} var result = await client.MaskAsync( "Card: 4532-7562-9102-3456", charsToShow: 4, // chars to show fromEnd: true, // from end maskChar: "*", // masking character entities: null // entities filter (null = all) ); Console.WriteLine(result.Text); // "Card: ***************3456" ``` ### HashAsync Create deterministic identifiers for analytics. ```csharp theme={null} var result = await client.HashAsync( "User john@example.com purchased item", hashType: "SHA-256", // hash type prefix: "user_", // prefix hashLength: 16, // hash length entities: null // entities filter ); Console.WriteLine(result.Text); // "User user_a3f8b9c2d4e5f6g7 purchased item" ``` ### EncryptAsync Encrypt PII using AES-256. ```csharp theme={null} var result = await client.EncryptAsync( "API Key: sk-1234567890abcdef", "your-secure-key-min-16-chars" ); Console.WriteLine(result.Text); // "API Key: gAAAAABh3K7x..." ``` ### SynthesizeAsync Replace PII with realistic fake data. ```csharp theme={null} var result = await client.SynthesizeAsync( "John Doe lives in New York", language: "en", // language entities: null // entities filter ); Console.WriteLine(result.Text); // "Michael Smith lives in Boston" (example - will vary) ``` ## Batch Processing Process multiple texts in a single call. ```csharp theme={null} var texts = new[] { "Contact John Doe", "Email jane@example.com", "No PII here" }; var result = await client.TokenizeBatchAsync(texts); Console.WriteLine(result.Total); // 3 Console.WriteLine(result.Succeeded); // 3 foreach (var item in result.Results) { Console.WriteLine(item.Text); } ``` All methods have batch variants: `DetectBatchAsync`, `TokenizeBatchAsync`, `RedactBatchAsync`, `MaskBatchAsync`, `HashBatchAsync`, `EncryptBatchAsync`, `SynthesizeBatchAsync`. ## Entity Filtering Only detect specific entity types: ```csharp theme={null} var result = await client.DetectAsync( "John Doe, SSN 123-45-6789, email john@example.com", entities: new[] { "Social Security Number", "Email Address" } ); // Only SSN and email detected, name is ignored ``` ## Error Handling ```csharp theme={null} using Blindfold.Sdk.Errors; try { var result = await client.TokenizeAsync("..."); } catch (AuthenticationException ex) { // Invalid API key (401) Console.Error.WriteLine("Invalid API key"); } catch (ApiException ex) { // API error (validation, rate limit, etc.) Console.Error.WriteLine($"API error {ex.StatusCode}"); } catch (NetworkException ex) { // Connection issues Console.Error.WriteLine($"Network error: {ex.Message}"); } ``` ## Locales Configure country-specific entity detection: ```csharp theme={null} using var client = new BlindfoldClient(new BlindfoldOptions { Locales = new[] { "us", "de", "fr" } }); ``` Available locales: `us`, `uk`, `eu`, `de`, `fr`, `es`, `it`, `pt`, `pl`, `cz`, `sk`, `ru`, `nl`, `ro`, `dk`, `se`, `no`, `be`, `at`, `ie`, `fi`, `hu`, `bg`, `hr`, `si`, `lt`, `lv`, `ee`, `ca`, `ch`, `au`, `nz`, `in`, `jp`, `kr`, `za`, `tr`, `il`, `ar`, `cl`, `co`, `br` ## Source Code Full source code, API reference, and additional examples. # Go SDK Source: https://docs.blindfold.dev/sdks/go-sdk Official Go SDK for Blindfold — detect, tokenize, mask, redact, hash, encrypt, and synthesize PII ## Installation ```bash theme={null} go get github.com/blindfold-dev/Blindfold/packages/go-sdk ``` **Zero external dependencies** — uses only the Go standard library. ## Quick Start (Local Mode) No API key needed — runs entirely in-process with 86 regex-based entity types. ```go theme={null} package main import ( "context" "fmt" "log" blindfold "github.com/blindfold-dev/Blindfold/packages/go-sdk" ) func main() { client := blindfold.New() // no API key needed ctx := context.Background() result, err := client.Detect(ctx, "Email john@acme.com, SSN 123-45-6789") if err != nil { log.Fatal(err) } for _, entity := range result.DetectedEntities { fmt.Printf("%s: %s\n", entity.Type, entity.Text) } // Email Address: john@acme.com // Social Security Number: 123-45-6789 } ``` ## Cloud API Setup For NLP-powered detection (names, addresses, organizations), compliance policies, and audit logs: ```go theme={null} import ( "time" blindfold "github.com/blindfold-dev/Blindfold/packages/go-sdk" ) // Simple initialization client := blindfold.New(blindfold.WithAPIKey("your-api-key")) // Full configuration client := blindfold.New( blindfold.WithAPIKey("your-api-key"), blindfold.WithRegion("eu"), // "eu" (default) or "us" blindfold.WithLocales([]string{"us", "eu"}), blindfold.WithMaxRetries(3), blindfold.WithTimeout(30 * time.Second), blindfold.WithPolicy("gdpr_eu"), blindfold.WithUserID("user-123"), // optional user tracking ) ``` ## Methods ### Detect Identify PII without modifying the text. ```go theme={null} ctx := context.Background() result, err := client.Detect(ctx, "Contact John Doe at john@example.com") if err != nil { log.Fatal(err) } fmt.Println(result.EntitiesCount) // 2 for _, entity := range result.DetectedEntities { fmt.Printf("%s: %s (%.2f)\n", entity.Type, entity.Text, entity.Score) } ``` ### Tokenize / Detokenize Replace PII with reversible tokens, then restore. ```go theme={null} // Tokenize result, err := client.Tokenize(ctx, "Contact John Doe at john@example.com") if err != nil { log.Fatal(err) } fmt.Println(result.Text) // "Contact at " fmt.Println(result.Mapping) // map[:John Doe :john@example.com] // Detokenize (client-side only, no context needed) original := client.Detokenize(result.Text, result.Mapping) fmt.Println(original.Text) // "Contact John Doe at john@example.com" ``` ### Redact Permanently remove PII from text. ```go theme={null} result, err := client.Redact(ctx, "Patient Jane Smith, SSN: 123-45-6789") if err != nil { log.Fatal(err) } fmt.Println(result.Text) // "Patient , SSN: " ``` ### Mask Partially hide PII while keeping some characters visible. ```go theme={null} result, err := client.Mask(ctx, "Card: 4532-7562-9102-3456", blindfold.WithCharsToShow(4), blindfold.WithFromEnd(true), blindfold.WithMaskingChar("*"), ) if err != nil { log.Fatal(err) } fmt.Println(result.Text) // "Card: ***************3456" ``` ### Hash Create deterministic identifiers for analytics. ```go theme={null} result, err := client.Hash(ctx, "User john@example.com purchased item", blindfold.WithHashType("SHA-256"), blindfold.WithHashPrefix("user_"), blindfold.WithHashLength(16), ) if err != nil { log.Fatal(err) } fmt.Println(result.Text) // "User user_a3f8b9c2d4e5f6g7 purchased item" ``` ### Encrypt Encrypt PII using AES-256. ```go theme={null} result, err := client.Encrypt(ctx, "API Key: sk-1234567890abcdef", "your-secure-key-min-16-chars") if err != nil { log.Fatal(err) } fmt.Println(result.Text) // "API Key: gAAAAABh3K7x..." ``` ### Synthesize Replace PII with realistic fake data. ```go theme={null} result, err := client.Synthesize(ctx, "John Doe lives in New York") if err != nil { log.Fatal(err) } fmt.Println(result.Text) // "Michael Smith lives in Boston" (example - will vary) ``` ## Batch Processing Process multiple texts in a single call. ```go theme={null} texts := []string{ "Contact John Doe", "Email jane@example.com", "No PII here", } result, err := client.TokenizeBatch(ctx, texts) if err != nil { log.Fatal(err) } fmt.Println(result.Total) // 3 fmt.Println(result.Succeeded) // 3 for _, item := range result.Results { fmt.Println(item.Text) } ``` ## Entity Filtering Only detect specific entity types: ```go theme={null} result, err := client.Detect(ctx, "John Doe, SSN 123-45-6789, email john@example.com", blindfold.WithEntities([]string{"Social Security Number", "Email Address"}), ) // Only SSN and email detected, name is ignored ``` ## Error Handling ```go theme={null} import "errors" result, err := client.Tokenize(ctx, "...") if err != nil { var authErr *blindfold.AuthenticationError var apiErr *blindfold.APIError var netErr *blindfold.NetworkError switch { case errors.As(err, &authErr): // Invalid API key (401) fmt.Println("Invalid API key") case errors.As(err, &apiErr): // API error (validation, rate limit, etc.) fmt.Printf("API error %d\n", apiErr.StatusCode) case errors.As(err, &netErr): // Connection issues fmt.Printf("Network error: %s\n", netErr.Error()) } } ``` ## Locales Configure country-specific entity detection: ```go theme={null} client := blindfold.New( blindfold.WithAPIKey("your-api-key"), blindfold.WithLocales([]string{"us", "de", "fr"}), ) ``` Available locales: `us`, `uk`, `eu`, `de`, `fr`, `es`, `it`, `pt`, `pl`, `cz`, `sk`, `ru`, `nl`, `ro`, `dk`, `se`, `no`, `be`, `at`, `ie`, `fi`, `hu`, `bg`, `hr`, `si`, `lt`, `lv`, `ee`, `ca`, `ch`, `au`, `nz`, `in`, `jp`, `kr`, `za`, `tr`, `il`, `ar`, `cl`, `co`, `br` ## Source Code Full source code, documentation, and additional examples. # Guardrails AI Source: https://docs.blindfold.dev/sdks/guardrails PII detection and protection validator for the Guardrails AI framework The `guardrails-blindfold` package integrates Blindfold with [Guardrails AI](https://guardrailsai.com), letting you add PII protection to any Guard with one line. Detect and fix PII in LLM outputs automatically. ## Installation ```bash theme={null} pip install guardrails-blindfold ``` Set your API key: ```bash theme={null} export BLINDFOLD_API_KEY=your-api-key ``` Get a free API key at [app.blindfold.dev](https://app.blindfold.dev). ## Quick Start ```python theme={null} from guardrails import Guard from guardrails_blindfold import BlindfoldPII guard = Guard().use(BlindfoldPII(on_fail="fix")) result = guard.validate("Contact John Doe at john@example.com") print(result.validated_output) # → "Contact at " ``` ## Parameters | Parameter | Type | Default | Description | | ----------------- | ------- | ------------ | ----------------------------------------- | | `policy` | `str` | `"basic"` | Detection policy | | `pii_method` | `str` | `"tokenize"` | How to fix detected PII | | `region` | `str` | `None` | `"eu"` or `"us"` for data residency | | `entities` | `list` | `None` | Specific entity types to detect | | `score_threshold` | `float` | `None` | Confidence threshold (0.0–1.0) | | `api_key` | `str` | `None` | Falls back to `BLINDFOLD_API_KEY` env var | | `on_fail` | `str` | `None` | Guardrails failure action | ### Policies | Policy | Entities | Best For | | ---------- | --------------------------------------------- | ---------------------- | | `basic` | Names, emails, phones, locations | General PII protection | | `gdpr_eu` | EU-specific: IBANs, addresses, dates of birth | GDPR compliance | | `hipaa_us` | PHI: SSNs, MRNs, medical terms | HIPAA compliance | | `pci_dss` | Card numbers, CVVs, expiry dates | PCI DSS compliance | | `strict` | All entity types, lower threshold | Maximum detection | See [Policies](/essentials/policies) for details. ### PII Methods The `pii_method` parameter controls how detected PII is fixed when `on_fail="fix"`: | Method | Output | Reversible | | ------------ | --------------------------------- | -------------- | | `tokenize` | ``, `` | Yes | | `redact` | PII removed entirely | No | | `mask` | `J****oe`, `j****om` | No | | `hash` | `HASH_abc123` | No | | `synthesize` | `Jane Smith`, `jane@example.org` | No | | `encrypt` | AES-256 encrypted value | Yes (with key) | ## Usage Examples ### GDPR Compliance with EU Region ```python theme={null} guard = Guard().use( BlindfoldPII( policy="gdpr_eu", region="eu", on_fail="fix", ) ) result = guard.validate("Hans Mueller, hans.mueller@example.de, IBAN DE89370400440532013000") print(result.validated_output) # → ", , IBAN " ``` ### HIPAA — Redact PHI ```python theme={null} guard = Guard().use( BlindfoldPII( policy="hipaa_us", pii_method="redact", region="us", on_fail="fix", ) ) result = guard.validate("Patient Sarah Jones, SSN 123-45-6789, MRN 4567890") print(result.validated_output) # → PHI redacted from output ``` ### Block Output if PII Detected Use `on_fail="exception"` to raise an error instead of fixing: ```python theme={null} from guardrails.errors import ValidationError guard = Guard().use( BlindfoldPII(policy="strict", on_fail="exception") ) try: result = guard.validate("Email john@example.com") except ValidationError as e: print("PII detected — output blocked") ``` ### Detect Specific Entity Types ```python theme={null} guard = Guard().use( BlindfoldPII( entities=["Email Address", "Phone Number", "Credit Card Number"], on_fail="fix", ) ) ``` ### Chain with Other Validators Blindfold can be combined with any other Guardrails validator: ```python theme={null} guard = Guard().use( BlindfoldPII(policy="strict", on_fail="fix"), ).use( AnotherValidator(on_fail="exception"), ) ``` ### Protect LLM Output in a Chain ```python theme={null} from guardrails import Guard from guardrails_blindfold import BlindfoldPII from openai import OpenAI client = OpenAI() guard = Guard().use(BlindfoldPII(policy="gdpr_eu", on_fail="fix")) response = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": "Write a sample customer profile"}], ) # Validate and protect PII in the LLM output result = guard.validate(response.choices[0].message.content) print(result.validated_output) # PII tokenized ``` ## On-Fail Actions Guardrails supports several failure handling strategies: | Action | Behavior | | ----------- | ------------------------------------------------------------------ | | `fix` | Replace PII with the protected version (tokenized, redacted, etc.) | | `exception` | Raise `ValidationError` — blocks the output entirely | | `noop` | Log the failure but return the original output unchanged | | `reask` | Re-prompt the LLM to regenerate without PII | ## Data Residency Use the `region` parameter to ensure PII is processed in a specific jurisdiction: | Region | Endpoint | Location | | ------ | ---------------------- | ------------------ | | `eu` | `eu-api.blindfold.dev` | Frankfurt, Germany | | `us` | `us-api.blindfold.dev` | Virginia, US | See [Regions](/essentials/regions) for details. ## Links Install from PyPI Source code and issues Guardrails AI documentation Working integration examples # Java SDK Source: https://docs.blindfold.dev/sdks/java-sdk Official Java SDK for Blindfold — detect, tokenize, mask, redact, hash, encrypt, and synthesize PII ## Installation ```xml theme={null} dev.blindfold blindfold-sdk 1.0.0 ``` ```gradle theme={null} implementation 'dev.blindfold:blindfold-sdk:1.0.0' ``` ## Quick Start (Local Mode) No API key needed — runs entirely in-process with 86 regex-based entity types. ```java theme={null} import dev.blindfold.sdk.Blindfold; import dev.blindfold.sdk.models.DetectResponse; Blindfold client = new Blindfold(); // no API key needed DetectResponse result = client.detect("Email john@acme.com, SSN 123-45-6789"); for (var entity : result.getDetectedEntities()) { System.out.println(entity.getType() + ": " + entity.getText()); } // Email Address: john@acme.com // Social Security Number: 123-45-6789 ``` ## Cloud API Setup For NLP-powered detection (names, addresses, organizations), compliance policies, and audit logs: ```java theme={null} import dev.blindfold.sdk.Blindfold; import dev.blindfold.sdk.BlindfoldOptions; // Simple initialization Blindfold client = new Blindfold("your-api-key"); // Full configuration Blindfold client = new Blindfold(BlindfoldOptions.builder() .apiKey("your-api-key") .region("eu") // "eu" (default) or "us" .maxRetries(3) .retryDelay(Duration.ofMillis(500)) .timeout(Duration.ofSeconds(30)) .userId("user-123") // optional user tracking .build()); ``` ## Methods ### Detect Identify PII without modifying the text. ```java theme={null} DetectResponse result = client.detect("Contact John Doe at john@example.com"); System.out.println(result.getEntitiesCount()); // 2 for (var entity : result.getDetectedEntities()) { System.out.printf("%s: %s (%.2f)%n", entity.getType(), entity.getText(), entity.getScore()); } ``` ### Tokenize / Detokenize Replace PII with reversible tokens, then restore. ```java theme={null} import dev.blindfold.sdk.models.TokenizeResponse; import dev.blindfold.sdk.models.DetokenizeResponse; // Tokenize TokenizeResponse response = client.tokenize( "Contact John Doe at john@example.com" ); System.out.println(response.getText()); // "Contact at " System.out.println(response.getMapping()); // {=John Doe, =john@example.com} // Detokenize DetokenizeResponse original = client.detokenize( response.getText(), response.getMapping() ); System.out.println(original.getText()); // "Contact John Doe at john@example.com" ``` ### Redact Permanently remove PII from text. ```java theme={null} import dev.blindfold.sdk.models.RedactResponse; RedactResponse result = client.redact( "Patient Jane Smith, SSN: 123-45-6789" ); System.out.println(result.getText()); // "Patient , SSN: " ``` ### Mask Partially hide PII while keeping some characters visible. ```java theme={null} import dev.blindfold.sdk.models.MaskResponse; MaskResponse result = client.mask( "Card: 4532-7562-9102-3456", 4, // chars to show true, // from end "*", // masking character null // entities filter (null = all) ); System.out.println(result.getText()); // "Card: ***************3456" ``` ### Hash Create deterministic identifiers for analytics. ```java theme={null} import dev.blindfold.sdk.models.HashResponse; HashResponse result = client.hash( "User john@example.com purchased item", "sha256", // hash type "user_", // prefix 16, // hash length null // entities filter ); System.out.println(result.getText()); // "User user_a3f8b9c2d4e5f6g7 purchased item" ``` ### Encrypt Encrypt PII using AES-256. ```java theme={null} import dev.blindfold.sdk.models.EncryptResponse; EncryptResponse result = client.encrypt( "API Key: sk-1234567890abcdef", "your-secure-key-min-16-chars" ); System.out.println(result.getText()); // "API Key: gAAAAABh3K7x..." ``` ### Synthesize Replace PII with realistic fake data. ```java theme={null} import dev.blindfold.sdk.models.SynthesizeResponse; SynthesizeResponse result = client.synthesize( "John Doe lives in New York", "en", // language null // entities filter ); System.out.println(result.getText()); // "Michael Smith lives in Boston" (example - will vary) ``` ## Batch Processing Process multiple texts in a single call. ```java theme={null} import dev.blindfold.sdk.models.BatchResponse; BatchResponse result = client.tokenizeBatch( List.of( "Contact John Doe", "Email jane@example.com", "No PII here" ) ); System.out.println(result.getTotal()); // 3 System.out.println(result.getSucceeded()); // 3 for (TokenizeResponse item : result.getResults()) { System.out.println(item.getText()); } ``` ## Async Client For non-blocking operations using `CompletableFuture`. ```java theme={null} import dev.blindfold.sdk.BlindfoldAsync; BlindfoldAsync asyncClient = new BlindfoldAsync( BlindfoldOptions.builder() .apiKey("your-api-key") .region("eu") .build() ); CompletableFuture future = asyncClient.detectAsync( "Email john@acme.com" ); DetectResponse response = future.get(); System.out.println(response.getEntitiesCount()); ``` ## Entity Filtering Only detect specific entity types: ```java theme={null} DetectResponse result = client.detect( "John Doe, SSN 123-45-6789, email john@example.com", List.of("Social Security Number", "Email Address") ); // Only SSN and email detected, name is ignored ``` ## Error Handling ```java theme={null} import dev.blindfold.sdk.errors.AuthenticationException; import dev.blindfold.sdk.errors.ApiException; import dev.blindfold.sdk.errors.NetworkException; try { client.tokenize("..."); } catch (AuthenticationException e) { // Invalid API key (401) System.err.println("Invalid API key"); } catch (ApiException e) { // API error (validation, rate limit, etc.) System.err.println("API error " + e.getStatusCode()); } catch (NetworkException e) { // Connection issues System.err.println("Network error: " + e.getMessage()); } ``` ## Locales Configure country-specific entity detection: ```java theme={null} Blindfold client = new Blindfold(BlindfoldOptions.builder() .locales(List.of("us", "de", "fr")) .build()); ``` Available locales: `us`, `uk`, `eu`, `de`, `fr`, `es`, `it`, `pt`, `pl`, `cz`, `sk`, `ru`, `nl`, `ro`, `dk`, `se`, `no`, `be`, `at`, `ie`, `fi`, `hu`, `bg`, `hr`, `si`, `lt`, `lv`, `ee`, `ca`, `ch`, `au`, `nz`, `in`, `jp`, `kr`, `za`, `tr`, `il`, `ar`, `cl`, `co`, `br` ## Source Code Full source code, Javadoc, and additional examples. # JavaScript SDK Source: https://docs.blindfold.dev/sdks/javascript-sdk Official JavaScript/TypeScript SDK for Blindfold ```bash theme={null} npm install @blindfold/sdk ``` ```typescript theme={null} import { Blindfold } from '@blindfold/sdk' const client = new Blindfold() // no API key needed const result = await client.detect("Email john@acme.com, SSN 123-45-6789") ``` All methods, configuration options, local scanner, batch processing, and examples. # LangChain Source: https://docs.blindfold.dev/sdks/langchain PII protection for LangChain chains and RAG pipelines The `langchain-blindfold` package integrates Blindfold with [LangChain](https://python.langchain.com), letting you tokenize PII before it reaches your LLM and restore originals in the response. Includes chain-composable Runnables and a DocumentTransformer for RAG pipelines. ## Installation ```bash theme={null} pip install langchain-blindfold ``` Set your API key: ```bash theme={null} export BLINDFOLD_API_KEY=your-api-key ``` Get a free API key at [app.blindfold.dev](https://app.blindfold.dev). ## Quick Start ### Protect a LangChain Chain ```python theme={null} from langchain_blindfold import blindfold_protect from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI tokenize, detokenize = blindfold_protect(policy="basic") prompt = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant."), ("user", "{input}"), ]) llm = ChatOpenAI(model="gpt-4o-mini") chain = tokenize | prompt | llm | (lambda msg: msg.content) | detokenize # PII is tokenized before the LLM sees it, then restored in the response result = chain.invoke("Write a follow-up email to John Doe at john@example.com") ``` The LLM only sees `` and `` — never the real data. ### Transform Documents for RAG ```python theme={null} from langchain_blindfold import BlindfoldPIITransformer from langchain_core.documents import Document transformer = BlindfoldPIITransformer(pii_method="redact", policy="hipaa_us", region="us") docs = [Document(page_content="Patient John Smith, SSN 123-45-6789")] safe_docs = transformer.transform_documents(docs) # safe_docs[0].page_content → "Patient [REDACTED], SSN [REDACTED]" ``` ## Components ### `blindfold_protect()` Convenience function that returns a paired tokenizer and detokenizer for use in chains: ```python theme={null} tokenize, detokenize = blindfold_protect( api_key=None, # Falls back to BLINDFOLD_API_KEY env var region=None, # "eu" or "us" for data residency policy="basic", # Detection policy entities=None, # Specific entity types to detect score_threshold=None, # Confidence threshold (0.0-1.0) ) ``` ### `BlindfoldTokenizer` A LangChain `Runnable` that tokenizes PII in text and stores the mapping: | Parameter | Type | Default | Description | | ----------------- | ------- | --------- | ----------------------------------------- | | `api_key` | `str` | `None` | Falls back to `BLINDFOLD_API_KEY` env var | | `region` | `str` | `None` | `"eu"` or `"us"` for data residency | | `policy` | `str` | `"basic"` | Detection policy | | `entities` | `list` | `None` | Specific entity types to detect | | `score_threshold` | `float` | `None` | Confidence threshold (0.0–1.0) | ```python theme={null} from langchain_blindfold import BlindfoldTokenizer tokenizer = BlindfoldTokenizer(policy="gdpr_eu", region="eu") safe_text = tokenizer.invoke("Contact Hans at hans@example.de") # → "Contact at " ``` ### `BlindfoldDetokenizer` A LangChain `Runnable` that restores original PII from tokenized text using the paired tokenizer's mapping: ```python theme={null} from langchain_blindfold import BlindfoldTokenizer, BlindfoldDetokenizer tokenizer = BlindfoldTokenizer(api_key="...") detokenizer = BlindfoldDetokenizer(tokenizer=tokenizer) tokenizer.invoke("Hi John") # stores mapping result = detokenizer.invoke("Response to ") # → "Response to John" ``` This is a client-side operation — no API call is made for detokenization. ### `BlindfoldPIITransformer` A LangChain `DocumentTransformer` for protecting PII in documents: | Parameter | Type | Default | Description | | ----------------- | ------- | ------------ | ----------------------------------------- | | `api_key` | `str` | `None` | Falls back to `BLINDFOLD_API_KEY` env var | | `region` | `str` | `None` | `"eu"` or `"us"` for data residency | | `policy` | `str` | `"basic"` | Detection policy | | `pii_method` | `str` | `"tokenize"` | How to protect PII | | `entities` | `list` | `None` | Specific entity types to detect | | `score_threshold` | `float` | `None` | Confidence threshold (0.0–1.0) | When `pii_method="tokenize"`, the mapping is stored in `doc.metadata["blindfold_mapping"]` so you can restore originals later. ### Policies | Policy | Entities | Best For | | ---------- | --------------------------------------------- | ---------------------- | | `basic` | Names, emails, phones, locations | General PII protection | | `gdpr_eu` | EU-specific: IBANs, addresses, dates of birth | GDPR compliance | | `hipaa_us` | PHI: SSNs, MRNs, medical terms | HIPAA compliance | | `pci_dss` | Card numbers, CVVs, expiry dates | PCI DSS compliance | | `strict` | All entity types, lower threshold | Maximum detection | See [Policies](/essentials/policies) for details. ### PII Methods The `pii_method` parameter controls how detected PII is protected (applies to `BlindfoldPIITransformer`): | Method | Output | Reversible | | ------------ | --------------------------------- | -------------- | | `tokenize` | ``, `` | Yes | | `redact` | PII removed entirely | No | | `mask` | `J****oe`, `j****om` | No | | `hash` | `HASH_abc123` | No | | `synthesize` | `Jane Smith`, `jane@example.org` | No | | `encrypt` | AES-256 encrypted value | Yes (with key) | ## Usage Examples ### GDPR Compliance with EU Region ```python theme={null} from langchain_blindfold import blindfold_protect from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI tokenize, detokenize = blindfold_protect(policy="gdpr_eu", region="eu") prompt = ChatPromptTemplate.from_messages([ ("system", "You are a GDPR-compliant assistant."), ("user", "{input}"), ]) llm = ChatOpenAI(model="gpt-4o-mini") chain = tokenize | prompt | llm | (lambda msg: msg.content) | detokenize result = chain.invoke("Contact Hans Mueller at hans.mueller@example.de about IBAN DE89370400440532013000") ``` ### HIPAA — Redact PHI in Documents ```python theme={null} from langchain_blindfold import BlindfoldPIITransformer from langchain_core.documents import Document transformer = BlindfoldPIITransformer( policy="hipaa_us", pii_method="redact", region="us", ) docs = [ Document(page_content="Patient Sarah Jones, SSN 123-45-6789, MRN 4567890"), Document(page_content="Dr. Smith prescribed medication on 2024-01-15"), ] safe_docs = transformer.transform_documents(docs) # PHI redacted from all documents ``` ### Protect RAG Pipeline ```python theme={null} from langchain_blindfold import BlindfoldPIITransformer from langchain_core.documents import Document # Tokenize documents before storing in vector DB transformer = BlindfoldPIITransformer(pii_method="tokenize", policy="strict") docs = [Document(page_content="John Doe's account #12345 has balance $50,000")] safe_docs = transformer.transform_documents(docs) # Mapping stored in metadata for later restoration print(safe_docs[0].metadata["blindfold_mapping"]) # → {"": "John Doe", ...} ``` ### Detect Specific Entity Types ```python theme={null} tokenize, detokenize = blindfold_protect( entities=["Email Address", "Phone Number", "Credit Card Number"], ) ``` ## Data Residency Use the `region` parameter to ensure PII is processed in a specific jurisdiction: | Region | Endpoint | Location | | ------ | ---------------------- | ------------------ | | `eu` | `eu-api.blindfold.dev` | Frankfurt, Germany | | `us` | `us-api.blindfold.dev` | Virginia, US | See [Regions](/essentials/regions) for details. ## Links Install from PyPI Source code and issues LangChain documentation Working integration examples # MCP Server Source: https://docs.blindfold.dev/sdks/mcp-server Blindfold MCP Server for Claude, Cursor, and other AI assistants Add to your MCP config (Claude Desktop, Claude Code, or Cursor): ```json theme={null} { "mcpServers": { "blindfold": { "command": "npx", "args": ["-y", "@blindfold/mcp-server"] } } } ``` No API key needed. 9 tools available: detect, tokenize, detokenize, redact, mask, synthesize, hash, encrypt, discover. All tools, environment variables, setup guides, and examples. # Python SDK Source: https://docs.blindfold.dev/sdks/python-sdk Official Python SDK for Blindfold ```bash theme={null} pip install blindfold-sdk ``` ```python theme={null} from blindfold import Blindfold client = Blindfold() # no API key needed result = client.detect("Email john@acme.com, SSN 123-45-6789") ``` All methods, configuration options, local scanner, batch processing, and examples.