Is it possible to use API to get session relevance results?

Hello everyone,

I hope you’re all doing well.

I’d like to know if anyone here has experience using Session Relevance to retrieve all actions executed over a long period (for example, a full month).

Currently, I’m building a way to easily query and audit actions in my BigFix environment, regardless of the operator. I managed to get this working through the Presentation Debugger, and I’m quite satisfied with the results. I was able to export the data and convert it to an XLSX file without any issues.

However, my main goal is to take this a step further and automate the process — ideally generating this report on a recurring basis (weekly, biweekly, or monthly).

So my questions are:

  • Is it possible to automate this kind of Session Relevance query?

  • What approaches would you recommend for scheduling and exporting the results regularly?

Below is the relevance I’m currently using:

("Action ID,Parent ID,Type,Source Site,Issued By,Time Issed,Action State,Action Name,Computer Name,OS,All Target Groups,Status,Start Time,End Time,Exit Code";
("%22" & (id of action of it as string | "") & "%22," &
 "%22" & (if (exists parent group of action of it) then (id of parent group of action of it as string) else "-") & "%22," &
 "%22" & (if (exists parent group of action of it) then "Baseline Component" else if (exists member actions of action of it) then "Baseline (Parent)" else "Single Action") & "%22," &
 "%22" & (if (exists source fixlet of action of it) then (name of site of source fixlet of action of it) else "Custom/ActionSite") & "%22," &
 "%22" & (name of issuer of action of it | "Unknown") & "%22," &
 "%22" & (time issued of action of it as string | "") & "%22," &
 "%22" & (state of action of it as string | "") & "%22," &
 "%22" & (name of action of it | "") & "%22," &
 "%22" & (name of computer of it | "") & "%22," &
 "%22" & (operating system of computer of it | "Unknown") & "%22," &
 "%22" & (concatenation "; " of names of bes computer groups of computer of it) & "%22," &
 "%22" & (status of it as string | "") & "%22," &
 "%22" & (start time of it as string | "-") & "%22," &
 "%22" & (end time of it as string | "-") & "%22," &
 "%22" & (exit code of it as string | "-") & "%22")
 of results of bes actions
 whose (time issued of it >= ("01 Feb 2026 00:00:00 -0300" as time)
   AND time issued of it <= ("28 Feb 2026 23:59:59 -0300" as time)))

Any insights, best practices, or even alternative approaches would be greatly appreciated.

Thanks in advance!

Short answer, yes! The /api/query REST API resource can be used here (https://developer.bigfix.com/rest-api/api/query.html).

There are a few considerations here such as whether or not you're leveraging BigFix Explorer and also the desired output format (you have the ability to request a JSON output rather than XML even without BigFix Explorer).

You could convert this to a relevance expression so it dynamically uses the fist and last date of the current month (have to check that rollover in December works too)

whose (time issued of it >= (((day_of_month 1 & current month_and_year) as string & " 00:00:00") as universal time)
AND time issued of it <= (((day_of_month 1 & (current month_and_year + 1 * month) - 1 * day) as string & " 00:00:00") as universal time)))

2 Likes

