OP

openrouter-data-privacy

Provides PII detection and redaction tools for OpenRouter API interactions to protect sensitive data.

Install

mkdir -p .claude/skills/openrouter-data-privacy && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/9367" && unzip -o skill.zip -d .claude/skills/openrouter-data-privacy && rm skill.zip

Installs to .claude/skills/openrouter-data-privacy

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Implement data privacy controls for OpenRouter API usage. Use when handling
75 chars✓ has a “when” trigger
Intermediate

Key capabilities

  • Detect PII types like email, phone, SSN, credit card, API keys, and IP addresses
  • Redact PII from text and replace it with generic placeholders
  • Anonymize PII with unique placeholders for later deanonymization
  • Route workloads to specific OpenRouter providers based on sensitivity
  • Hash logged prompts using SHA-256 for GDPR compliance

How it works

The skill scans input text against predefined regex patterns for PII, then redacts identified sensitive information or replaces it with unique placeholders.

Inputs & outputs

You give it
Text string containing potential PII, like 'Contact [email protected]'
You get back
Redacted text, PII scan findings, and a boolean indicating PII presence

When to use openrouter-data-privacy

  • Redact PII from prompts before API calls
  • Implement GDPR-compliant data handling for LLM workloads
  • Classify sensitivity of API request workloads

About this skill

OpenRouter Data Privacy

Overview

When sending data through OpenRouter to upstream LLM providers, you're responsible for ensuring prompts don't leak PII inappropriately. OpenRouter itself does not train on API data, but each upstream provider has its own data retention and training policies. This skill covers PII detection and redaction, placeholder substitution, provider selection for privacy, and consent tracking.

Prerequisites

  • An OpenRouter API key (sk-or-v1-...) exported as OPENROUTER_API_KEY — see the openrouter-install-auth skill for setup
  • Python 3.8+ with the OpenAI SDK (pip install openai) — every pattern in this skill is Python
  • A sensitivity classification for your workloads (public / standard / sensitive) so privacy_aware_completion() can route each one
  • A list of providers your org approves for sensitive data, to plug into provider.order with allow_fallbacks: False

Instructions

  1. Start with PII Detection and Redaction: adapt PII_RULES (email, phone, SSN, credit card, sk-or-v1- API keys, IPs) to your data, then run scan_and_redact() on representative inputs and review the findings for false positives.
  2. When downstream code needs the original values back, use the Placeholder Substitution Pattern instead of plain redaction — PrivacyProxy.anonymize() before the API call, deanonymize() on the model's reply.
  3. Classify each workload and route it via Provider Selection for Privacy: privacy_aware_completion() maps sensitivity to a model plus a provider block (order: ["Anthropic"], allow_fallbacks: False for standard/sensitive).
  4. Wire the Privacy Middleware into every call path, choosing block_on_pii=True (raise on detection) or auto_redact=True (scrub and continue) per workload.
  5. Apply the Enterprise Considerations: hash logged prompts (SHA-256) for GDPR right-to-erasure, and use BYOK for the most sensitive workloads.

PII Detection and Redaction

import re
from dataclasses import dataclass
from typing import Optional

@dataclass
class PiiScanResult:
    clean_text: str
    findings: list[dict]
    has_pii: bool

PII_RULES = [
    ("email", r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'),
    ("phone", r'\b(?:\+1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b'),
    ("ssn", r'\b\d{3}-\d{2}-\d{4}\b'),
    ("credit_card", r'\b(?:\d{4}[- ]?){3}\d{4}\b'),
    ("api_key", r'\bsk-or-v1-[a-zA-Z0-9]+\b'),
    ("ip_address", r'\b(?:\d{1,3}\.){3}\d{1,3}\b'),
]

REPLACEMENTS = {
    "email": "[EMAIL]", "phone": "[PHONE]", "ssn": "[SSN]",
    "credit_card": "[CARD]", "api_key": "[API_KEY]", "ip_address": "[IP]",
}

def scan_and_redact(text: str) -> PiiScanResult:
    """Scan text for PII and return redacted version with findings."""
    findings = []
    clean = text
    for pii_type, pattern in PII_RULES:
        matches = re.findall(pattern, clean)
        for match in matches:
            findings.append({"type": pii_type, "value_prefix": match[:4] + "..."})
        clean = re.sub(pattern, REPLACEMENTS[pii_type], clean)

    return PiiScanResult(clean_text=clean, findings=findings, has_pii=len(findings) > 0)

Placeholder Substitution Pattern

import os, uuid
from openai import OpenAI

client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key=os.environ["OPENROUTER_API_KEY"],
    default_headers={"HTTP-Referer": "https://my-app.com", "X-Title": "my-app"},
)

