What Gridlinedoes with aspreadsheet.

Upload a CSV or XLSX file and it is checked on arrival, scanned for personal data, held to your rules, cleaned if you ask, versioned and compared row by row, shared with exactly the people you name, open to your questions, and written into an audit log. Every capability below is in the product today.

Start free
01

Check

What is in the file, and does it meet your rules.

A quality report for every upload.

Within seconds of an upload you get row and column counts, empty cells per column, the type each column really holds, and duplicate rows. Optionally, a plain-language summary is written from those statistics. The model never sees your rows.

CSV and XLSX files are profiled. A legacy XLS file is stored, listed and downloadable, but not profiled.

Empty cells per column · inventory-q2.csv (sample)
  • sku

    text

    0.0%
  • name

    text

    1.2%
  • qty

    whole number

    0.0%
  • unit_cost

    number

    12.8%Over
  • region

    text

    3.1%
  • supplier

    text

    0.9%

The tick marks a 5% limit. Sample data, invented for this page.

A scan for personal and secret data.

Each report names the columns that look like email addresses, phone numbers, card numbers, IBANs, IP addresses, birth dates or secret keys (an API key or a private key pasted into a cell). Cards and IBANs must pass their checksum, so an order number is not mistaken for a card.

It is found by patterns, never by an AI, and a value is never shown or sent anywhere. When a file with personal data is open to the whole company, the uploader and your admins are told, and a webhook can tell your own systems. A rule can also fail any file that has it.

customers-export.csv · personal data (sample)
  • emailEmail addresses · 98% of cellsPersonal data
  • mobilePhone numbers · 91% of cellsPersonal data
  • card_on_fileCard numbers · Luhn check passesPersonal data
  • planNothing personalClear

Visible to the whole company. The uploader and your admins are told.

Found by patterns and checksums, never by an AI, and never shown as a value. Sample data, invented for this page.

Your own rules, on every upload.

Require a column, cap empty cells, expect a type, set a minimum or a maximum, demand unique values, limit duplicate rows, or require that a file holds no personal data. Each rule is an error or a warning. An error counts double in the score and raises an alert when it fails.

A rule about a column a file does not have is skipped, not failed, so one company rule set can cover many different files. A report keeps the rules as they were when it ran.

Rules applied to inventory-q2.csv (sample)
  • sku column is presentError · counts doublefoundPass
  • Empty cells in unit_cost, at most 5%Error · counts double12.8%Fail
  • qty holds whole numbersError · counts doubleevery rowPass
  • sku is uniqueWarning · counts once14 repeatedFail
  • No duplicate rowsWarning · counts once0 foundPass

5 of 8 weighted points passed

63 / 100

02

Fix

Correct what the report found, without touching the upload.

Clean a file into its next version.

Pick steps from a short list: trim spaces, remove empty or repeated rows, write dates as YYYY-MM-DD, read text as numbers, replace placeholders such as N/A, fill empty cells, change case, rename or remove a column, and hide personal data (all of it, the last four characters, or a fingerprint you can still count and join on).

Before anything is written, Gridline counts what each step would do across the whole file and shows the first rows that change. The result is the next version, with a report of its own. Your upload is never touched, and a cleaned version does not use your file allowance.

Save the recipe for a file and it is there next month. On Basic and Premium, every new upload can be cleaned automatically, the original kept exactly as it arrived.

customers-export.csv · clean (sample)
  1. 1Trim spaces212 cells
  2. 2Remove repeated rows38 rows
  3. 3Write dates as YYYY-MM-DD1,904 cells
  4. 4Hide the card numbers (last four)1 column
  • joined03 Apr 20262026-04-03
  • name··Ada··Lovelace·Ada Lovelace
  • card_on_file4111 1111 1111 1111•••• 1111

The result is the next version, and your upload is left as it was. Sample data, invented for this page.

03

Compare

What changed between one version and the next.

Every upload is the next version.

A new version of a dataset is compared with the last one from the two stored reports: rows, columns, empty cells, duplicates and the score. A removed or retyped column alerts you and your admins.

Each version has its own report, its own access and its own place in the audit log. Deleting the newest version promotes the one before it.

inventory-q2.csv · version 3 to version 4 (sample)
v3v4uploaded just now
  • Rows8,930 → 8,930 +482
  • Empty cells in unit_cost12.8% → 4.1%
  • Quality score63 → 63
  • Column region removedSchema changed

A removed or retyped column alerts the uploader and your admins. Sample data, invented for this page.

Which rows changed, not just that something did.