Here you go .

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>BigFix Action Deployment Report</title>
    <style>
        :root { 
            --hcl-blue: #005EB8; 
            --bg-app: #f4f5f7; 
            --text-primary: #1e293b; 
            --border-light: #e2e8f0; 
        }
        body { font-family: 'Inter', sans-serif; margin: 0; background-color: var(--bg-app); color: var(--text-primary); }
        .app-layout { display: flex; height: 100vh; flex-direction: column; }
        
        /* Navbar */
        .navbar { height: 60px; background: #fff; border-bottom: 1px solid var(--border-light); display: flex; align-items: center; padding: 0 32px; font-weight: 700; font-size: 18px; }
        
        .content-container { flex: 1; overflow: hidden; display: flex; flex-direction: column; }
        .header { padding: 20px 32px; }
        
        /* Table Container - Allow horizontal scroll */
        .card { 
            background: #fff; 
            margin: 0 32px 24px 32px; 
            padding: 0; 
            border-radius: 8px; 
            border: 1px solid var(--border-light); 
            overflow: auto; /* Enables scrolling */
            flex: 1;
        }

        table { width: 100%; border-collapse: collapse; font-size: 12px; white-space: nowrap; }
        th { 
            text-align: left; 
            background: #f8fafc; 
            padding: 12px 16px; 
            border-bottom: 2px solid var(--border-light); 
            color: #64748b; 
            position: sticky;
            top: 0;
            z-index: 10;
        }
        td { padding: 10px 16px; border-bottom: 1px solid var(--border-light); }
        tr:hover { background-color: #f1f5f9; }
        
        .status-badge {
            padding: 2px 8px;
            border-radius: 12px;
            font-size: 11px;
            font-weight: 600;
            background: #e2e8f0;
        }
        .status-fixed { background: #dcfce7; color: #166534; }
        .status-failed { background: #fee2e2; color: #991b1b; }

        #loading { padding: 40px; text-align: center; color: var(--hcl-blue); }
    </style>
</head>
<body>
    <div class="app-layout">
        <div class="navbar">HCL BigFix Inventory</div>
        <main class="content-container">
            <div class="header">
                <div style="font-size: 22px; font-weight: 600;">Action Deployment History</div>
                <div style="font-size: 12px; color: #64748b; margin-top: 4px;" id="timestamp">Reporting Period: Feb 2026</div>
            </div>
            
            <div class="card">
                <div id="loading">Gathering action results...</div>
                <table id="results-table" style="display: none;">
                    <thead>
                        <tr id="table-head-row">
                            </tr>
                    </thead>
                    <tbody id="table-body"></tbody>
                </table>
            </div>
        </main>
    </div>

    <script>
        // Your provided Relevance
        const actionRelevance = `("Action ID,Parent ID,Type,Source Site,Issued By,Time Issued,Action State,Action Name,Computer Name,OS,All Target Groups,Status,Start Time,End Time,Exit Code"; ("%22" & (id of action of it as string | "") & "%22,%22" & (if (exists parent group of action of it) then (id of parent group of action of it as string) else "-") & "%22,%22" & (if (exists parent group of action of it) then "Baseline Component" else if (exists member actions of action of it) then "Baseline (Parent)" else "Single Action") & "%22,%22" & (if (exists source fixlet of action of it) then (name of site of source fixlet of action of it) else "Custom/ActionSite") & "%22,%22" & (name of issuer of action of it | "Unknown") & "%22,%22" & (time issued of action of it as string | "") & "%22,%22" & (state of action of it as string | "") & "%22,%22" & (name of action of it | "") & "%22,%22" & (name of computer of it | "") & "%22,%22" & (operating system of computer of it | "Unknown") & "%22,%22" & (concatenation "; " of names of bes computer groups of computer of it) & "%22,%22" & (status of it as string | "") & "%22,%22" & (start time of it as string | "-") & "%22,%22" & (end time of it as string | "-") & "%22,%22" & (exit code of it as string | "-") & "%22") of results of bes actions whose (time issued of it >= ("01 Feb 2026 00:00:00 -0300" as time) AND time issued of it <= ("28 Feb 2026 23:59:59 -0300" as time)))`;

        function loadData() {
            try {
                const evalFn = (typeof EvaluateRelevance !== 'undefined') ? EvaluateRelevance : (window.parent && window.parent.EvaluateRelevance);
                
                if (!evalFn) {
                    document.getElementById('loading').innerText = "Dashboard must be run within the BigFix Console.";
                    return;
                }

                const rawData = evalFn(actionRelevance);
                if (!rawData || rawData.length < 2) {
                    document.getElementById('loading').innerText = "No action results found for this period.";
                    return;
                }

                // First row is the header string from Relevance
                const headerLabels = rawData[0].split(',');
                renderHeaders(headerLabels);

                // Subsequent rows are data. We strip the surrounding %22 (quotes)
                const dataRows = rawData.slice(1).map(row => {
                    // Remove leading/trailing quotes and split by ","
                    return row.replace(/^"|"$/g, '').split('","');
                });

                renderTable(dataRows);

                document.getElementById('loading').style.display = 'none';
                document.getElementById('results-table').style.display = 'table';
            } catch (err) {
                document.getElementById('loading').innerText = "Error: " + err.message;
            }
        }

        function renderHeaders(headers) {
            const headRow = document.getElementById('table-head-row');
            headRow.innerHTML = headers.map(h => `<th>${h}</th>`).join('');
        }

        function renderTable(data) {
            const tbody = document.getElementById('table-body');
            tbody.innerHTML = data.map(row => {
                return `<tr>${row.map((cell, index) => {
                    // Special formatting for Status column (index 11)
                    if (index === 11) {
                        const statusClass = cell.toLowerCase().includes('fixed') ? 'status-fixed' : 
                                            (cell.toLowerCase().includes('failed') ? 'status-failed' : '');
                        return `<td><span class="status-badge ${statusClass}">${cell}</span></td>`;
                    }
                    // Bold the Action ID and Computer Name
                    if (index === 0 || index === 8) return `<td style="font-weight:600">${cell}</td>`;
                    return `<td>${cell}</td>`;
                }).join('')}</tr>`;
            }).join('');
        }

        window.onload = loadData;
    </script>
</body>
</html>

Use the following link link to schdeule the report.

3 Likes

Have you tried that with the report scheduler? I really like the style of your report, it looks like good clean code. But, when the Web Reports scheduler runs I'm not entirely sure that it triggers the window.onload event, it might save the the report with empty data.

Hey, just a little heads up - I tried to run this report on my environment, and I noticed that the Time Issued was not giving the right dates.