Most CSV diff tools stop at "here are the rows that changed". That covers maybe a third of what you actually want when you open two files side by side. The other two-thirds — focusing on the columns that matter, matching rows by ID instead of position, picking which side wins for a merged export, getting a plain-English summary of what changed — usually require a script, a spreadsheet wizard, or a paid SaaS. csvdiff.app pulls all of it into one browser tab. This post walks through the features in the order you tend to reach for them.
Row-level Diff with Status Pills
Drop two files in and the first thing you see is a unified diff table. Each row is tagged Modified, Added, Removed, or Unchanged, and changed cells highlight the old value next to the new value inline. No squinting between two windows.
| Status | id | name | role | status |
|---|---|---|---|---|
| Modified | 102 | Sara Ahmed | Engineer→Senior Engineer | active |
| Added | 201 | David Miller | Designer | active |
| Removed | 088 | Layla Hassan | Engineer | inactive |
Match Keys — Diff by ID, Not Row Position
Two exports of the same dataset will almost never come back in the same order. A positional diff treats every reordered row as a change, which is noise. Pick a match key column (id, email, sku, order_number) and csvdiff.app pairs rows across files by that key first, then computes cell-level diffs only on the genuine differences. Same export reordered? Zero changes. One row deleted, one added, three modified? You see exactly that, no false positives.
A good match key is unique and stable across both files. If your data has no single-column key, you can still diff positionally — but the match key is what makes the diff trustworthy on real-world exports.
Column-Level Filters — Hide What You Don't Care About
A wide CSV is harder to read than a tall one. The Columns menu lets you toggle individual columns on and off, with a search box for files that have dozens of headers. There's also an "Only changed" switch that hides every column where the two files agree on every row — leaving just the columns where something actually moved. On a 40-column export with three differing columns, this turns 40 columns of scrolling into 3 columns of focus.
- idall equal
- nameall equal
- role
- salary
- departmentall equal
- managerall equal
- status
- created_atall equal
- updated_atall equal
| role | salary | status |
|---|---|---|
Sort, Pin, and Filter by Column
Every column header is a control surface. Click the header text to sort that column ascending, click again for descending, click a third time to clear. Click the pin icon to lock a column to the left edge of the scroll area — useful when you have an ID or name column you always want visible while you scroll horizontally through 30 other fields. And click the filter icon to open a value picker: a checklist of every distinct value in that column, with counts. Tick the values you want to keep and the table narrows to just rows where that column matches. Sort, pin, and value filters all stack — sort by salary descending, pin "name", filter "department" to just Engineering and Design, and you have a focused view in four clicks.
id | name | department⚲ 2 | salary▼ | status |
|---|---|---|---|---|
Pinned columns stay anchored to the left while everything else scrolls. Combined with column visibility and value filters, you can shape a 50-column export into a 5-column working view without touching a spreadsheet.
Status Filters — Modified, Added, Removed
Above the table, six pills (Changes only, All rows, Unchanged, Modified, Added, Removed) act as a single-click filter on row status. "Changes only" is the default and usually what you want — it hides every Unchanged row so the table is just the deltas. Toggle Modified to audit edits, Added to review new records, Removed to confirm deletions.
One click to slice the diff. Filters compose with column visibility and search.
Search — Cross-Cell, Across Both Files
Press / and a search input takes focus. The query runs across every visible cell in both files at once, including row numbers — useful for tracking down a specific record by name, ID, or any value. The match count updates as you type, and the search composes with the column visibility and status filters so you can narrow first and search within the narrowed set.
| id | name | role | department |
|---|---|---|---|
| 102 | Sara Ahmed | Senior Engineer | Platform |
| 145 | Sara Khan | Designer | Brand |
| 188 | Sarah Lee | Data Analyst | Insights |
View Modes — Diff, File A, File B
Sometimes a diff isn't what you need. The view switcher flips the same table between three modes: Diff (the unified comparison), File A (just file A as a viewer), and File B (just file B as a viewer). Same column visibility, same search, same sort — you don't lose your place when you switch contexts.
Resolve and Merge — Pick a Winner per Cell
Diffing is half the job; the other half is producing a single merged file. On every changed cell, click A or B to pick which side wins for the export. Row-level controls let you keep or drop entire Added/Removed rows. Bulk actions handle the common cases — "keep all from A", "keep all from B", "accept everything as new". The export honors every choice you made.
| ID | role | salary | status |
|---|---|---|---|
| 102 | AEngineerBSenior Engineer | A95,000B110,000 | active |
| 145 | Designer | 78,000 | AactiveBarchived |
Export — CSV or JSON
When you're happy with the resolutions, the footer has Download CSV and Download JSON buttons. The export uses your current filter and column visibility, so you can ship either the full merged dataset or just the changes-only slice. Everything is generated in the browser — the file goes straight from memory to your disk.
84 rows · 9 columns · generated client-side
AI Summary — Plain-English Diff
For files where you need to communicate what changed (a stakeholder, a PR description, a release note), the AI Summary popover ships the diff to your configured LLM and gets back a structured paragraph: counts by status, a few representative examples, and patterns it noticed (e.g. "all status changes were active → archived"). You bring your own API key — it never touches our server.
- Six employees received role and salary updates, all in the Platform department.
- Four new hires were added across Engineering and Design.
- Two records were removed — both had status set to "inactive" in file A.
Privacy — 100% Client-Side
Every feature above runs in your browser. The CSV parser, the diff algorithm, the merge logic, the export — none of it makes a network request with your data. The only optional exception is the AI summary, which uses a key you supply and goes directly to your chosen provider. For regulated data (PII, finance, health), this is usually the deciding factor.
Putting It All Together
A typical session: drop two CSVs, pick a match key, switch to "Only changed columns", filter to Modified rows, search for the customer ID a teammate flagged, click B for the cells where the new values are correct, hit Download CSV. Three minutes, no scripts, no spreadsheet macros, no data leaving the tab. That's the tool — built for the thing you actually do, not the thing the demo shows.