Learn how to find duplicates in Google Sheets with 6 powerful methods. Covers conditional formatting, formulas, pivot tables, & scripts to clean your data.

You open a lead list to prep an outreach campaign, sort by email, and spot the same contact twice. Then you notice the same company appears under two slightly different names. Then a rep points out a lead already got the same follow-up last week. What looked like a quick spreadsheet check has turned into a trust problem.
That is why learning how to find duplicates in google sheets matters. Duplicate rows do not just make a sheet look messy. They distort reports, create avoidable follow-ups, and force teams to waste time checking whether a record is real, repeated, or just entered differently.
Most duplicate problems start small. A CSV gets imported twice. A teammate copies rows from one tab into another. A Google Form submission lands next to older manual entries. On the surface, it feels like housekeeping. In practice, it affects decisions.
A sales team might overcount leads. A project manager might assign the same task twice because a shared list pulled from two tabs contains matching rows. A client list might trigger duplicate messages because nobody caught repeated contacts before a mail merge.
The direct problem is obvious. The hidden problem is confidence.
Once people suspect the sheet contains duplicates, they stop trusting totals, filters, and summaries. They start checking the same data manually, often row by row. That slows down handoffs and creates side conversations like “which row is the correct one?” or “did we already contact this person?”
For teams that work inside Google Workspace all day, this becomes a workflow issue, not just a spreadsheet issue. Shared task lists, CRM exports, and cross-functional trackers all depend on one thing: a record should mean one thing, one time.
The most effective teams do not treat deduplication as random cleanup. They treat it as part of a broader data quality framework. That mindset changes the goal from “delete messy rows” to “protect reporting, communication, and handoffs.”
Practical rule: Do not pick a method until you answer one question first. Do you want to delete duplicates, review them, or monitor them over time?
Google Sheets gives you a full spectrum of options. Some are fast and destructive. Some are safer and reversible. Some are formula-driven and ideal for live datasets. Some are strong enough for multi-sheet operations where one tab is no longer the whole story.
The mistake is not choosing the wrong formula. The mistake is using a destructive method when the sheet still contains history you may need later.
A sales coordinator imports a lead list, spots repeated contacts, and wants them gone before the next handoff. A project team working from a shared tracker has the opposite problem. They need to see possible duplicates without deleting history that someone still depends on.
That is the decision to make first. Use a destructive method for throwaway data. Use a non-destructive method for live operational sheets.

The built-in command lives under Data > Data cleanup > Remove duplicates. It is fast, simple, and good for cleanup tabs that exist only to prepare data for the next step.
Use it when the source can be recreated and the duplicate rule is already clear:
Avoid it in active CRMs, shared task lists, and client logs. In those sheets, deleting a row also deletes context. Notes, status changes, timestamps, and ownership history often matter as much as the duplicate itself.
Conditional formatting is the safer review method. It marks suspect records and leaves the original data in place, which is usually the right call when several people edit the same sheet.
A simple single-column rule works for basic lists. For duplicate detection across several columns, the stronger approach is a custom COUNTIFS rule.
To check whether rows in A2:D1000 are duplicates across all four columns:
=COUNTIFS($A$2:$A,$A2,$B$2:$B,$B2,$C$2:$C,$C2,$D$2:$D,$D2)>1
This rule highlights rows only when all selected fields match. That is the standard I use for operational data, because a true duplicate in business sheets usually depends on a combination of fields, not one value alone. In a CRM, email plus company may matter more than name alone. In a task tracker, title, assignee, date, and status often define whether two rows are duplicated or just similar.
Visual review sounds slower, but it prevents expensive mistakes.
| Method | Best for | Risk |
|---|---|---|
| Remove duplicates | One-time cleanup on replaceable data | Deletes rows immediately |
| Conditional formatting | Shared sheets and review workflows | Can flag the wrong records if the range or formula is set up poorly |
The setup details matter. Exact-match rules will treat Acme Inc, ACME INC, and Acme Inc as different values. If your team has inconsistent data entry, clean the inputs first or build that normalization into a later formula-based process.
Conditional formatting also has a maintenance cost. Each rule recalculates as people edit the sheet, so performance can drop in larger trackers with many formatting rules. I see this often in collaborative boards where teams keep adding visual logic instead of simplifying the process.
For teams running work from Sheets, a better pattern is to highlight duplicates, review them in context, and only then remove or merge records through a controlled workflow. That approach fits especially well with a Google Sheets Kanban workflow, where the sheet is not just storage. It is the system people use to decide what happens next.
Tip: If only part of a duplicate row gets highlighted, check Apply to range before changing the formula. Misaligned ranges cause more problems than the rule itself.
A common failure point looks like this. A sales coordinator imports new leads into a shared sheet, someone else sorts by owner, and a third person updates notes on what turns out to be the second copy of the same record. The duplicate is no longer just messy data. It creates rework, conflicting edits, and bad handoffs.
Formula-based detection helps because it separates two decisions that teams often mix together. First, identify possible duplicates. Second, decide what to keep, merge, or remove. That non-destructive approach is usually the right call in live sheets where people are still working.

