Building privacy datasets that stay usable

Privacy teams run on datasets: a tracker of laws and bills, a vendor list, a system inventory, a ROPA, a log of requests. Most of them start as a spreadsheet someone made in a hurry, and most of them become hard to trust within a year. A few habits borrowed from data science keep them usable.

None of this needs special software. It is about structure: what goes in a row, what goes in a column, how values are spelled and where they came from. Get the structure right and a spreadsheet can carry a privacy program a long way. Get it wrong and no tool will rescue it.

Why privacy datasets go bad

The failure pattern is familiar. A law tracker has a "Status" column that contains "Passed", "passed (signed 3/12)", "Enacted", "In effect Jan" and "see notes". A vendor list has a "Data" column with a paragraph of prose per row. A system inventory has merged cells for each department, three tabs that partly duplicate each other, and a column titled "Owner (old)".

Each of these was a reasonable shortcut at the time. Together they mean you cannot filter, sort, count or join anything without reading every cell. And privacy questions are almost always filter-and-join questions: which vendors receive health data and store it outside the EU? Which states have laws in effect this year with a data protection assessment requirement? Which systems lack a retention rule?

Tidy data, applied to privacy work

The statistician Hadley Wickham's paper "Tidy Data" (Journal of Statistical Software, 2014) describes a structure that makes datasets easy to analyze. Its three rules translate directly:

  1. Each variable is a column. "Effective date" and "Enforcement starts" are two variables, so two columns, not one cell with both dates.
  2. Each observation is a row. One row per law, per vendor, per system, per processing activity. Not one row per department with several systems listed in it.
  3. Each type of observational unit is a table. Vendors are one table. Systems are another. Processing activities are a third. Laws, and the obligations within each law, may be separate tables too.

A related, practical paper for spreadsheet users is Broman and Woo, "Data Organization in Spreadsheets" (The American Statistician, 2018). Its advice (be consistent, write dates in one format, don't leave cells empty, put one thing in a cell, make it a rectangle, don't use formatting as data) reads like a list of the ways privacy trackers go wrong.

One fact per column

The single most useful rule. If a cell needs a sentence to explain, it probably holds several facts.

Instead of one columnUse separate columns
Status: "Signed May 2025, effective Jan 1 2026, cure period ends 2027"Stage (enacted); signed date; effective date; cure period end date
Data: "Emails, names, some payment info, maybe health in notes"One yes/no column per data category, or a linked table of system × category
Location: "US (AWS us-east-1), support from Philippines"Storage country; storage region; access countries
Contract: "DPA signed, SCCs pending"DPA status; transfer mechanism; transfer mechanism status

Keep a free-text "Notes" column for context, but never put anything in it that you will need to filter on. If you find yourself searching the notes column, promote that fact to its own column.

Controlled vocabularies

A controlled vocabulary is a fixed list of allowed values for a column. In a spreadsheet, that is a dropdown validated against a list on a separate tab. It is what makes counting and filtering reliable.

  • Data categories: pick a list (contact details, government ID, financial account, precise geolocation, health, biometric, and so on) and stick to it. Map your list to the categories in the laws you care about, such as GDPR special categories or the CCPA's sensitive personal information, in a separate crosswalk table rather than by renaming your categories for each law.
  • Countries: ISO 3166-1 codes (DE, US, BR), not "Germany", "Deutschland" and "DE" in the same column.
  • Dates: ISO 8601 (2026-10-09). It sorts correctly as text and is unambiguous across US and European readers.
  • Legislative stage: introduced, passed one chamber, passed both, enacted, in effect, repealed. Define each in a legend so two people code the same bill the same way.
  • Yes/no fields: actually yes or no, with a separate "unknown" value. A blank should mean "not yet assessed", and the legend should say so.

Vocabularies will need to grow. Add values deliberately, in the list tab, with a note on when and why. Don't let people type new values into the main table.

IDs and relationships

Give every row a stable, meaningless identifier: VEN-0042, SYS-0107, PA-014, LAW-US-MN-2024. Names change; vendors rebrand, systems get replaced, bills get renumbered in a new session. An ID lets other tables refer to the row without breaking.

