Content Item Report with Sitecore API

Working with items

I have interacted with Sitecore customers where some of their needs on Sitecore reports have been similar: to have a tabular report tool. Whether it’s for checking content item inventory, a clean-up analysis, or identifying when it was last updated and by whom. There’s already several ways to create a report like this, with external Sitecore modules such as Sitecore Powershell Extensions. But for the curious developer, a good Sitecore API practice comes in handy and can help us exercise our minds on how to solve this need with a simple utility ASPX page, where a Sitecore power user can get access to it and use it in a simplistic way.

Exercise requirements

1. Data needs to come from the database, not from the Sitecore index

2. The utility page must ask:

  • From what database it should read the data
  • What is the Sitecore root item path, from where it should start looking Sitecore items
  • The path of the item’s template it inherits from

3. Export the data in CSV format

4. No code behind, for easy push/deployment to any environment without impacting its operation


<%@ Page language="C#" EnableEventValidation="false" AutoEventWireup="true" EnableViewState="true" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="Sitecore" %>
<%@ Import Namespace="Sitecore.Data" %>
<%@ Import Namespace="Sitecore.Data.Items" %>
<%@ Import Namespace="Sitecore.Data.Fields" %>
<!DOCTYPE html>

<script runat="server">

protected void btnExport_Click(object sender, EventArgs e)
        var database = Sitecore.Data.Database.GetDatabase(databaseName.Text);
        var rootItem = database.GetItem(sitecorePathText.Text);
        if (rootItem == null)
            results.Text = "Root item not found";

        var items = rootItem.Axes.GetDescendants();
             Sitecore.Data.Templates.Template templateItem = Sitecore.Data.Managers.TemplateManager.GetTemplate(templateName.Text, database);
        if (templateItem == null)
            results.Text = "Filter template not found";
        var filteredItems = items.Where(item => item.DescendsFrom(templateItem.ID));
        var fields = templateItem.GetFields(true).ToList();
        var exportedText = new System.Text.StringBuilder();               

        //exporting headers
        exportedText.Append("Item full path");
        foreach (Sitecore.Data.Templates.TemplateField field in fields)
            exportedText.Append("," + field.Name);

        foreach (Item filteredItem in filteredItems)
            foreach (Sitecore.Data.Templates.TemplateField field in fields)
                exportedText.Append("," + PreFormatCSVValue(filteredItem.Fields[field.ID].Value));
             results.Text = string.Empty;
        SaveToCsvFile(exportedText.ToString(), templateName.Text + " items report");
    catch (Exception ex)
        results.Text = ex.Message + Environment.NewLine + ex.StackTrace;

private string PreFormatCSVValue(string value)
       if (!string.IsNullOrEmpty(value) && value.IndexOf(",") >= 0)
             return "\"" + value + "\"";
       return value;

private void SaveToCsvFile(string contents, string fileName)
    Response.ContentType = "text/csv";
    Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName + ".csv");


<html lang="en">
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Content Item Report</title>
  <link href="" rel="stylesheet"
    integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    main { padding: 1rem; }
    form { max-width: 1024px; }
      <h3>Content Item Report</h3><br />
      <form runat="server" id="exportForm">
        <div class="mb-3">
          <label for="databaseName" class="form-label"><b>Database name:</b> <span class="small">(can be core, master or web!)</span></label>
          <asp:TextBox CssClass="form-control" ID="databaseName" runat="server" Columns="120" TextMode="SingleLine" Text="master" />
        <div class="mb-3">
          <label for="sitecorePathText" class="form-label"><b>Sitecore root path:</b> <span class="small">(you can use Sitecore IDs with curly brackets ({}) too!)</span></label>
          <asp:TextBox CssClass="form-control" ID="sitecorePathText" runat="server" Columns="120" TextMode="SingleLine" Text="" />
        <div class="mb-3">
          <label for="templateName" class="form-label"><b>Template FULL name filter:</b> <span class="small">(Template path, without "/sitecore/templates/")</span></label>
          <asp:TextBox CssClass="form-control" ID="templateName" runat="server" Columns="120" TextMode="SingleLine" Text="System/Templates/Standard template" />
        </div><br />
        <asp:Button ID="btnExport" CssClass="btn btn-primary" Text="Export to CSV" runat="server" OnClick="btnExport_Click" />
      </form><br />
      <div class="mb-3">
        <asp:Literal ID="results" runat="server" Text=""></asp:Literal>
<script src=""
  integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous">

We set up all this code in an ASPX page, and we drop it into /Sitecore/admin folder on our Sitecore instance and test it:


This is just the tip of the iceberg in terms of report functionality, as there are many areas of improvement! But we’ll get into that in another post.

Happy coding!