Skip to content
 
 

Repository files navigation

Google Photos Delete Tool

Find and delete duplicate photos in Google Photos, and bulk delete safely: dry run first, batches of up to 500, optional empty trash.

Get it on the Chrome Web Store or as a userscript. It runs in your browser; nothing is uploaded.

CI Release License: MIT Chrome Web Store

Find duplicates

Google Photos only removes exact copies of the same file. Copies that were resized, re-saved, edited slightly, or uploaded twice from different apps stay in your library. Find duplicates finds them for you:

  1. Open the view you want to check (your library, an album, or a search).
  2. Click the extension icon, then Find duplicates (userscript: the Find duplicates button in the floating panel), then Scan this view.
  3. The tool scrolls the view and compares small thumbnails on your computer. Look-alike photos are shown in groups.
  4. In each group the best copy is kept (green) and the rest are marked for Trash (red). The best copy is the largest one when the size is known, otherwise the oldest. Click any photo to switch it. Each group always keeps at least one photo.
  5. Use the Similarity slider: 95% finds near-identical copies; lower values also group edits and burst shots, so check those groups.
  6. Preview (dry run) checks the chosen photos are still in the view without changing anything. Move to Trash hands them to the same safe delete flow as the rest of the tool: a one-time confirmation, batches, Stop at any time, and 60 days in Trash to change your mind.

Find duplicates reviewing look-alike groups on a test page

Test page with generated images, not real photos (scripts/dupes-demo.mjs).

Private by design. Thumbnails are fetched only from Google's own image servers (the same ones the page already uses), turned into a 64-bit fingerprint in memory, and forgotten when you close the review. Nothing is uploaded; there is no server. Works for tens of thousands of photos: the comparison runs in short slices so the tab stays responsive, with progress and Cancel throughout. Large views take a while because Google Photos loads the grid only as you scroll.

Why not the Google Photos API? Since 31 March 2025 Google no longer lets apps read your whole library through the Photos API, so an external duplicate finder cannot see your photos. This tool works inside the Google Photos page you already have open instead.

Bulk delete

Google Photos has no "delete all". This tool runs the select, trash, confirm loop for you in batches of up to 500 until your current view is empty. It works in your browser by clicking the same controls a person would, because the Google Photos Library API has no delete endpoint.

Two surfaces, one engine

Surface Get it Includes
Chrome / Firefox extension Chrome Web Store; Firefox zip on each release Popup UI, badge, 9 languages, empty-trash flow
Userscript (Tampermonkey, Violentmonkey, Greasemonkey) google-photos-delete.user.js from the latest release Same engine, floating panel, same safety model

Built to be trusted

  • Fail-closed matching. Delete, confirm and empty-trash buttons are matched by positive multilingual keywords on aria-label, tooltip or text. An unknown UI stops the run with an error; it never clicks a guess.
  • Consent gate. The first real run asks you to acknowledge what will happen. Nothing is scheduled or unattended.
  • 60-day Trash. Deleted photos sit in Google Photos Trash for 60 days. "Empty trash afterwards" is opt-in, permanent, and reported done only after the trash is verified empty.
  • Accurate numbers. The progress bar is indeterminate while the total is unknown; ETA appears once a dry run has established a total.
  • No telemetry, no server. Everything runs in your browser. Pro licence verification is local (Ed25519).