Use UNIQUE when you need a clean output without touching the source range:
=UNIQUE(A2:A)
This works well for review tabs, import staging areas, and approval flows. The original data stays intact, which matters if the sheet is tied to an active process and not just an archive.
I use this method first when the business risk of deleting the wrong row is higher than the annoyance of reviewing extra records. That is common in shared task lists, lead trackers, and operations logs, where one "duplicate" may contain the latest comment, status, or assignee change.
A unique list is useful, but it does not answer the question teams usually ask next: which rows need attention right now?
For a row-by-row flag in column E, use:
=COUNTIF($A$2:$A,A2)>1
That returns TRUE or FALSE depending on whether the value in column A appears more than once. It is simple, readable, and easy to audit. If your team inherits the sheet later, that matters.
For duplicate rows across several columns, combine the values into a helper key, then count that key. In E2:
=A2&"|"&B2&"|"&C2&"|"&D2
Then in F2:
=COUNTIF($E$2:$E,E2)>1
This pattern is more maintainable than dropping a long all-in-one formula into the sheet. It also makes your matching logic visible. People can see exactly which fields define a duplicate.
If multiple people are cleaning data, send them to a dedicated review view instead of asking them to scan the original sheet.
This formula returns only duplicated rows from A2:D:
=ARRAYFORMULA(UNIQUE(FILTER(A2:D, COUNTIFS(A2:A,A2:A,B2:B,B2:B,C2:C,C2:C,D2:D,D2:D)>1)))
That setup works best when duplicates need human judgment. A CRM import may contain two rows for the same company, but one row has the correct owner and the other has the latest activity note. Removing duplicates too early throws away context. A review tab preserves it.
A practical workflow looks like this:
UNIQUE for a cleaned reference listCOUNTIF or COUNTIFS to flag suspect rowsFILTER to create a queue for reviewThat sequence is slower than one-click removal. It is also safer.
Formulas only catch what you tell them to match. If one person enters Acme Inc, another enters ACME INC, and a third leaves a trailing space, exact-match formulas treat those as different values.
Clean the values before checking for duplicates:
=ARRAYFORMULA(UNIQUE(TRIM(LOWER(A2:A))))
Use this version when the sheet is fed by manual entry, copied exports, or form submissions from different teams. The trade-off is straightforward. Normalization improves detection, but it also changes the display of the data, so keep the original values somewhere if case or formatting matters for reporting.
Sometimes you do not need a full cleanup pass. You just need to know whether an import created a problem.
Use:
=ROWS(A2:A1000)-ROWS(UNIQUE(A2:A1000))
This gives a quick duplicate count for the range. It is useful before monthly reporting, before syncing data into another system, or after a bulk paste by a teammate who may have introduced repeat entries.
I see this often in sheets used for operations, especially work logs and timesheets. In those cases, a quick duplicate check before payroll review is far safer than deleting rows on sight. The same review-first habit makes sense in Google Sheets time tracking workflows, where duplicate entries can affect billing or payroll.
Built-in removal tools are fine for one-time cleanup on disposable data. Formula methods are better when the sheet is still active and the team needs evidence before making changes.
Choose formulas if you need to preserve the source data, expose all matching records, or review duplicates with other fields in context. Choose deletion only after the team agrees on the rule for what stays. That is the difference between cleaning a sheet and damaging one.
Duplicate problems get expensive once they spread across tabs and files. A sales lead gets contacted twice. A support record is updated in one sheet but not another. A task appears on both a team board and a manager’s planning tab, so two people assume the other one owns it.

