
Salesforce tells us when someone changes the org. The problem is that this information is not always easy to understand.
If a Flow is activated, a permission is changed, a field is deleted, or a package is deployed, Salesforce adds an entry to Setup Audit Trail. This is useful, but the entries are mostly shown as a long technical list. During a release or production issue, it can take time to answer a simple question:
What changed in the org?
I built WhatChanged to make this easier.
WhatChanged is a native Salesforce application that reads Setup Audit Trail and turns the raw entries into a clean dashboard, timeline, and set of useful insights. It helps Salesforce architects, admins, developers, and DevOps teams understand recent configuration activity without exporting the data to another system.
In this post, I will explain why I built it, how it works, the architecture behind it, and how you can deploy it to a Salesforce org.
The problem with Setup Audit Trail
Setup Audit Trail is important. I often use it when I need to investigate a production issue or check what happened after a deployment or who changed things in lower environments.
But I normally face a few problems:
- The action names can be technical and difficult to read quickly.
- Related changes appear as separate entries.
- It is hard to see which area of the org had the most activity.
- High-risk access or security changes are mixed with normal changes.
- Finding everything that happened around an incident takes manual filtering.
- It is not easy to compare today’s activity with normal activity.
Imagine that an automation stops working at 3:15 PM. You may want to know whether someone deactivated a Flow, changed a field, updated a permission, or completed a deployment around that time.
The information exists, but finding the story behind it takes effort.
My goal with WhatChanged was simple: keep Setup Audit Trail as the source of truth, but present it in a way that is easier for people to understand.
What does WhatChanged provide?
The application has five main areas.
1. Overview dashboard
The Overview page gives a quick summary of recent activity. It shows:
- Total changes for the selected period
- Automation changes
- Access and user changes
- High-interest changes
- Hourly activity
- Category breakdown
- Recent changes
- Items that may need attention
For the default Today view, it also compares the activity with the same weekday from previous weeks. This gives the user some context. For example, 40 changes may be normal on a release day but unusual on a quiet day.

2. Change timeline
The Timeline page shows the normalized audit events in date order.
Users can filter by:
- Date range
- Category
- Severity
- Person
- Setup section
- Search text
The application converts technical actions into simpler titles such as “Flow activated”, “Permission Set updated”, or “Custom Field created”. The original audit text is still available in the event details.

3. Incident mode
Incident mode is one of my favourite features.
The user selects a date, time, and a window such as 30 minutes. WhatChanged then shows the configuration activity around that moment.
This is helpful when investigating questions like:
- What changed just before the problem started?
- Was there a deployment at that time?
- Did someone update a permission or security setting?
- Was a Flow activated or deactivated?
It does not prove that a change caused the issue, but it gives the support team a much better place to start.
4. Insights
The Insights page shows patterns over 7 or 30 days. It includes:
- Daily change volume
- Activity by hour
- Category distribution
- Severity distribution
- Most active setup sections

5. People view
The People page shows who has been making changes and the areas where they are most active.
This is not designed to judge individuals. It is an operational view that can help a team understand whether activity came from an admin, a developer, or an automation user.

