Google Photos Toolkit: bulk operations for a photo library
Userscript to filter, search, organize, or delete your Google Photos library
At a glance
- What is it?
- Google Photos Toolkit is a Tampermonkey userscript that adds filtering, searching, album organisation and bulk deletion to the Google Photos web interface by driving the undocumented web API the site already uses. The current release is v3.3.0 from 2026-08-20, it is MIT licensed, and it also exposes its API class globally so the same operations can be scripted from the browser console.
- Who is it for?
- The toolkit fits a Google Photos user with a library that has grown past what the interface can manage, especially one who needs to find duplicates, isolate space-consuming media or clear a library without clicking through it by hand. It does not fit a user who wants an API to build on, since the whole thing runs against an undocumented interface that Google can change, and it does not fit anyone who is not willing to run a script with access to their session.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 64 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
It works by driving the API the site already uses
The How It Works section is one line, and it determines everything about how the tool behaves.
In your browser, utilizing GP's undocumented web api.
So there is no server component, no account and no upload of your library anywhere. The userscript runs inside the Google Photos page, in the session you are already logged into, and it talks to the same endpoints the web interface talks to. That has an immediate consequence for trust: the script has the same access to your account as the tab you are looking at, because it is running in it, and it is granted `unsafeWindow` and `GM_registerMenuCommand` in the userscript header.
The features that follow from that design are all bulk operations that the web interface does not offer. Finding space-consuming media, by selecting `SPACE-CONSUMING` in the Space filter and adding the result to a new album. Identifying media not in any albums, by selecting all albums in the Exclude albums filter. Identifying duplicates and similar images, with the Similarity filter, where media with similar thumbnails is added to the album. And deleting all media in the library, which the documentation describes as selecting Library as the source, clicking Move to trash, and then clearing it.
That last one is the operation that needs a warning, and the framing is instructive. Move to trash is not a delete, and the second step, clearing the trash, is where the data actually goes. The documentation presents it as a two-step action, which is also how it behaves in the Google Photos interface.
The tool's own topic tags include mass-delete, and the fact that bulk deletion is a headline feature tells you the audience: people with libraries that need pruning, who are dealing with a platform whose interface is designed for browsing rather than for administration.
The API class is exposed for console scripting, and that is the powerful part
There is a section on using GPTK's API, and it is the most interesting thing in the readme.
GPTK exports its api class globally so you can use it in your browser's console. It's much more powerful than the UI.
The example is a script that scans the whole library for media owned by a particular person and moves it to trash if found:
let nextPageId = null;
const ownerName = 'John';
do {
const page = await gptkApi.getItemsByUploadedDate(nextPageId);
for (const item of page.items) {
if (item.isOwned) continue;
const itemInfo = await gptkApi.getItemInfoExt(item.mediaKey);
console.log(`${item.mediaKey} is shared by ${itemInfo.owner.name}`);
if (itemInfo.owner.name == ownerName) {
await gptkApi.moveItemsToTrash([itemInfo.dedupKey]);
console.log(`${item.mediaKey} moved to trash`);
}
}
nextPageId = page.nextPageId;
} while (nextPageId);
console.log('DONE');Three things about that script are worth reading. The pagination loop is the shape of any bulk operation over this API, and the `nextPageId` dance is what you need for anything that touches more than a screenful. The `isOwned` check skips media the user owns, and the `getItemInfoExt` call fetches the extended info for a media key, which is where the owner name comes from. And the `moveItemsToTrash` call takes a list of dedup keys, so the operation is batched at the API level rather than one item at a time.
The console being the interface for this is not a limitation so much as a design statement. A user who can paste a script can do things the UI has no affordance for, and a user who cannot paste a script is not the audience for the API half of the tool at all.
The author also points at a third-party write-up on how the API works, a post about deciphering Google's batchexecute mechanism, and says he found it only after doing all the work from zero. The existence of that post is worth noting too, because the batchexecute pattern is the awkward part of talking to Google APIs and the reason the whole thing is undocumented.
Installation is three clicks and a userscript manager
The install path is deliberately the shortest thing in the readme.
Install Tampermonkey for your browser, and if you are on Android, try Firefox, which supports Tampermonkey. Then click Install on the release download link, which points at `google_photos_toolkit.user.js` in the latest release, and accept installation.
The `match` pattern in the userscript header is `*://photos.google.com/*`, and the script runs at `body`, which means it does not execute until the page body exists. That timing choice matters for a tool of this kind. A script that runs at `document-start` would be injected before the page's own JavaScript had created the interface, and any attempt to add a menu entry to a DOM that does not exist yet would fail. Running at `body` means the script waits for the interface and can then find the elements it needs to attach to.
The `grant` list is short, `GM_registerMenuCommand` and `unsafeWindow`. The first is what puts an entry in the Tampermonkey menu, which is how the tool gets a button, and the second is what allows the script to reach the page's own JavaScript objects, which is what makes the global `gptkApi` class possible in the first place.
The `downloadURL` field points at the releases page rather than at the source tree, so installing from the releases page always gives you the latest tagged build, and the `noframes` setting keeps the script out of any iframes the page might contain.
For a user on Android, the note about Firefox is the practical bit. A phone browser has no extension mechanism that supports a userscript manager, so mobile use means Firefox with an add-on, and that is a real constraint on a library-management task that people in particular might want to do from a phone.
A TypeScript source tree that builds into a single userscript
The repository is a proper TypeScript project with a build, which is worth noting for a project that ships as a single file.
The package is `google-photos-toolkit` at version 3.3.0, the description is Bulk organize your media, and the main entry is `google_photos_toolkit.user.js`. The build is `rollup -c`, with a watch mode, and the dev dependencies are the rollup plugins for TypeScript and for replacing build-time constants, plus `rollup-plugin-banner2`, which is how the userscript metadata block gets its header at build time.
The quality tooling is thorough for a single-purpose project. Typecheck is `tsc --noEmit`, lint is eslint over `src` with a flat config in `eslint.config.mjs`, and the tests run under vitest with a `vitest.config.ts`. There is a `build/` directory and a `tests/` directory in the tree, and a `tools/` directory at the top level.
That `tools/` directory is not the test suite. It holds a separate userscript that parses all the API responses and logs them to the console in a more readable way, which the author links as a resource for people learning how the API works. That is the same instinct as the console API export: the tool is partly a utility and partly a teaching aid, and the parts intended for other people are given away separately.
The credits name undiscord as the source of some borrowed code and UI inspiration, which explains a good deal about the interface. The filter-and-act UI pattern, the source selector and the action dropdown are the same shape as a tool people already understand.
The two related projects in the readme are also worth knowing about. A Python client with unlimited uploads, and a tool to disguise any file as media so that Google Photos will accept and store it, which is a different kind of workaround against the same upload restrictions.
Where Google Photos Toolkit is the wrong tool
The first case is anything that needs a supported API. This drives an undocumented interface, and the existence of a third-party post about deciphering the batchexecute mechanism is a fair signal of how fragile that is. Google can change the endpoint, the payload shape or the request encoding, and the tool breaks with an error rather than a message. The readme's own bug section asks for detailed issue reports when something does not work, which is the shape of a project that expects breakage.
The second case is a user who wants to build on top of their photo library programmatically, in a repeatable and scheduled way. A userscript that runs in a browser tab is a tool you use while looking at the interface. A library, an API client or a scheduled job is a different requirement, and the readme's related projects point at that direction with a Python client.
The third case is a user whose account carries risk they would rather not take. The script runs with your session and with `unsafeWindow` access, it can move media to trash, and it exposes an API that can do more than the UI. For an account with a large irreplaceable library, a sensible first step is to run the read-only parts, the filters and the space report, and to leave the delete path until you have a backup.
The fourth case is a Google Photos account on the platform's newer storage arrangements, where the library is no longer a single folder you own. The filters in this tool are built around the library structure as the web interface presents it, and the distinction between owned media and shared media in the API example shows how much the model depends on that.
A last note on scope. This is a single-user tool with a small feature set, and the readme's request for detailed bug reports and a separate discussions channel for questions is the shape of a maintainer who wants to keep it small. It is not trying to be a photo management platform, and the projects linked under My Other Google Photos Projects are each narrowly aimed at a specific limitation of the service.
Editorial conclusion
The toolkit fits a Google Photos user with a library that has grown past what the interface can manage, especially one who needs to find duplicates, isolate space-consuming media or clear a library without clicking through it by hand. It does not fit a user who wants an API to build on, since the whole thing runs against an undocumented interface that Google can change, and it does not fit anyone who is not willing to run a script with access to their session. Before you run a bulk delete, read the deletion section carefully, because the tool moves items to trash irreversibly from the user's point of view.
Frequently asked questions
How does Google Photos Toolkit work?
It is a Tampermonkey userscript that runs in your browser inside the Google Photos page and drives the undocumented web API the site itself uses, which is how it can perform bulk filter, search, album, move and delete operations that the web interface does not offer.
How do I install Google Photos Toolkit?
Install the Tampermonkey userscript manager, then open the `google_photos_toolkit.user.js` download from the latest release and accept installation. On Android, use Firefox, which supports Tampermonkey. The script matches `*://photos.google.com/*` and runs at `body`.
Can I use Google Photos Toolkit from the browser console?
Yes. The toolkit exports its API class globally as `gptkApi`, so you can call `getItemsByUploadedDate`, `getItemInfoExt` and `moveItemsToTrash` directly, paginating with `nextPageId`, which the readme says is much more powerful than the UI.
How do I find duplicates and space-consuming media with Google Photos Toolkit?
Make sure Library is the selected source, then use the Similarity filter with the action Add to new album to collect media with similar thumbnails, or select `SPACE-CONSUMING` in the Space filter for large files. Media not in any album is found by selecting all albums in the Exclude albums filter.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/xob0t-google-photos-toolkit)Was this useful?