Across multiple sheets, the first job is not deletion. It is understanding the pattern.
A pivot table is useful when you need to see which records repeat most often and where the duplication is concentrated. That matters in product catalogs, recurring lead imports, shared task libraries, and CRM exports where the repeated item may point to a broken process rather than a simple data-entry mistake.
Build the pivot from a consolidated range, put the fields that define the duplicate in Rows, and use COUNTA in Values. Start with the narrowest identifier that matters to the business. For a CRM, that may be email address. For operations, it may be order ID. For task tracking, it is often a combination such as project name plus task title.
That distinction matters. If you count duplicates on task title alone, "Kickoff Call" may look like a problem when it is a normal repeat across clients.
The hard part is rarely the formula. The hard part is deciding what counts as the same record across systems.
In real client sheets, I usually see one of three cases:
The wrong move is to start with a destructive cleanup tool before that rule is settled. In a multi-sheet CRM, deleting a row because the email matches can erase a newer owner, note, or pipeline stage. In a collaborative task list, removing one "duplicate" can wipe out a different due date or assignee that the team still needs to review.
For cross-sheet work, review-first methods are usually safer.
If you need to check whether a value in the current sheet already exists in another file, IMPORTRANGE plus COUNTIF is the fastest workable pattern:
=COUNTIF(IMPORTRANGE("sheetURL","A:A"), A1)>1
If the source file is not always connected, wrap it in IFERROR:
=IFERROR(COUNTIF(IMPORTRANGE("sheetURL","A:A"), A1)>1, FALSE)
Use it for targeted checks, not full-sheet surveillance. A focused comparison works well when one team owns the master customer list and another team needs to confirm whether a lead, account, or SKU already exists before adding a new row.
A clean workflow looks like this:
That last step is where teams avoid bad cleanup decisions. The duplicate flag identifies risk. It does not decide which row deserves to survive.
Within a single file, many-tab setups usually perform better when you stack the relevant data into one helper sheet and run duplicate analysis there.
For example, a company may keep separate tabs for inbound leads, qualified leads, renewals, and partner referrals. Instead of checking each tab against every other tab with nested formulas, pull the key columns into one analysis tab, add a source column so you know where each row came from, and then count duplicates against that combined table.
This gives the team two things standard tutorials often skip. First, it preserves traceability. Second, it shows whether the duplicate is a true error or a handoff between teams.
Cross-file formulas are fine for lightweight checks. They become a maintenance problem when people stack IMPORTRANGE, QUERY, lookup formulas, and duplicate logic across large shared sheets.
The symptoms are familiar: slow recalculation, broken permissions, partial imports, and duplicate flags that appear to change after someone edits an unrelated tab. At that point, the method is no longer just technical. It becomes an operations decision.
Use this rule set:
Tip: If performance drops, shrink the imported range before adding duplicate logic. Pull the exact column you need, not the full sheet.
For business sheets, that is usually the right trade-off. Broad formula stacks look clever, but narrow checks tied to a clear duplicate rule are easier to audit, explain, and trust.
A weekly duplicate check is manageable. A sheet that collects form submissions every day, feeds a CRM tab, and gets edited by three or four teammates is a different problem. At that point, duplicate handling stops being a spreadsheet trick and becomes a process design choice.

