Skip to main content
Lesson 21 of 22 · Responses API: OpenAI Fundamentals

Data Privacy and GDPR

Lesson 21 of 22 Updated July 29, 2026 Developer
On this page
  1. Data Privacy and GDPR
  2. How OpenAI Processes Your Data
  3. Data Minimization
  4. GDPR-Compliant Pipeline
  5. Consent Management
  6. Right to Erasure (Article 17)
  7. GDPR Checklist for Developers
  8. Key Takeaways

Data Privacy and GDPR

As a European developer, you must understand how data flows through the OpenAI API and what steps to take to comply with the GDPR (General Data Protection Regulation). This lesson covers the technical aspects of compliance. It does not replace advice from your Data Protection Officer (DPO), but it gives you the coding practices that will make their job possible—and that, if neglected during design, become extremely costly to fix later.

How OpenAI Processes Your Data

Via the API (not ChatGPT)

Distinguishing API usage from consumer use is the starting point for any discussion on this topic. When you use the OpenAI API for your application, data is not used to train models: this is the API policy, which differs from ChatGPT’s, and it is the argument you will use to address the most common objection in security committees. However, data is retained for 30 days to enable abuse detection, then deleted. You can shorten this retention period: you can request early deletion via the Zero Data Retention feature. One point remains to document in your impact assessment—data transits through OpenAI servers, primarily located in the United States, which constitutes a transfer outside the European Union.

# Check your organization's retention policy
# on platform.openai.com/settings/organization/data-controls

Data Minimization

The GDPR requires processing only strictly necessary data. Apply this principle to your API calls: in the vast majority of cases, the model has no need to know a person’s name, email address, or phone number to summarize their request or classify its subject.

Reversible pseudonymization addresses this need exactly. Before sending, each piece of personal data is replaced with a numbered marker, and the mapping is kept in memory on your server. The API sees only [EMAIL_1] and [TEL_1]. Upon return, the markers are restored in the generated text, and the end user receives a complete response without coordinates ever leaving your system.

import re

def anonymize_before_send(text: str) -> tuple[str, dict]:
    """Anonymizes personal data before sending to the API."""
    replacements = {}
    counter = {"email": 0, "phone": 0, "name": 0}

    # Emails
    def replace_email(match):
        counter["email"] += 1
        key = f"[EMAIL_{counter['email']}]"
        replacements[key] = match.group()
        return key

    text = re.sub(
        r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
        replace_email, text
    )

    # French phone numbers
    def replace_phone(match):
        counter["phone"] += 1
        key = f"[TEL_{counter['phone']}]"
        replacements[key] = match.group()
        return key

    text = re.sub(
        r'\b(?:0|\+33)\s*[1-9](?:[\s.-]*\d{2}){4}\b',
        replace_phone, text
    )

    return text, replacements

def restore_data(text: str, replacements: dict) -> str:
    """Restores data after API processing."""
    for key, value in replacements.items():
        text = text.replace(key, value)
    return text

# Usage
from openai import OpenAI
client = OpenAI()

original_text = "Contact Jean Dupont at [email protected] or 06 12 34 56 78"

# Anonymize
anonymous_text, mapping = anonymize_before_send(original_text)
print(f"Sent to API: {anonymous_text}")
# Sent to API: Contact Jean Dupont at [EMAIL_1] or [TEL_1]

# API call with anonymized data
response = client.responses.create(
    model="gpt-5.6-terra",
    input=f"Summarize this message: {anonymous_text}"
)

# Restore
result = restore_data(response.output_text, mapping)
print(f"Final result: {result}")

Look closely at the output of this example: “Jean Dupont” is still there. The counter includes an entry for name, but no regular expression fills it—detecting a surname requires named entity recognition, not a character pattern. Therefore, consider this function a foundation to build upon, not a complete anonymization solution.

GDPR-Compliant Pipeline

Minimization alone is not enough: the regulation also requires that every processing operation rests on an identified legal basis and is recorded. This pipeline combines both requirements in four steps—record the purpose and legal basis, minimize, call, restore. The user identifier is never stored in plain text but hashed, so the register remains usable for counting operations without itself constituting a file of personal data.

from datetime import datetime
import json
import hashlib