Once rows have IDs, relationships become explicit. The ROPA's "Systems used" column holds system IDs. The system inventory's "Vendor" column holds a vendor ID. A many-to-many relationship, such as systems and data categories, gets its own small table with one row per pair. This is the structure the ROPA template assumes, and it is what lets a change to one vendor show up everywhere that vendor is used.

Don't reuse IDs for deleted rows. Mark rows as retired with a date instead of deleting them, so history survives and old references still resolve.

Sourcing and versioning

A privacy dataset is only as credible as its sources. For each row, or for each fact that matters, record:

  • Source URL, preferably the primary source: the statute on the legislature's site, the regulator's guidance, the vendor's published sub-processor list, not a blog summary.
  • Date checked. Laws get amended, effective dates get pushed back, vendors add sub-processors. A fact without a "checked on" date is a fact of unknown age.
  • Who checked it, if more than one person maintains the dataset.

For versioning, spreadsheet tools keep revision history, which helps with undoing mistakes but not with answering "what did our vendor list look like at the time of the audit?" For that, take dated snapshots (export to CSV with the date in the filename) at meaningful points: before an audit, at each quarterly review, before a big restructure. If your team is comfortable with it, CSV files in a version control repository give you a full, diffable history.

Spreadsheet or database?

Spreadsheets win early: everyone can open one, they are flexible, and they need no setup. They start to strain when:

  • several people edit at once and overwrite each other's changes;
  • you need real relationships between tables and lookup formulas become fragile;
  • row counts grow into the thousands and filters get slow;
  • you need per-row permissions (some vendor contract details shouldn't be visible to everyone);
  • other systems need to read the data automatically, for example a request tool that needs the system inventory.

The middle ground is a low-code database or a structured table tool with linked records, dropdown fields and form-based entry. The jump after that is either a purpose-built privacy platform for the inventory and ROPA (see the privacy tech stack) or a proper database owned by an engineering or data team. If your data is tidy, any of these migrations is a straightforward import. If it isn't, the migration becomes a cleanup project first.

The personal data piling up in your spreadsheets

Privacy datasets have an awkward property: they tend to accumulate personal data of their own. A request log holds requesters' names, emails and sometimes identity documents. A vendor list holds contacts at each vendor. A system inventory may contain sample records pasted in to show what a table holds. Interview notes from data mapping can name individuals and describe what is known about them.

That data is subject to the same rules as everything else: data minimization and storage limitation under GDPR Article 5(1)(c) and (e), access control, and inclusion in your own map. Practical rules:

  • Never paste real records as examples. Describe fields, not values. Use made-up examples clearly labeled as such.
  • Keep request logs in the request system, not in a shared spreadsheet, and don't store identity documents longer than verification needs. See the DSR working guide.
  • Restrict sharing. "Anyone with the link" is not an access control. Check who can open each privacy dataset.
  • Put the datasets in the inventory. Your privacy tracker is a system that holds personal data. List it.
  • Set retention for request logs and interview notes, and actually delete expired rows.

Security basics for these files are the same as for any other store of personal data; see security controls for personal data.

A starting structure

If you are starting a privacy program's datasets from scratch, this set of tables covers most needs and links cleanly:

TableOne row perKey columns
VendorsVendor (legal entity)Vendor ID, name, role (processor/controller), DPA status, sub-processor list URL, last reviewed
SystemsSystem or applicationSystem ID, vendor ID (or internal), business owner, technical owner, storage country, identifiers used, request method
System × data categoryPairSystem ID, category (from vocabulary), source of finding (interview, scan), date
Processing activitiesActivityActivity ID, purpose, legal basis, data subjects, retention rule, owner
Activity × systemPairActivity ID, system ID
LawsLaw or billLaw ID, jurisdiction code, stage, enacted date, effective date, source URL, checked on
VocabulariesAllowed valueList name, value, definition, added on

From these you can produce the ROPA, the inventory view, vendor review queues and a jurisdiction checklist as filtered views, without maintaining any of them separately. The data mapping guide covers how to populate the system tables, and the calculator estimates how long it will take by hand. For the jurisdiction side, the privacy regulators directory is a useful starting list.