keelapps/Satchel for Confluence
For the file that is attached to the wrong page
Move an attachment to another page. Confluence Cloud still cannot.
Confluence shows attachments one page at a time, and moving a file between pages is not possible at all. Satchel indexes the whole space instead: search every file, download a structured zip, spot orphans and duplicate candidates, and move attachments between pages — with a dry run before, an undo after, and a per-file report of what actually happened. Nothing leaves Atlassian.
CONFCLOUD-15025 — “Bulk Move of Attachments Between Pages” — has been open since March 2009, with 152 votes, and Atlassian's answer in January 2022 was that it is “a feature that we don't have plans to prioritize in the near future.” Confluence Data Center has a move endpoint. Cloud never got one.
The rest of it is the same story one level down: to answer “what is in this space, how big is it, who put it there” you open pages one at a time. The Marketplace has a download-only app in this category and nothing that puts move, orphan detection and storage analysis together.
What it does
Move attachments between pages
Pick the files, pick the target page, read a dry run that names every consequence — including which route the move will take on your site — and undo it afterwards.
A whole space in one zip
Select files across pages and download one archive, foldered by page title, with a CSV manifest inside it. Built in your browser: attachment content never reaches our servers, because we do not have any.
One table for the whole space
Search and filter every attachment by page, type, uploader and size; select across pages; act in bulk. Confluence gives you one page's worth at a time.
Find what nobody is using
Four buckets: files on deleted pages, files on archived pages, files sitting in the trash and still billed to you, and attachments no page body references.
Duplicate candidates
Grouped by normalised filename and identical byte count, with the space each group would reclaim. Candidates, not verdicts — Confluence exposes no content hash.
Delete carefully, or not at all
Bulk delete is off until a site administrator enables it, deletions go to Confluence's own trash where a space admin can restore them, and every one is recorded. Satchel never edits page content.
Cleaning up a space, end to end
-
Index it once
A scan builds the space's attachment inventory — metadata only, never file content — resumable, so a space with forty thousand files finishes. Before it runs, Satchel shows what it will cost in Confluence API points.
-
Read the four orphan buckets
Deleted pages, archived pages, the trash, and files no page body references. The first three are certain; the last is labelled as inferred, and the interface distinguishes “checked and found nothing” from “never looked”.
-
Move what belongs somewhere else
Select the files, pick the target page, and read the dry run: what will move, what will not and why, and which route the move will take on this site — because one route preserves attachment ids and version history and the other does not.
-
Then, if you must, delete
An administrator enables deletion; it goes to the trash rather than the void, and the audit trail records who removed what. Zip it first if you want a copy on disk.
Against what you have today
| Question | Native Confluence | Download-only apps | Satchel |
|---|---|---|---|
| Move an attachment to another page? | Not possible at all | — | Dry run, per-file report, undo |
| See every attachment in a space at once? | One page at a time | Partly | One searchable table |
| Download a whole space's files? | — | Yes | One zip, foldered by page |
| Which files is nothing using? | — | — | Four buckets, honestly labelled |
| Where did the space's storage go? | No breakdown | — | By page, uploader and type |
| Do attachment bytes pass through a vendor server? | — | Often | Never — built in your browser |
Limits we state up front
The move has two possible routes, and which one your site allows decides what it costs you. Confluence's current API has no attachment write path, so Satchel attempts the honest route first: a single call that re-parents the attachment, preserving its id, its file id and its whole version history. Only if the endpoint answers that the operation does not exist does it fall back to copy-then-delete — which works everywhere, but gives the file a new id, a new file id, a version history starting at 1, and breaks any page body that embedded the file by its old id.
Satchel does not guess which one you get. It attempts, learns from the answer, caches what it learned for your site, reports per file which route actually ran, and prints the consequence in the dry run before you commit. On the copy route the original is deleted only after the copy has been observed on the target page — there is no path where the original is gone and the copy was never made. And nothing in the interface claims ids were preserved unless a re-parent actually succeeded.
Duplicate detection finds candidates. There is no content hash in Confluence's API — the file id identifies the stored file for that one attachment, not a checksum shared across identical uploads. So grouping is by normalised filename and identical byte count, every surface says “candidates”, and two deliberate exclusions follow: same name with different sizes is not grouped (that is two revisions), and same size with different names is not grouped (that is a coincidence, and a common one at small sizes).
Version-history storage is a number we will not fabricate. Confluence reports the current version's size and the version count, but no prior version's size and no aggregate. Multiplying one by the other would be an invention: a document whose first draft was 2 KB and whose tenth is 8 MB is not 80 MB. The storage report gives counts and states plainly what it cannot tell you.
“Unreferenced” means inferred, not proven. The check reads the parent page's body for a reference to the file. A file may still be linked from another page, from a comment, or from outside Confluence. That bucket is labelled inferred where the other three are labelled certain.
“No attachments” is never asserted as a fact. Confluence can answer a read it could not serve with an empty success, so a scan can succeed, index nothing, and be completely wrong. Satchel records that case, phrases it as a question rather than a finding, and gives administrators a one-call check that settles it.
Availability
Satchel for Confluence is built and deployed on Atlassian Forge. It is going through Atlassian Marketplace review; this page will link to the listing as soon as it is live.
Licensing is handled by Atlassian. Sites with 10 users or fewer pay nothing at all; paid tiers are priced per user and taper as the site grows, at the same rates as Satchel for Jira.
Questions, bug reports and feature requests: raise a support request.
Found a security issue? Please report it privately rather than in a public channel.