class PrivacyProxy:
    """Replace PII with placeholders before API, restore after."""

    def __init__(self):
        self._map: dict[str, str] = {}

    def anonymize(self, text: str) -> str:
        """Replace PII with unique placeholders."""
        result = scan_and_redact(text)
        if not result.has_pii:
            return text

        # Use deterministic placeholders for consistent replacement
        anonymized = text
        for pii_type, pattern in PII_RULES:
            for match in re.finditer(pattern, anonymized):
                original = match.group()
                if original not in self._map:
                    placeholder = f"[{pii_type.upper()}_{len(self._map)}]"
                    self._map[placeholder] = original
                else:
                    placeholder = next(k for k, v in self._map.items() if v == original)
                anonymized = anonymized.replace(original, placeholder, 1)
        return anonymized

    def deanonymize(self, text: str) -> str:
        """Restore original values from placeholders."""
        result = text
        for placeholder, original in self._map.items():
            result = result.replace(placeholder, original)
        return result

# Usage
proxy = PrivacyProxy()
user_input = "Contact [email protected] or call 555-123-4567"
safe_input = proxy.anonymize(user_input)
# safe_input = "Contact [EMAIL_0] or call [PHONE_1]"

response = client.chat.completions.create(
    model="anthropic/claude-3.5-sonnet",
    messages=[{"role": "user", "content": safe_input}],
    max_tokens=200,
)
# Restore PII in the response if model referenced it
result = proxy.deanonymize(response.choices[0].message.content)

Provider Selection for Privacy

# Force specific provider to control data handling
def privacy_aware_completion(messages, sensitivity="standard"):
    """Route to appropriate provider based on data sensitivity."""

    PRIVACY_CONFIG = {
        "public": {
            "model": "openai/gpt-4o-mini",
            "provider": None,  # Any provider OK
        },
        "standard": {
            "model": "anthropic/claude-3.5-sonnet",
            "provider": {"order": ["Anthropic"], "allow_fallbacks": False},
        },
        "sensitive": {
            "model": "anthropic/claude-3.5-sonnet",
            "provider": {"order": ["Anthropic"], "allow_fallbacks": False},
            # Add PII redaction as mandatory pre-processing
        },
    }

    config = PRIVACY_CONFIG.get(sensitivity, PRIVACY_CONFIG["standard"])
    extra = {}
    if config["provider"]:
        extra["extra_body"] = {"provider": config["provider"]}

    return client.chat.completions.create(
        model=config["model"],
        messages=messages,
        max_tokens=1024,
        **extra,
    )

Privacy Middleware

class PrivacyMiddleware:
    """Enforce privacy policies before every API call."""

    def __init__(self, block_on_pii: bool = False, auto_redact: bool = True):
        self.block_on_pii = block_on_pii
        self.auto_redact = auto_redact

    def process(self, messages: list[dict]) -> list[dict]:
        """Scan and optionally redact PII from all messages."""
        processed = []
        for msg in messages:
            content = msg.get("content", "")
            if isinstance(content, str):
                result = scan_and_redact(content)
                if result.has_pii:
                    if self.block_on_pii:
                        raise ValueError(f"PII detected: {[f['type'] for f in result.findings]}")
                    if self.auto_redact:
                        msg = {**msg, "content": result.clean_text}
            processed.append(msg)
        return processed

Output

The privacy flows in this skill produce:

  • A PiiScanResult per scan: clean_text with placeholders substituted, findings (PII type + first-4-chars value prefix per match), and a has_pii flag
  • Anonymized prompts like "Contact [EMAIL_0] or call [PHONE_1]" plus the placeholder→original map that deanonymize() uses to restore values in the response
  • Chat completions served only by approved providers when the provider.order + allow_fallbacks: False config is applied
  • A ValueError listing the detected PII types when PrivacyMiddleware runs with block_on_pii=True

Examples

Scanning a support message before it leaves your infrastructure:

result = scan_and_redact("Contact [email protected] or call 555-123-4567")
print(result.clean_text)  # Contact [EMAIL] or call [PHONE]
print(result.has_pii)     # True
print(result.findings)    # [{'type': 'email', 'value_prefix': 'john...'}, {'type': 'phone', ...}]

To keep the values recoverable, run the same input through PrivacyProxy.anonymize() instead, send the placeholder version to the model, then deanonymize() the reply. More worked examples: references/examples.md.

Error Handling

ErrorCauseFix
PII detected in promptUser input contains sensitive dataAuto-redact or block and prompt user to remove
Provider retained dataUsing provider with training-on-API-dataSwitch to Anthropic or use BYOK
Placeholder in responseModel used placeholder literallyMap it back with deanonymize()
False positive PII matchRegex too aggressiveTune patterns; use NLP-based PII detection for accuracy