Features

  • Find duplicates: scan the current view, group look-alike photos by perceptual hash at an adjustable similarity, review which to keep, then move the rest to Trash through the consent-gated flow.
  • Batch delete: up to 500 per batch (Google's selection cap); the engine detects the cap, scrolls and flushes the final partial batch.
  • Pause / Resume / Stop: stop is instant; a stopped run never reports a false error.
  • Dry run: scrolls and counts without clicking anything, and (with Pro) returns a per-type breakdown.
  • Empty trash (opt-in): opens /trash, empties it and verifies the result.
  • Type filters (Pro): delete only screenshots, videos, animations, collages or photos.
  • Versioned selector packs: Google Photos selectors and keyword lists live in a versioned JSON pack, so a UI change ships as a data patch.
  • Report issue: one click opens a pre-filled GitHub issue with pack version, selector matches and observed labels.
  • 9 languages in the extension UI, with compile-time-complete translations.

Installation

Chrome / Firefox

  1. Install from the Chrome Web Store or load the Firefox zip from the release.
  2. Navigate to photos.google.com.
  3. Click the extension icon, confirm the safety notice on your first real run, then press Start.

Manual load (development): download the release zip, unzip, open chrome://extensions (or about:debugging#/runtime/this-firefox), enable developer mode, and Load unpacked.

Userscript

  1. Install Tampermonkey or Violentmonkey.
  2. Install the latest google-photos-delete.user.js.
  3. Open photos.google.com — the floating panel appears bottom-right.

Usage

  1. Be on the Google Photos view you intend to clean (the tool acts on the current view).
  2. Dry run first to see the count without touching anything.
  3. Configure: photos per batch (default 500), empty-trash toggle, optional type filter (Pro).
  4. Start, and use Pause / Resume / Stop freely. Stop is immediate.
  5. Watch the progress: deleted count, rate, elapsed; ETA only when a dry-run total is known.

Privacy

Zero data collection, zero servers, zero telemetry. Full statement in PRIVACY.md.

Pro

The delete engine, dry-run, and empty-trash are free forever. A one-time Pro license unlocks the analysis layer: type filters and the dry-run report/export. Pro is a locally-verified Ed25519 token — no account, no backend. Seller tooling and key management: see docs/PRO.md.

Development

bun install
bun run typecheck   # strict TS
bun run lint        # ESLint (src/ + scripts/)
bun run test        # Vitest — full engine loop on a scripted DOM
bun run build       # all artifacts (Chrome, Firefox, userscript, standalone)
bun run verify      # artifact smoke gate (manifest/pack/IIFE self-containment)
bun run zip         # release zips
bun run package     # build + verify + zip

Architecture

src/
├── core/                  # Framework-agnostic engine & domain
│   ├── delete-engine.ts   # Batch loop on an injected DOM adapter (testable)
│   ├── dom-adapter.ts     # EngineDom contract; browserDom = real browser impl
│   ├── selector-pack.ts   # Versioned, data-driven selector + keyword pack
│   ├── empty-trash.ts     # Empty-trash flow WITH postcondition proof
│   ├── empty-trash-baton.ts# Pending-flag semantics (localStorage / chrome)
│   ├── page-runner.ts     # In-page orchestration: consent, license, runner
│   ├── license.ts         # Local Ed25519 Pro license verification
│   ├── photo-filter.ts    # Type classification + the id filter used by Find duplicates
│   ├── dedup/             # Find duplicates: pHash, grouping, scan loop, keep/Trash choices
│   ├── diagnostics.ts     # Bounded selector/label evidence for issue reports
│   ├── status.ts          # One RunStatus union shared by every surface
│   └── ...
├── selector-packs/        # pack-v1.json (versioned selectors + keywords)
├── ui/panel/              # ONE floating panel (userscript + standalone)
├── ui/dupes/              # Find duplicates review (extension + userscript)
├── extension/             # MV3 manifests, popup (i18n), content, background
│   └── api.ts             # Chrome/Firefox promise wrappers (callback-based)
├── standalone/            # Dev-only console-paste mount
└── userscript/            # Thin mount of the shared panel
scripts/                   # build.ts · zip.ts · verify.ts · license.ts · dupes-demo.mjs
tests/                     # engine loop on a scripted DOM fake + core/surface suites

Release gate

Every release passes the live-run protocol in docs/RELEASE_GATE.md: a disposable account, a fixed deletion scenario, and recorded postconditions. Release notes carry the evidence.

FAQ

Is this safe? It only clicks what a human would click, matching destructive actions by positive keywords (never guessing), and deleted photos sit in Trash for 60 days. The only permanent action is "Empty trash", which is opt-in, gated by the postcondition check, and never unattended.

What happens when Google changes their UI? The selector pack version is recorded in every diagnostic report. When a drift is reported, the fix is a data patch to the pack, shipped as a point release. This is the maintenance model by design.

How does it decide what is a duplicate? Each thumbnail is shrunk to 32×32 gray pixels and turned into a 64-bit perceptual hash (pHash). Two photos whose hashes differ in only a few bits look the same to a person. The default 95% similarity allows 3 of 64 bits to differ. The hashing and grouping are ported from our Photo Dedup engine and tested against its reference results.

Does it find duplicates across my whole library? It checks the view you scan. Scan your main Photos view to cover the library, or an album or search to narrow it down.

How fast is it? Deletion runs at Google's UI pace; each release's photos per minute is measured in the release gate and published in its notes.

What about the trash? Deleted photos go to Trash for 60 days. "Empty trash afterwards" empties and permanently removes them — with your explicit opt-in.

License & provenance

MIT, see LICENSE. A Sylphx open-source product, modernized from mrishab/google-photos-delete-tool. See docs/LICENSE_PROVENANCE.md.

Releases

Packages

Used by

Contributors

Languages