Choose the least detailed useful input
Write down the question before opening the source file. “How many refund, login, and delivery issues occurred?” needs two output columns: issue and count. “Did one customer contact us twice?” needs a consistent subject token across those rows, but it does not need that person's name, email, city, order number, or note. If the task needs note wording, check every note before sharing it.
| Task | Candidate input for ChatGPT | Decision before sharing |
|---|---|---|
| Explain a formula or plan an analysis | Column names and synthetic example rows | Use no real records if the task can be answered from the schema. |
| Summarize issue counts | issue,count | Review small or rare categories; a count of one can still disclose information in context. |
| Group repeat contacts | subject_id,issue | Keep the raw-to-token relationship outside the submission and check whether the token can be joined to another export. |
| Read case notes by region | A redacted note, issue, and broad region only if each is needed | Free text and combinations of fields may identify someone even when known names are gone. |
Before you work with real records, confirm who owns the data, what you may do with it, and which ChatGPT workspace, if any, your organization permits. The sensitive-data preflight walks through that decision. ChatGPT settings do not grant permission to share a file. OpenAI's data-use guidance distinguishes individual services from managed business offerings, so check the workspace you actually use.
The UK Information Commissioner's Office says pseudonymized personal data remains in scope of data protection law. NIST treats de-identification as risk reduction that depends on the intended use and sharing model. Masking a few fields does not establish that real data is anonymous; that conclusion needs a context-specific assessment of identification risk. NIST SP 800-188 explains the choices.
Run the four-row practice example locally
Download the example CSV and the practice kit. They contain the same four fictional support records: three invented customers, three cities, fake order codes, and notes with sample emails or phone numbers. The script recognizes only this example's columns and formats. It rejects another file instead of pretending that an unfamiliar file passed its checks.
Unzip the kit, open a terminal in its directory, and run:
python3 sanitize.py
python3 -m unittest test_sanitize.py
The first command writes results/aggregated-issues.csv, results/repeat-subject-issues.csv, results/regional-note-review.csv, and results/audit.json. The second command checks the expected four-row outputs and plants a customer name in a note to verify that a known-value leak stops the script before it writes any output. Run it in a fresh extracted directory; the script refuses to overwrite a nonempty results directory.
For counts, use the aggregate
The aggregate output contains exactly three rows and no subject token, region, or note:
issue,count
delivery,1
login,1
refund,2
If the question ends at issue totals, this is the only output the example needs. Do not send the source CSV just because ChatGPT could count it. A real aggregate still needs a disclosure check: a unique category, tiny team, or publicly known event could make a count informative about one person. Combine, suppress, or keep such groups inside the approved environment when the context requires it. This fixture does not determine a universal safe group size.
For repeat contacts, keep a minimal token
The repeat-subject file has four rows with only subject_id and issue:
subject_id,issue
CUST-001,refund
CUST-002,login
CUST-001,delivery
CUST-003,refund
CUST-001 appears once for refund and once for delivery, so you can see the repeated contact without seeing the fictional customer's email. The script uses that email only on your computer to group the example rows. Real records may have shared addresses, changed addresses, or duplicate names; check that the chosen key really groups the right person before producing an extract.
The numbered CUST-001 token makes the lesson easy to follow; it is not a token design for a real release. Generate unpredictable tokens for each permitted task, keep their mapping outside the file you share, and do not reuse them across unrelated exports. If counts answer the question, leave tokens out entirely.
Keep notes only when the task actually needs them
The third file shows what happens when the question really needs note wording. It keeps a broad region, issue, customer token, and redacted note. One example row becomes CUST-001,Northeast,refund,Email [REDACTED_EMAIL] about order CASE-001. This is a file to inspect, not the default file to send. Use the smaller repeat-contact file when notes and regions are unnecessary.

