You can now vote for scripts to help people know if they're useful or not. Login or create an account to vote!


Archive Unused Personal Spaces


A scheduled job that you can also run in the script console to archive personal spaces that have not been modified. The script checks each personal space to see if it contains only the following 'sample' pages and archives the space if the pages are unedited: Overview, Sample Pages, Decisions, Product requirements, Meeting notes


Personal spaces are created whenever a new user accesses Confluence. Each space has the same set of sample pages that clutter up the search results in Confluence. This script archives the personal spaces that aren't being used, in order to improve the search experience for both spaces and pages.

Good to Know

Users with a non-English language setting in Confluence will have pages created with different names to the ones specified in the script e.g. Requisitos del producto. You must update the script to cater for non-English page names.

This script may timeout when it is run from the Script Console or as a Script Job if you have many spaces in your Confluence instance. After a timeout, the script picks up from where it stopped when you re-run it. Timeouts will show as errors in the Execution History of a Script Job.

You can configure this script to run as a Script Job to ensure unused personal spaces are continuously archived in the background.


  • Confluence Confluence
  • Jira Jira
  • ScriptRunner for Confluence ScriptRunner for Confluence
def archiveSpaces(int startAt = 0) { def spacesResponse = get('/wiki/rest/api/space') .queryString('start', startAt) .queryString('type', 'personal') .queryString('status', 'current') .asObject(Map) if (spacesResponse.status > 300) { logger.warn("Failed to fetch spaces starting at ${startAt}: ${spacesResponse}") return } def searchLimit = spacesResponse.body.limit as Integer def spaces = spacesResponse.body.results as List if (spaces.empty) {"Found 0 spaces starting at ${startAt}, stopping") return } def spacesNotArchived = 0 spaces.collect { [it.key,] }.each { tuple -> def spaceKey = tuple[0] def spaceName = tuple[1]"Checking contents in space: ${spaceName}") def contentResp = get('/wiki/rest/api/content') .queryString('spaceKey', spaceKey) .queryString('type', 'page') .queryString('expand', 'version') .asObject(Map) if (contentResp.status > 300) { logger.warn("Failed to fetch space content for ${spaceName} with key ${spaceKey}") spacesNotArchived++ return } def templatePageNames = ['Meeting notes', 'Sample Pages', 'Overview', 'Decision', 'Product requirements'] def pages = contentResp.body.results as List if (pages.size() != templatePageNames.size()) { logger.debug("Space ${spaceName} had ${pages.size()} pages, skipping") spacesNotArchived++ return } def unmodifiedTemplatePages = pages.every { templatePageNames.contains(it.title as String) && (it.version as Map).number == 1 } if (!unmodifiedTemplatePages) { logger.debug("Space ${spaceName} has modified page or title didnt match templates, skipping") spacesNotArchived++ return }"Archiving space ${spaceName} with key ${spaceKey}") def resp = put("/wiki/rest/api/space/${spaceKey}") .header('Content-Type', 'application/json') .body([ status: 'archived', type: 'personal' ]) .asObject(Map) if (resp.status > 300) { logger.warn("Archiving space ${spaceName} failed: ${resp}") spacesNotArchived++ } } if (spaces.size() >= searchLimit) { archiveSpaces(startAt + spacesNotArchived) } else {'No more spaces found, stopping') } } archiveSpaces()
Discovered an issue? Report it here

Suggested for you