# Finding unused files

**URL:** <https://community.hubspot.com/t/finding-unused-files/46343>\
**Category:** APIs & Integrations\
**Tags:** cms-content\
**Created:** [November 2, 2021, 4:16pm UTC](https://community.hubspot.com/t/finding-unused-files/46343 "2021-11-02T16:16:46Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Sheamus](https://d10pqhm3lwygmk.cloudfront.net/user_avatar/community.hubspot.com/sheamus/32/95715_2.png) [@Sheamus](https://community.hubspot.com/u/Sheamus)\
**Post date:** [November 2, 2021, 4:16pm UTC](https://community.hubspot.com/t/finding-unused-files/46343/1 "2021-11-02T16:16:46Z")

</div>

Our ‘Files’ are full of unused files. There doesn’t seem to be a way in HS to sort by usage or a filter for ‘unused’. I was hoping I could write a script using the API to get a list of the unused files and delete them.

However, the V3 API doesn’t seem to offer any meta-data for files. The V2 API does offer a ‘get file metadata’ call, but it doesn’t seem to offer anything that the V3 ‘get file’ call does. I am guessing that this is just a renaming of the endpoint.

So _ **is there any way I can programmatically get information about the usage of files** _, similar to how I can use the HS file manager on the web? I really don’t want to have to sort through 1000’s of files, and one at a time clicking on details, delete, ok, rinse repeat.

Note that we have HS Marketing Pro, but we do not have/use the HS CMS platform. These are files used in our LP’s, social media posts, or LP templates.

---

<div class="post-metadata">

**Author:** ![Sheamus](https://d10pqhm3lwygmk.cloudfront.net/user_avatar/community.hubspot.com/sheamus/32/95715_2.png) [@Sheamus](https://community.hubspot.com/u/Sheamus)\
**Post date:** [November 3, 2021, 1:23pm UTC](https://community.hubspot.com/t/finding-unused-files/46343/2 "2021-11-03T13:23:43Z")

</div>

I was able write a tampermonkey script that scraped the information about all the files (including usage) into a json object so that it can be used with a script which deletes the unused files. I’ll post it here hoping that it helps someone else.

1. Install the chrome TamperMonkey plugin.
2. Add this script below to TM.
3. Go to the first page of your files.
4. You should see a 'Get File Info button. Click the button.
5. Don’t touch anything; wait until a popup shows the JSON, and copy paste it to where you need it.

```lia-code-sample
// ==UserScript==
// @name Hubspot find unused
// @namespace http://tampermonkey.net/
// @version 0.1
// @description crawl the HS file explorer and make a printable list if they are not used.
// @author Shea Martin
// @match https://app.hubspot.com/files/*
// @icon https://www.hubspot.com/hubfs/assets/hubspot.com/style-guide/brand-guidelines/guidelines_approved-sprocket-2.svg
// @grant none
// @require http://code.jquery.com/jquery-latest.js
// ==/UserScript==
var $ = window.jQuery;

const maxPages = 20;

function getFileInfoFromSidePanel(r) {
 $('[data-key="FileManagerDashboard.detailPanel.fileUsage"]').click();
 $('[data-key="FileManagerDashboard.detailPanel.sections.general"]').click();

 const name = $('[data-test-id="panel-file-name"] > span').text();
 const url = $('[data-test-id=file-detail-url-link]').attr('href');
 const unused = $('[data-key="FileManagerDashboard.fileUsage.unused"]').length === 1;
 const size = $('[data-test-id=file-detail-size]').text();
 const dimensions = $('[data-key="FileManagerCore.fileDimensions.dimensions"]').text();
 const fileId = $('[data-test-id="panel-file-id"]').text();
 const fileType = $('[data-key="FileManagerDashboard.detailPanel.fileType"]').parent().next().text();

 return {
 name,
 url,
 unused,
 size,
 dimensions,
 fileId,
 fileType,
 };
}

function processRowsOnPage(rows, fileDetails, pageCompleteCallback) {
 const r = rows.pop();
 if(!r) {
 log(`completed page ${curPage}`);
 pageCompleteCallback();
 return;
 }
 r.click();
 setTimeout(() => {
 const details = getFileInfoFromSidePanel();
 fileDetails.push(details);
 log(`got details for ${details.name}`);
 processRowsOnPage(rows, fileDetails, pageCompleteCallback);
 }, 1000);
}

function processPage(fileDetails, allPagesCompleteCallback) {
 log(`processing page ${curPage}`);
 const rows = $('button[data-test-id=file-row]').toArray();
 processRowsOnPage(rows, fileDetails, () => {
 const hasNext = nextPage();
 if(hasNext) {
 processPage(fileDetails, allPagesCompleteCallback);
 } else {
 allPagesCompleteCallback();
 }
 });
}

function getUnused() {
 curPage = 1;
 const fileDetails = [];
 processPage(fileDetails, () => {
 log('complete');
 completeAllPages(fileDetails);
 });
}

function completeAllPages(fileDetails) {
 const content = JSON.stringify(fileDetails, undefined, 4);

 alert(`got information on ${fileDetails.length} files. Copy the results from the results pane.`);
 $('#file-results-pane').show();
 $('#file-results-data').html(content);
}

let curPage = 1;
function nextPage() {
 const nextButton = $('button[data-next-page=true]');
 if(curPage >= maxPages) {
 log(`page limit of ${maxPages} has been exceeded`);
 return false;
 }
 if(nextButton.length !== 1 || nextButton.attr('aria-disabled') === 'true') {
 log('no more pages');
 return false;
 }
 curPage += 1;
 nextButton.click();
 return true;
}

function setupUi() {
 log('ui initiated');
 const startButton = $('<button>Get File Info</button>');
 startButton.click(() => {
 alert('starting to retrieve file information. Do not touch mouse or keyboard until complete dialog shows.');
 getUnused();
 });
 $('[data-test-id=upload-files-button]').parent().append(startButton);

 const css = `
 border: 4px solid green;
 position: absolute;
 top: 100px;
 left: 20px;
 right: 20px;
 height: 80vh;
 padding: 40px;
 overflow: auto;
 z-index: 1000;
 background-color: white;
 font-family: monospace;
 display: none;
 `;

 $('body').prepend(`
 <div id="file-results-pane" style="${css}">
 <button onclick="$('#file-results-pane').hide();">Close</button>
 <h1>Results</h1>
 <pre id="file-results-data"></pre>
 </div>`);
}

function log(msg) {
 console.log('[tm] ' + msg);
}

(function() {
 'use strict';

 log('loaded');

 setTimeout(() => setupUi(), 3000);
 // setTimeout(() => completeAllPages([{name: 'shea', age: 43}, { name: 'Denby', age: 42 }]), 4000);

 // document.addEventListener('keydown', (e) => {
 // if(e.ctrlKey && e.key === 'D') {
 // log('shortcut pressed');
 // getUnused();
 // }
 // }, true);
})();

```

---

<div class="post-metadata">

**Author:** ![schmelik](https://d10pqhm3lwygmk.cloudfront.net/user_avatar/community.hubspot.com/schmelik/32/78301_2.png) [@schmelik](https://community.hubspot.com/u/schmelik)\
**Post date:** [March 30, 2023, 12:27am UTC](https://community.hubspot.com/t/finding-unused-files/46343/3 "2023-03-30T00:27:13Z")

</div>

Thanks Sheamus (and no thanks to HubSpot)

the code worked well but I made a few augmentations to it.  
Now it highlights and selects those files that are unused.  
_I kept the json return but left it hidden in case someone really wanted it_

```lia-code-sample
// ==UserScript==
// HubSpot -- Select Unused Files
// @namespace http://tampermonkey.net/
// @version 0.2
// @description make HubSpot life easier
// @author erik bloomstrand
// @match https://app.hubspot.com/files/*
// https://www.google.com/s2/favicons?sz=64&domain=hubspot.com
// none
// @require http://code.jquery.com/jquery-latest.js
// ==/UserScript==
var $ = window.jQuery;

const maxPages = 1;

function getFileInfoFromSidePanel(r) {
 $('[data-key="FileManagerDashboard.detailPanel.fileUsage"]').click();
 $('[data-key="FileManagerDashboard.detailPanel.sections.general"]').click();

 const name = $('[data-test-id="panel-file-name"] > span').text();
 const url = $('[data-test-id=file-detail-url-link]').attr('href');
 const unused = $('[data-key="FileManagerDashboard.fileUsage.unused"]').length === 1;
 const size = $('[data-test-id=file-detail-size]').text();
 const dimensions = $('[data-key="FileManagerCore.fileDimensions.dimensions"]').text();
 const fileId = $('[data-test-id="panel-file-id"]').text();
 const fileType = $('[data-key="FileManagerDashboard.detailPanel.fileType"]').parent().next().text();

 return {
 name,
 url,
 unused,
 size,
 dimensions,
 fileId,
 fileType,
 };
}

function processRowsOnPage(rows, fileDetails, pageCompleteCallback) {
 const r = rows.pop();
 if(!r) {
 log(`completed page ${curPage}`);
 pageCompleteCallback();
 return;
 }
 r.click();
 setTimeout(() => {
 const details = getFileInfoFromSidePanel();
 fileDetails.push(details);
 log(`got details for ${details.name} ${details.fileId} ${details.unused}`);
 processRowsOnPage(rows, fileDetails, pageCompleteCallback);
 if ( details.unused === true) {
 $('tr[data-test-object-id="'+details.fileId+'"]').css('background-color', '#FF000055').find('label').click();
 } else {
 $('tr[data-test-object-id="'+details.fileId+'"]').css('background-color', '#00FF0055');
 }
 }, 1000);
}

function processPage(fileDetails, allPagesCompleteCallback) {
 log(`processing page ${curPage}`);
 const rows = $('button[data-test-id=file-row]').toArray();
 processRowsOnPage(rows, fileDetails, () => {
 const hasNext = nextPage();
 if(hasNext) {
 processPage(fileDetails, allPagesCompleteCallback);
 } else {
 allPagesCompleteCallback();
 }
 });
}

function getUnused() {
 curPage = 1;
 const fileDetails = [];
 processPage(fileDetails, () => {
 log('complete');
 completeAllPages(fileDetails);
 });
}

function completeAllPages(fileDetails) {
 const content = JSON.stringify(fileDetails, undefined, 4);
 const unusedFiles = fileDetails.filter(file => file.unused === true);
 $('[data-test-id="close-panel-button"]').click();

 setTimeout(() => {
 alert(`${fileDetails.length} files have been evaluated. ${unusedFiles.length} are selected and not being used`);
 }, 200);
// $('#file-results-pane').show();
 $('#file-results-data').html(content);
}

let curPage = 1;
function nextPage() {
 const nextButton = $('button[data-next-page=true]');
 if(curPage >= maxPages) {
 log(`page limit of ${maxPages} has been exceeded`);
 return false;
 }
 if(nextButton.length !== 1 || nextButton.attr('aria-disabled') === 'true') {
 log('no more pages');
 return false;
 }
 curPage += 1;
 nextButton.click();
 return true;
}

function setupUi() {
 log('ui initiated');
 const startButton = $('<button class="uiButton private-button private-button--sm private-button--non-link">Select Unused Files</button>');
 startButton.click(() => {
 alert('Starting to retrieve file information. Do not touch mouse or keyboard until complete dialog shows.');
 getUnused();
 });
 $('[data-test-id=upload-files-button]').parent().append(startButton);

 const css = `
 border: 4px solid green;
 position: absolute;
 top: 100px;
 left: 20px;
 right: 20px;
 height: 80vh;
 padding: 40px;
 overflow: auto;
 z-index: 1000;
 background-color: white;
 font-family: monospace;
 display: none;
 `;

 $('body').prepend(`
 <div id="file-results-pane" style="${css}">
 <button onclick="$('#file-results-pane').hide();">Close</button>
 <h1>Results</h1>
 <pre id="file-results-data"></pre>
 </div>`);
}

function log(msg) {
 console.log('[tm] ' + msg);
}

(function() {
 'use strict';
 setTimeout(() => setupUi(), 3000);
})();

```

here is an example of the output

 ![output.png](https://d2qpr2jzcazej7.cloudfront.net/original/3X/1/3/13e5d3f3990ba922bcaa04c2e7c362239feaf9c6.png)

---

<div class="post-metadata">

**Author:** ![GTreboit7](https://avatars.discourse-cdn.com/v4/letter/g/45deac/32.png) [@GTreboit7](https://community.hubspot.com/u/GTreboit7)\
**Post date:** [May 25, 2023, 2:49pm UTC](https://community.hubspot.com/t/finding-unused-files/46343/4 "2023-05-25T14:49:52Z")

</div>

Hi @schmelik super cool ! I actually be really interested to have the exhaustive code if it is possible please ? 🙂

---

<div class="post-metadata">

**Author:** ![schmelik](https://d10pqhm3lwygmk.cloudfront.net/user_avatar/community.hubspot.com/schmelik/32/78301_2.png) [@schmelik](https://community.hubspot.com/u/schmelik)\
**Post date:** [May 26, 2023, 4:13pm UTC](https://community.hubspot.com/t/finding-unused-files/46343/5 "2023-05-26T16:13:42Z")

</div>

To be honest, I was under a deadline, so I left out comments  
_horrible_ 😜  
I’ll circle back to add the exhaustive code when I find the time. -- no promises