How the application is built
WhatChanged uses a simple layered architecture.
Salesforce user ↓React application hosted as a Salesforce UI Bundle ↓Salesforce Platform Data SDK ↓Apex REST API ↓Security and service layer ↓Normalization and classification ↓SetupAuditTrail
There is no separate web server or application database. The application runs on Salesforce and reads the audit data when the user opens or refreshes a view.
Let us look at each part.
React frontend using Salesforce Multi-Framework
The user interface is built with:
- React
- TypeScript
- Vite
- Tailwind CSS
- Salesforce Platform SDK
Instead of hosting the React application outside Salesforce, it is deployed as a Salesforce UIBundle and connected to a Custom Application.
This means users can open WhatChanged from the Salesforce App Launcher like any other Salesforce app.
The frontend is divided into feature folders for Overview, Timeline, Insights, People, and Event Details. React hooks handle data loading, filters, refresh, theme, and pagination.
The active page refreshes every 60 seconds while the browser tab is visible. Only the visible page is refreshed, so the application does not make four API requests every minute when the user only needs one view.
For local development, the application uses sample data. A clear Demo Mode banner is shown, so users can see that the data is not from a live Salesforce org.
Apex REST API
The frontend calls a versioned Apex REST API:
/services/apexrest/what-changed/v1/summary/services/apexrest/what-changed/v1/events/services/apexrest/what-changed/v1/people/services/apexrest/what-changed/v1/insights
I used Apex REST because it gives the application one clear place for security, request validation, business logic, and error handling.
The main Apex classes are:
WhatChangedApi— receives and routes API requestsWhatChangedSecurity— checks whether the user can access the applicationWhatChangedAuditService— calculates metrics, applies filters, and builds the responseWhatChangedAuditRepository— queries Setup Audit TrailWhatChangedEventNormalizer— creates readable titles and descriptionsWhatChangedClassifier— assigns category and severityWhatChangedDtos— defines the JSON response structureWhatChangedSettings— reads configuration from Custom Metadata
Keeping these responsibilities separate made the code easier to test and maintain.
Turning raw events into useful information
A Setup Audit Trail record contains fields such as action, section, display text, user, namespace, and date.
The normalizer converts the raw record into an event that the UI can use. It creates:
- A readable title
- A simple description
- Actor details
- Category and severity
- Component information when it can be identified
- Search terms
The classifier uses deterministic rules. It does not use AI or send data to an external service.
Every event is placed into one of 11 categories:
- Deployment
- Automation
- Access
- Security
- Data Model
- Code
- UI
- Integration
- User Administration
- Configuration
- Other
It also receives one of five severity levels: Info, Low, Medium, High, or Critical.
These labels help the user focus on important activity without hiding the original Salesforce audit information.
Making the rules configurable
Not every company looks at risk in the same way.
For one company, a data export may be critical. For another company, frequent deployments from a CI user may be expected and can be shown as informational.
To support this, WhatChanged includes a Custom Metadata type for classification rules. A rule can match text in the action, section, or display value and then set the required category and severity.
There is also a settings Custom Metadata type for values such as:
- Access activity threshold
- Automation activity threshold
- Aggregate sample size
- Maximum scan iterations
- Optional custom classifier strategy
This allows important behaviour to be changed without editing the main service code.
Security model
Security was an important part of the design because audit history can show sensitive configuration activity.
The application follows these rules:
- Salesforce handles user authentication.
- WhatChanged does not store an OAuth token, password, or client secret.
- Every API request checks access on the server.
- The
WhatChanged_AccessCustom Permission controls application access. - The
WhatChanged_UserPermission Set provides the app, Apex class, and Custom Permission access. - Users must also have the approved Salesforce permission needed to read Setup Audit Trail.
- Apex classes use
with sharing. - SOQL filters use bind variables.
- The application has no create, update, or delete API.
- The application does not make outbound Apex callouts.
In short, this is a read-only application. It explains changes but cannot make changes to the org.
Handling Salesforce query limits
This was one of the most interesting technical parts of the project.
Setup Audit Trail does not support every filter and grouping operation that we normally use with Salesforce objects. For example, some text fields cannot be filtered in SOQL, and the object does not support the required GROUP BY queries.
I handled this in a few ways:
- Date and user filters are applied in SOQL when possible.
- Other filters are applied in Apex after the records are normalized.
- Event pages use keyset pagination based on date and record ID instead of
OFFSET. - Every request has page, row, and scan limits to protect Apex governor limits.
- Exact totals and daily counts use
COUNT()queries. - Category, severity, hour, section, and contributor summaries use a bounded sample for busy periods.
This last point is important. The dashboard is built for operational understanding, not compliance reporting. Total event counts and daily counts are exact. Some detailed breakdowns may be estimated from the most recent sample when an org has a large number of audit records.
Change stories
A single activity can create many Setup Audit Trail entries. For example, a developer may deploy a set of fields, permissions, and automation changes together.
WhatChanged can group multiple entries with the same actor name on the current page into a simple change story. This reduces some of the noise and gives the user a quick summary.
The story is only a helpful presentation. It is not a deployment record, and it does not prove that all grouped items belong to the same release.
Project structure
Here is a simplified view of the project:
force-app/main/default/├── applications/ Salesforce Custom Application├── classes/ Apex API, service, security, repository and tests├── customMetadata/ Default settings and example classification rules├── customPermissions/ WhatChanged_Access├── objects/ Custom Metadata type definitions├── permissionsets/ WhatChanged_User└── uiBundles/ └── whatChangedApp/ React and TypeScript application
How to deploy WhatChanged
You need Node.js, Salesforce CLI, and access to a Salesforce org that supports the UI bundle metadata used by the project.
Step 1: Clone the project
git clone https://github.com/arun12209/WhatChanged.gitcd WhatChanged
Step 2: Install the frontend dependencies
npm --prefix force-app/main/default/uiBundles/whatChangedApp install
Step 3: Build and test the React application
npm run testnpm run build
Step 4: Log in to Salesforce
sf org login web --alias my-salesforce-org
Step 5: Deploy the application
sf project deploy start \ --source-dir force-app/main/default \ --target-org my-salesforce-org \ --wait 30
Step 6: Assign the permission set
sf org assign permset \ --name WhatChanged_User \ --target-org my-salesforce-org
Also confirm that the user has your company’s approved permission to query Setup Audit Trail. The WhatChanged permission set does not add broad Salesforce setup permissions automatically.
After deployment, open the App Launcher and search for WhatChanged.
Current limitations
WhatChanged is an operational tool, and it has a few clear limits:
- It depends on Salesforce’s Setup Audit Trail retention.
- It does not provide long-term audit archiving.
- Some breakdowns are sample-based in high-volume periods.
- Incident mode has a bounded result size.
- Change stories are a simple grouping helper, not deployment correlation.
- It does not send alerts or automatically fix a problem.
If long-term, exact, compliance-level reporting is required, the next version would need a scheduled ingestion process and a governed data store.
Final result
WhatChanged started with a common question: What changed in my Salesforce org?
The final application gives teams a faster way to answer that question. It keeps Salesforce as the source of truth, uses a native Salesforce security model, and presents the audit information in a form that is much easier to investigate.
The project also shows how a React and TypeScript application can work with Apex REST inside Salesforce using the Multi-Framework UI bundle approach.
You can view the project and source code on GitHub.
If you build or extend something similar, I would be interested to know which Setup Audit Trail use cases are most useful for your team. Feel free to leave a comment below.