Check what the script catches, then inspect what it cannot
The script checks all three output files for the names, emails, phone numbers, and order codes in the example source. It also scans for the expected email, phone, and order formats, then checks the row and issue counts. In this four-row run, those checks found no known raw identifier. The included failure test puts “Avery Stone” back into a note; the script stops before writing any output.
Passing those checks is narrow. A note such as “the only night-shift manager at the small Seattle office” may identify someone without matching any name, email, phone, or order pattern. Read every note you plan to keep. Look for exact dates, addresses, handles, signatures, quotations, unusual events, and combinations of region and issue that point to one person. Remove an unnecessary detail, generalize it when the task permits, or keep the file local when the meaning cannot be preserved without it.
Compare tokens across every extract that might be shared with the same recipient. Check source filenames and, for actual workbooks, documents, images, or archives, inspect hidden sheets, comments, revisions, embedded objects, and metadata before upload. The artifact checklist covers the container inspection that a pasted CSV test cannot exercise. Do not ask ChatGPT to inspect a file you have not already cleared for that workspace.
Adapt the decisions to a real CSV
Start with the question and a list of source columns, not by changing the example script until it accepts your file. Suppose your support export has customer_name,email,phone,city,issue,note,created_at. Make a local working copy, then write down the exact columns you want in the result:
| Source field | If you only need issue counts | If you need repeat-contact analysis |
|---|---|---|
customer_name, phone | Leave out. | Leave out. |
email | Leave out. | Use locally to group rows only after checking shared or changed addresses; emit a new random token, never the email. |
city, created_at | Leave out unless the question needs a place or time trend. | Leave out by default. If a broad region or month is needed, check whether its combination with the issue singles someone out. |
issue | Count by issue; inspect rare categories before sharing totals. | Keep only if the analysis needs it; review unusual categories. |
note | Leave out. | Leave out unless you are studying wording. Then remove direct identifiers and read every remaining note for indirect clues. |
For a repeat-contact file, keep one random token per person within this task. Python's secrets.token_urlsafe(16) can generate one; a local mapping gives the same person the same token on their other rows. Keep that mapping out of the export. A random token still lets the recipient connect rows within the file, so call the result pseudonymized, not anonymous. After checking that your source has a reliable grouping key, this is the token step:
import secrets
tokens = {} # Keep this mapping local; do not export it.
def subject_token(customer_key):
if customer_key not in tokens:
tokens[customer_key] = secrets.token_urlsafe(16)
return tokens[customer_key]
Next, build checks for your source: verify the input columns and missing values, allow only the output columns you chose, search for known source identifiers and formats, and plant a sample leak to confirm the process stops. Compare row counts and category totals with the source. Inspect every retained note and small group yourself. If a date is needed for a monthly trend, test whether a month is enough; an exact timestamp can reveal far more. If the answer cannot be preserved without a unique personal detail, keep that analysis in the permitted local environment.
The download does not perform this adaptation for you. A different file might fail its four-row checks, or coincidentally pass them without being safe. A real release needs a review of the actual records, what else the recipient might know, and your organization's rules.
Use ChatGPT only after the local decision
If the data owner permits the specific ChatGPT workspace and an issue-count table answers the question, paste only that reviewed table. If individual rows are truly needed, use the smallest reviewed extract. You can ask ChatGPT to recalculate counts and flag details that might reconnect rows to people. Its response is a second look, not permission to share the data or proof that it is anonymous. It cannot see the source file, metadata, or other exports you did not provide.
Use only the rows below. Recalculate the row and issue counts.
List any stable IDs, locations, rare categories, or text that could
still link rows to a person. Do not describe the extract as anonymous.
If a field needs human review, name the field and why. Do not infer
anything about the original records or files that I did not provide.
In the example below, we pasted only the fictional regional-note file. ChatGPT got the counts right and pointed to customer tokens, case tokens, regions, and notes that could reconnect records to people. It did not inspect a real dataset or find every possible clue.

Decide what can leave the local workspace
- Confirm the purpose, owner, receiving tool, and permitted data type. If any is unresolved, stop.
- Select the smallest output that answers the question. Counts do not need the row-level files.
- Run checks written for the actual source. Read every retained note, examine rare groups, and inspect the full file for hidden content.
- Have the responsible owner approve any real-data release. Record which file was approved and keep raw records and token mappings outside the submission.
- After ChatGPT responds, verify its counts against the local output and remove any new claim that the data is anonymous unless a qualified, contextual assessment supports it.
Disclosure: The downloadable kit contains fictional data. We ran it locally with Python 3.13.2 on September 28, 2026; two tests covered the four-row example and one planted name leak. The ChatGPT screenshot shows a separate August 19, 2026 run using the same fictional regional-note file. Neither test evaluates real records, unusual identifier formats, outside knowledge, or whether a real dataset is legally anonymous.