class GDPRCompliantPipeline:
    """GDPR-compliant processing pipeline."""

    def __init__(self):
        self.client = OpenAI()
        self.processing_logs = []

    def process(self, text: str, purpose: str,
                legal_basis: str, user_id: str) -> str:
        """Processes text in compliance with GDPR."""

        # 1. Record the legal basis of processing
        processing = {
            "timestamp": datetime.now().isoformat(),
            "user_hash": hashlib.sha256(user_id.encode()).hexdigest()[:12],
            "purpose": purpose,
            "legal_basis": legal_basis,  # consent, legitimate_interest, contract
        }

        # 2. Minimize data
        anonymous_text, mapping = anonymize_before_send(text)

        # 3. API call
        response = self.client.responses.create(
            model="gpt-5.6-terra",
            input=anonymous_text,
            # Store for the shortest time possible
        )

        processing["tokens_used"] = response.usage.total_tokens
        self.processing_logs.append(processing)

        # 4. Restore and return
        return restore_data(response.output_text, mapping)

    def export_register(self) -> str:
        """Exports the record of processing activities (Article 30 GDPR)."""
        return json.dumps(self.processing_logs, indent=2, ensure_ascii=False)

# Usage
pipeline = GDPRCompliantPipeline()

result = pipeline.process(
    text="Customer Pierre Martin wishes to cancel his subscription.",
    purpose="Cancellation request processing",
    legal_basis="contract",
    user_id="user-456"
)
print(result)
print(pipeline.export_register())

The legal_basis parameter deserves attention: processing a cancellation request falls under contract performance, not consent. Choosing the wrong legal basis is the most frequent and consequential error, as it determines the rights a user can exercise over that processing.

When the chosen legal basis is consent, it must be collected, dated, versioned, and, above all, revocable. The manager below stores consent by purpose—accepting AI assistance does not imply acceptance of text analysis—and verifies this match before every processing operation. The withdrawal method carries a critical comment: deleting the consent record is not enough; you must also delete the data that depended on it.

class ConsentManager:
    """Manages user consent for AI processing."""

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

    def record_consent(self, user_id: str, purposes: list[str]):
        """Records user consent."""
        self.consents[user_id] = {
            "purposes": purposes,
            "date": datetime.now().isoformat(),
            "version": "v1.0"
        }

    def verify_consent(self, user_id: str, purpose: str) -> bool:
        """Checks if the user has consented to a purpose."""
        consent = self.consents.get(user_id)
        if not consent:
            return False
        return purpose in consent["purposes"]

    def withdraw_consent(self, user_id: str):
        """Withdraws consent (right to withdraw)."""
        if user_id in self.consents:
            del self.consents[user_id]
            # Here: also delete associated data

# Usage
consent = ConsentManager()

# User consents to AI processing
consent.record_consent("user-123", ["ai_assistance", "text_analysis"])

# Verify before every processing operation
if consent.verify_consent("user-123", "ai_assistance"):
    # Proceed with processing
    response = client.responses.create(
        model="gpt-5.6-terra",
        input="User question"
    )
else:
    print("Consent required for this processing")

Right to Erasure (Article 17)

When a user requests erasure of their data, your obligation extends beyond the application database. You must sweep all locations: local data, logs containing personal information—often forgotten—and document the operation to justify it. On the API side, the action is already covered by the retention policy: sent data disappears automatically after thirty days, or immediately if Zero Data Retention is enabled.

def exercise_right_to_erasure(user_id: str):
    """Implements the GDPR right to erasure."""

    # 1. Delete local data
    # delete_user_data(user_id)

    # 2. Data sent to the OpenAI API is deleted
    # automatically after 30 days (or immediately
    # with Zero Data Retention enabled)

    # 3. Delete logs containing personal data
    # delete_user_logs(user_id)

    # 4. Document the deletion
    log = {
        "action": "right_to_erasure",
        "user_hash": hashlib.sha256(user_id.encode()).hexdigest()[:12],
        "date": datetime.now().isoformat(),
        "data_deleted": [
            "conversation_history",
            "user_profile",
            "activity_logs"
        ]
    }
    print(json.dumps(log, indent=2, ensure_ascii=False))

exercise_right_to_erasure("user-123")

GDPR Checklist for Developers

  • Identify the legal basis for each processing operation (consent, contract, etc.)
  • Minimize data sent to the API (anonymization)
  • Maintain a record of processing activities (Article 30)
  • Implement the right of access and right to erasure
  • Document transfers outside the EU (OpenAI = US servers)
  • Enable Zero Data Retention if possible
  • Never log personal data in plain text

Key Takeaways

  • The OpenAI API does NOT retrain its models with your data
  • Anonymize personal data before every API call
  • Maintain a record of processing activities compliant with Article 30
  • Implement GDPR rights: access, rectification, erasure, portability
  • Data transfers outside the EU require safeguards (standard contractual clauses)
  • Document every decision regarding data protection