Apps Script is useful because it lets you enforce the choice you already made. If the sheet is disposable, a script can remove repeats and keep the file tidy. If the sheet contains notes, owners, timestamps, or status updates, the safer choice is usually non-destructive: flag, separate, archive, and review.
That distinction matters in real business sheets. In a collaborative task list, two rows with the same title might reflect rework, not an error. In a multi-sheet CRM, the same contact can appear twice because sales and support touched the record at different stages. A delete-first script hides that context. An archive-first script preserves it.
This pattern keeps the first occurrence in place and moves later duplicates to an Archive sheet for review.
function archiveDuplicateRows() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const source = ss.getSheetByName("Data");
const archive = ss.getSheetByName("Archive") || ss.insertSheet("Archive");
const values = source.getDataRange().getValues();
if (values.length < 2) return;
const headers = values[0];
const rows = values.slice(1);
const seen = new Set();
const keepRows = [headers];
const duplicateRows = [headers];
rows.forEach(row => {
const key = [row[0], row[1], row[2], row[3]].join("||"); // adjust columns as needed
if (seen.has(key)) {
duplicateRows.push(row);
} else {
seen.add(key);
keepRows.push(row);
}
});
source.clearContents();
source.getRange(1, 1, keepRows.length, keepRows[0].length).setValues(keepRows);
if (duplicateRows.length > 1) {
archive.clearContents();
archive.getRange(1, 1, duplicateRows.length, duplicateRows[0].length).setValues(duplicateRows);
}
}
The script is simple on purpose. The important decision is the duplicate key. row[0], row[1], row[2], row[3] might make sense for a lead list where email, company, country, and source define uniqueness. It would be a poor fit for a task tracker where duplicate task names are common, and the key is task title plus assignee plus due date.
A few practical adjustments make a big difference:
Apps Script becomes more useful when it runs on a schedule, but the trigger type should match the sheet.
For high-collaboration sheets, I usually prefer a timed trigger over On edit. An edit-based trigger can fire too often, interrupt active work, or archive rows before someone finishes entering the full record. Nightly cleanup is slower, but it is easier to audit and less likely to create confusion.
For import tabs that refresh on schedule, timed automation is usually the right call. For controlled intake sheets with clear data-entry rules, On edit can work if the duplicate key is stable.
For a walkthrough on setting up automation in Google Workspace, this video is a useful visual companion:
Use Apps Script when duplicate handling needs to be repeatable and explainable:
Google Sheets can now help generate formulas with AI-assisted features, but formula suggestions do not solve the harder part: deciding what should happen to the extra row. Scripts are stronger when you need versioned behavior, archive tabs, triggers, and a process another teammate can inspect later.
If duplicate records feed customer communication, preserve a review step before anything goes out. That is especially important in workflows tied to document sends or mail merge with PDF automation, where one bad duplicate can send the wrong file twice or reach the same contact from two different rows.
The best method depends less on spreadsheet skill and more on what the sheet represents.
If the sheet is a throwaway import, remove duplicates and move on. If it is a live task board, preserve history. If it is a CRM working list, flag first, review second, remove third.
TRIM removes trailing spaces. LOWER helps expose capitalization differences.Final takeaway: The safest workflow is usually non-destructive first, destructive second. Review before deletion is not overkill. It is what keeps records trustworthy.
Knowing how to find duplicates in google sheets is useful. Knowing when not to delete them is what saves teams from avoidable cleanup damage.
Tooling Studio helps teams keep work inside Google Workspace with focused tools for task management, shared workflows, and growing operational processes. If your team is juggling Gmail, Google Tasks, Sheets, and client or project tracking, explore Tooling Studio for a more unified way to manage the work around your data.