The comparison above is about the shape of a file. Choose the column or columns that identify a row, such as a customer number, and two versions are lined up row by row: rows added, removed, changed and unchanged, which columns changed most, and the old and new value of each changed cell.

The first 500 changes are browsable on the page, and Download all changes is a CSV of every one. Save the key and each new version is compared with the one before it as soon as its report is ready: the uploader and your admins are told how many rows were added, removed and changed, and a webhook says it too.

inventory-q2.csv · version 3 to 4, by sku (sample)
Added
120
Removed
3
Changed
57
Unchanged
9,232
  • changedsku BX-1041unit_cost 4.80 5.25
  • addedsku BX-2210qty 400 · unit_cost 12.10
  • removedsku BX-0007qty 12 · unit_cost 3.40

Rows are lined up by the columns you choose. The first 500 changes are browsable and a CSV has every one. Sample data, invented for this page.

04

Ask

Answers from every row, without sending a row anywhere.

Explore a file, or just ask it.

Build a query from plain choices: filter rows, group by up to two columns, and work out a count, total, average, lowest, highest or the number of different values. It is computed by Gridline over every row (up to 100,000), shown as a chart and a table, and downloadable as CSV.

Or type a question in words. The assistant is given your question and the column names and kinds, never a value, and answers with a query that Gridline checks and runs itself. You see the query it chose and can change it. Questions are counted by plan; the builder is free.

sales-2026.csv · ask (sample)

Total revenue by region, highest first

  • Total of revenue
  • Group by region
  • Highest first
  • North412,600
  • South298,150
  • East187,900
  • West96,400

The assistant saw the question and the column names, never a row. Gridline ran the query on every row. Sample data, invented for this page.

05

Control

Who can see it, what was done, and how people talk about it.

Invisible, not forbidden.

A file is open to the whole company or only to the people you name. Everyone else cannot open it and cannot tell it exists: they get a not found, never an access denied.

New versions inherit the access of the file they extend, and changing access takes effect at once, even for someone watching the file live.

Who sees what
Viewing as
  • price-list.csvWhole company
  • payroll-march.csvRestricted
  • q2-targets.csvWhole company

Priya uploaded it, so the restricted file is in the list above.

A record that cannot be edited.

Uploads, access changes, rules, people, keys, plan changes and payments are written to the audit log in the same transaction as the change itself. Admins can filter it and open any entry.

Audit log · today (sample)
  1. 14:02file.uploadedPriya · payroll-march.csv
  2. 14:03file.access_changedPriya · payroll-march.csv
  3. 14:20quality_rule.updatedSam · unit_cost limit
  4. 15:41api_key.createdPriya · finance-export
  5. 16:05employee.invitedPriya · new person

The database rejects any update or delete of this table. There is no way to edit the past.

Talk about the file, where the file is.

Comment on a file and mention a colleague. Only someone who can already see the file can be mentioned, and a mention never grants access. See who else is looking at the file, and get notified in the app when a report is ready, a rule fails, a quota is close or a file is shared with you.

Comments on inventory-q2.csv (sample)
Sam and Priya are looking at this file now
  1. Priya · 14:12

    @Sam unit_cost is empty for 12.8% of rows. Can you check the supplier export?

  2. Sam · 14:19

    Found it: one supplier sent no prices. Uploading a corrected version.

Sam was told about the mention the moment it was posted. Nobody who cannot see the file can be mentioned.

Connect it to the rest of your stack.

The reference is generated from the API itself, so it cannot drift from what the API does.

Scoped API keys
A key acts as the person who made it, never with more than their role or its own scopes.
Signed webhooks
Every delivery carries an HMAC signature over the exact body, so you can verify it came from Gridline.
Live updates
Report status and quota arrive over Socket.IO as they change, with no polling.
Read-only GraphQL
One request for a whole page of files, reports and versions.
An MCP server for agents
An AI agent can list files, read reports, clean, compare versions row by row, and ask a file a question, with the same keys, scopes and limits as the API.
Upload a file
curl -X POST "$GRIDLINE_URL/api/files" \
  -H "Authorization: Bearer $GRIDLINE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@payroll-march.csv"
Ask a file for a total by region
curl -X POST "$GRIDLINE_URL/api/files/$FILE/explore" \
  -H "Authorization: Bearer $GRIDLINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "query": { "groupBy": ["region"],
        "measures": [{ "fn": "sum", "column": "revenue" }] } }'
What your endpoint receives
POST /your/endpoint
webhook-id: 6c1f9e2a-…
webhook-timestamp: 1790000000
webhook-signature: v1=3f8a…

{ "type": "report.ready", … }