Enterprise Considerations

  • OpenRouter does not train on API data; check each upstream provider's data use policy separately
  • Use provider.order + allow_fallbacks: false to ensure data only flows to approved providers
  • Implement PII redaction as middleware that runs on every request, not optional per-call
  • For GDPR right-to-erasure: don't log raw prompts -- hash them (SHA-256)
  • Use BYOK for sensitive workloads so data flows directly to the provider under your account
  • Build a data classification system that auto-routes based on sensitivity level

References

When not to use it

  • When the downstream code needs original PII values and placeholder substitution is not used
  • When an OpenRouter provider's data use policy is not checked
  • When the task requires PII detection beyond the defined `PII_RULES`

Prerequisites

An OpenRouter API key exported as OPENROUTER_API_KEYPython 3.8+ with the OpenAI SDKA sensitivity classification for workloads (public, standard, sensitive)A list of providers approved for sensitive data

Limitations

  • The skill's PII detection relies on predefined regex patterns, which may lead to false positives or negatives.
  • The skill does not train on API data, but upstream providers may have their own data retention policies.
  • The skill does not automatically validate the data use policies of upstream providers.

How it compares

This skill automates PII detection and redaction before sending data to OpenRouter, unlike manual review or direct API submission.

Compared to similar skills

openrouter-data-privacy side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
openrouter-data-privacy (this skill)027dReviewIntermediate
desktop-mac-mcp-host03moReviewIntermediate
prompt-guard16moReviewIntermediate
sandboxing-security05moReviewAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

More by jeremylongshore

View all by jeremylongshore

analyzing-logs

jeremylongshore

Analyze application logs to detect performance issues, identify error patterns, and improve stability by extracting key insights.

14123

ollama-setup

jeremylongshore

Configure auto-configure Ollama when user needs local LLM deployment, free AI alternatives, or wants to eliminate hosted API costs. Trigger phrases: "install ollama", "local AI", "free LLM", "self-hosted AI", "replace OpenAI", "no API costs". Use when appropriate context detected. Trigger with relevant phrases based on skill purpose.

1167

backtesting-trading-strategies

jeremylongshore

Backtest crypto and traditional trading strategies against historical data. Calculates performance metrics (Sharpe, Sortino, max drawdown), generates equity curves, and optimizes strategy parameters. Use when user wants to test a trading strategy, validate signals, or compare approaches. Trigger with phrases like "backtest strategy", "test trading strategy", "historical performance", "simulate trades", "optimize parameters", or "validate signals".

1071

generating-database-seed-data

jeremylongshore

Process this skill enables AI assistant to generate realistic test data and database seed scripts for development and testing environments. it uses faker libraries to create realistic data, maintains relational integrity, and allows configurable data volumes. u... Use when working with databases or data models. Trigger with phrases like 'database', 'query', or 'schema'.

1033

cursor-codebase-indexing

jeremylongshore

Execute set up and optimize Cursor codebase indexing. Triggers on "cursor index setup", "codebase indexing", "index codebase", "cursor semantic search". Use when working with cursor codebase indexing functionality. Trigger with phrases like "cursor codebase indexing", "cursor indexing", "cursor".

885

testing-mobile-apps

jeremylongshore

Execute mobile app testing on iOS and Android devices/simulators. Use when performing specialized testing. Trigger with phrases like "test mobile app", "run iOS tests", or "validate Android functionality".

810

You might also like

desktop-mac-mcp-host

hushh-labs

Use when implementing or reviewing the local MCP HTTP/SSE host on the Mac, the OpenClaw DataSourceBinding interface, CRT/DAT minting, or the OpenClaw conformance test harness inside the desktop-mac owner family.

00

prompt-guard

Orchestra-Research

Meta's 86M prompt injection and jailbreak detector. Filters malicious prompts and third-party data for LLM apps. 99%+ TPR, <1% FPR. Fast (<2ms GPU). Multilingual (8 languages). Deploy with HuggingFace or batch processing for RAG security.

13

sandboxing-security

gitwalter

Input validation and sanitization, output filtering, code execution

00

mcp-builder

anthropics

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

136215

copilot-sdk

github

Build agentic applications with GitHub Copilot SDK. Use when embedding AI agents in apps, creating custom tools, implementing streaming responses, managing sessions, connecting to MCP servers, or creating custom agents. Triggers on Copilot SDK, GitHub SDK, agentic app, embed Copilot, programmable agent, MCP server, custom agent.

763

openrouter-function-calling

jeremylongshore

Implement function/tool calling with OpenRouter models. Use when building agents or structured outputs. Trigger with phrases like 'openrouter functions', 'openrouter tools', 'openrouter agent', 'function calling'.

539

Search skills

Search the agent skills registry