Building a Media Usage & Orphan Tracking Dashboard in Sitecore XM 10
Hello everyone
Building a Media Usage & Orphan Tracking Dashboard in Sitecore XM 10
Hello everyone
While working on a Sitecore XM 10 implementation, I noticed a common challenge most content-heavy projects face over time: media sprawl.
Editors struggle to answer simple questions like:
- Which images are actually used?
- Which files are safe to delete?
- Where is this PDF referenced?
To solve this, I built a Media Usage & Orphan Tracking dashboard inside Sitecore.
This post explains what the solution does and includes essential code snippets so you can implement it in your own Sitecore project.
Solution Overview
The dashboard provides:
- Linked vs orphan media detection
- Expandable usage view (one media → many pages)
- Search, filtering, and pagination
- Excel export for reporting
- Support for site-specific and shared media
The implementation uses:
- Sitecore XM 10
- ASP.NET WebForms
- Stored procedures for performance
- EPPlus for Excel export
Step 1: Media Usage Model
Create a model to represent a media item and its usage.
[Serializable]
public class MediaItem
{
public string ID { get; set; }
public string Name { get; set; }
public string MediaType { get; set; }
public long Size { get; set; }
public string Language { get; set; }
public string IsPublished { get; set; }
public string MediaPath { get; set; }
public string IsLinked { get; set; }
// Grouping & UI helpers
public bool IsGroupHeader { get; set; }
public bool IsExpanded { get; set; }
public int LinkedItemsCount { get; set; }
public List<MediaItem> LinkedItems { get; set; }
}
This model supports grouping and expand/collapse behavior in the UI.
Step 2: Fetch Media Usage Data (Performance First)
Avoid traversing the content tree at runtime. Instead, fetch media usage via a stored procedure.
DataSet ds = masterDatabase.ExecuteDataSet(
"storeProcedure",
masterDatabase.CreateParameter("@par1", SqlDbType.NVarChar, par1),
masterDatabase.CreateParameter("@par2", SqlDbType.NVarChar, par2),
masterDatabase.CreateParameter("@par3", SqlDbType.NVarChar, par3)
);
Why stored procedures?
- Faster execution
- Cleaner C# code
- Easy to optimize later
- Scales well for large media libraries
Step 3: Map Raw Data to Strongly Typed Objects
var mediaItems = ds.Tables[0].AsEnumerable()
.Select(row => new MediaItem
{
ID = row["ID"].ToString(),
Name = row["Name"].ToString(),
MediaType = row["Extension"].ToString(),
MediaPath = row["MediaPath"].ToString(),
IsLinked = row["LinkedStatus"].ToString()
})
.ToList();
This makes filtering, grouping, and exporting far easier.
Step 4: Group Media by Usage
Multiple pages can reference the same media item. Instead of showing duplicates, group them.
private List<MediaItem> GroupMediaItems(List<MediaItem> items)
{
return items
.GroupBy(x => x.ID)
.Select(group =>
{
var header = group.First();
header.IsGroupHeader = true;
header.LinkedItemsCount = group.Count();
header.LinkedItems = group.ToList();
return header;
})
.ToList();
}
This enables:
- Expand / collapse UI
- Clean presentation
- Faster scanning for editors
Step 5: Filtering & Search
var filtered = mediaItems
.Where(x => x.Name.ToLower().Contains(searchText))
.Where(x => status == "All" || x.IsLinked == status)
.Where(x => type == "All" || x.MediaType == type)
.ToList();
This works seamlessly with pagination.
Step 6: Server-Side Pagination
var pagedItems = filtered
.Skip(currentPage * pageSize)
.Take(pageSize)
.ToList();
Server-side pagination ensures:
- Consistent performance
- Minimal memory usage
- Smooth UX even with thousands of items
Step 7: Expand / Collapse Linked Items
Track expanded rows using ViewState.
bool isExpanded = expandedIds.Contains(mediaItem.ID);
mediaItem.IsExpanded = isExpanded;
Nested repeaters display linked pages only when expanded.
Step 8: Export to Excel (EPPlus)
using (var package = new ExcelPackage())
{
var sheet = package.Workbook.Worksheets.Add("Media Usage");
sheet.Cells[1, 1].Value = "Media Name";
sheet.Cells[1, 2].Value = "Type";
sheet.Cells[1, 3].Value = "Linked Status";
int row = 2;
foreach (var item in mediaItems)
{
sheet.Cells[row, 1].Value = item.Name;
sheet.Cells[row, 2].Value = item.MediaType;
sheet.Cells[row, 3].Value = item.IsLinked;
row++;
}
package.SaveAs(response.OutputStream);
}

Why This Approach Works
✔ Fast (DB-driven) ✔ Scalable ✔ Editor-friendly ✔ Production-safe ✔ Easy to extend (delete unused media, bulk actions, etc.)
Final Thoughts
This Media Usage dashboard has become one of the most useful internal tools in our Sitecore projects. It dramatically improves content governance and editor confidence.
If you’re working with Sitecore XM 10, I highly recommend implementing something similar.
Happy Sitecore-ing
메타데이터
- post_id
- cd85bdf69fe3
- slug
- building-a-media-usage-orphan-tracking-dashboard-in-sitecore-xm-10-cd85bdf69fe3
- url
- https://medium.com/@drs231999/building-a-media-usage-orphan-tracking-dashboard-in-sitecore-xm-10-cd85bdf69fe3
- canonical_url
- https://medium.com/@drs231999/building-a-media-usage-orphan-tracking-dashboard-in-sitecore-xm-10-cd85bdf69fe3
- author_url
- https://medium.com/@drs231999
- status
- ok
- fetched_at
- 2026-07-17 04:32:30