Skip to content

Dynamics 365 Audit History Is Buried, Not Broken - A Before and After Fix With an Inline PCF Control

Dataverse auditing captures everything, but Microsoft hides it behind Related > Audit History. Here is the inline PCF fix that puts field history on the form.

Alex Pechenizkiy 9 min read
Dynamics 365 Audit History Is Buried, Not Broken - A Before and After Fix With an Inline PCF Control

Open the record. Click Related. Scroll the dropdown to find Audit History. Scan a flat chronological list of every change ever made to the record, hunting for the one field you care about. That is the click path for Dynamics 365 audit history today, and any reader with a Dynamics environment can count it themselves.

The people paying that tax are not admins. They are support agents mid-ticket who need to know whether a credit limit changed before or after the complaint came in. Compliance reviewers reconstructing a sequence of edits across three fields. Sales ops managers chasing who moved the close date on an opportunity.

Here is the position this article takes: the audit data is fine. Dataverse captures changes with full fidelity, and Microsoft’s data layer has nothing wrong with it. The consumption surface is the gap. And admins do not have to accept it, because surfacing field-level history inline on the form is a solvable problem. I solved it with a free PCF control I built called FieldAuditHistory, and this article walks through the before, the after, and exactly how to deploy the pattern.

Why a flat audit log fails field-level questions

Users never ask “what happened to this record.” They ask “what happened to this field.” Who changed the discount? When did the status flip? What was the phone number before someone overwrote it?

The native Audit History view answers the record-scoped question. It presents every audited change to the record in reverse chronological order. If the record is three years old and heavily edited, the answer to your field-scoped question is buried in dozens of entries about other fields. The mismatch between the question users ask and the answer the view gives is the entire problem.

Watch what that mismatch produces in practice. Screenshots of the audit grid pasted into support tickets because nobody trusts the other party to find the view. Audit logs exported to Excel so someone can filter by column name. Escalations to the system admin for a question the form itself should answer.

One more caveat worth honoring: Dataverse auditing tracks changes, not reads. Microsoft’s own documentation states that “the auditing feature is designed to meet the external and internal auditing, compliance, security, and governance policies that are common to many enterprises” (Manage Dataverse auditing). Access logging is a Purview concern. Do not conflate the two when scoping a compliance requirement.

The takeaway: the flat log is a record-scoped answer to a field-scoped question, and every workaround your users invent is evidence of that gap.

The after: FieldAuditHistory and its design decisions

FieldAuditHistory is a free PCF control I built to close that gap. No public repository or marketplace listing exists at the time of writing, so treat every feature description here as author-described behavior of my own build, not a claim you can independently verify yet. The control does exactly four things, and each one maps to a specific pain from the opening.

Inline indicators. Fields with audit history get a visible marker directly on the form. This kills the discoverability problem outright. Users no longer need to know that Audit History exists or where it lives. The history announces itself where people already look.

Quick peek. Hovering or clicking the indicator shows the most recent change: who, when, old value, new value. This is the support-agent-mid-ticket case. The agent gets the answer without leaving the form, without losing the ticket context, without a Related-menu expedition.

Deep dive. When the quick answer is not enough, the control opens the full field-level change history. This is the compliance-reviewer case: the complete before-and-after lineage of one field, not the interleaved history of forty.

Per-table configuration. Admins decide which tables and forms get the control. Not every form needs audit indicators, and a control that admins cannot scope is a control admins will not install. Footprint control is a feature, not a limitation.

Why a PCF control rather than an embedded canvas app or a separate page? Because this is model-driven app custom UI done the way Microsoft designed it to be done. Microsoft Learn describes the framework plainly: “Power Apps component framework empowers professional developers and app makers to create code components for model-driven and canvas apps” (Power Apps component framework overview). A PCF control lives inside the form’s rendering pipeline, respects the form’s security context, and binds to the field it decorates. A canvas embed or a separate page reintroduces the exact context switch the control exists to eliminate.

Clicks to an answer
Native path (Related > Audit History)
Open record, Related, Audit History, scan the list
Inline control on the form
The indicator is already on the field; one click for the peek
What the user sees
Native path (Related > Audit History)
Flat chronological list of all record changes
Inline control on the form
History scoped to the one field in question
Question it answers
Native path (Related > Audit History)
What happened to this record
Inline control on the form
What happened to this field
Who it works for
Native path (Related > Audit History)
Admins and trained users with time to dig
Inline control on the form
Anyone who can see the form
Discoverability
Native path (Related > Audit History)
Requires knowing the feature exists
Inline control on the form
Visible indicator at the point of need

One honest constraint: the control is a presentation layer over native audit data. It creates nothing. If auditing is not enabled for the environment, the table, and the column, there is nothing to show. User permissions still gate what history is visible. And a form carpeted with indicators adds load cost, which is exactly why per-table configuration exists.

The takeaway: every feature of the control is a direct answer to a documented pain, and anything that is not an answer to a pain stayed out of the control.

PCF best practices: built AI-first, tested like it matters

I built FieldAuditHistory with an AI-first workflow: AI agents handled scaffolding and iteration loops, and I reviewed and directed the output. I have written about that working style before in my agentic development workflow for Power Platform, and this control followed the same spec-driven approach rather than vibe-coding against a blank editor.

But the part that matters for anyone evaluating a third-party control is not how fast it was built. It is that automated tests validate the rendering of audit data. When a control’s entire job is displaying who changed what and when, trust is the product. A control that misrenders an old value is worse than no control at all, because users will act on wrong history with full confidence.

That is the baseline I hold any PCF control to before it touches production: automated tests around the data it displays, and clean packaging. Speed of development is a builder’s concern. Correctness of display is the user’s concern, and only one of those belongs in a sales pitch.

The takeaway: for controls that surface audit data, testing is not a best practice. It is the minimum.

Shipping as a managed solution

FieldAuditHistory ships as a managed solution, and that choice is for the evaluating admin, not for me. Microsoft’s ALM documentation is unambiguous about the pattern: “Managed solutions are used to deploy to any environment that isn’t a development environment for that solution” (Solution concepts). Managed means a clean install, a clean uninstall, and no component sprawl left behind in your production environment.

Here is the practitioner caveat: unmanaged components feel faster during development, and they are. But unmanaged components accumulate in production environments like sediment. They cannot be cleanly removed, they tangle with other customizations, and they make rollback a forensic exercise instead of a button click. Managed is the right default for anything distributed beyond the environment it was built in.

Packaging discipline is part of trusting a third-party control. If a vendor ships you an unmanaged solution for production, that tells you something about the rest of their engineering.

How to deploy the pattern

Here is the implementation path, from an empty environment to a validated inline control. The audit-enablement steps apply whether you use my control or build your own.

  1. 1

    Verify prerequisites

    You need system administrator or system customizer privileges, a Dataverse environment, and a clear list of which tables and columns actually need field-level history. Resist auditing everything. Audit data consumes capacity.

  2. 2

    Enable auditing at all three levels

    Dataverse auditing is opt-in and cascading: the environment setting, the table setting, and the column setting must all be on. Miss any one and nothing is captured. Nothing is captured retroactively either, so enable auditing before you need the history, not after.

  3. 3

    Check retention and permissions

    Confirm your audit retention policy matches your compliance window, and confirm which security roles can read audit data. The control respects Dataverse permissions. It cannot show a user history they are not entitled to see.

  4. 4

    Import the managed solution

    Import the control's managed solution into a sandbox first, never straight into production. Verify the solution contents match what you expect: the control and its configuration, nothing else.

  5. 5

    Configure the control per table

    Add the control to the forms where field-level questions actually arrive. Start narrow: the two or three tables your support and ops teams complain about. Expand from evidence, not ambition.

  6. 6

    Validate before rollout

    Make a test change to an audited field, confirm the indicator appears, confirm the quick peek shows the correct old and new values, and confirm a user without audit privileges sees nothing they should not. Check form load time on your heaviest form with the control enabled.

Before production, run the same evaluation you would on any third-party component: confirm what APIs the control calls, confirm it requests no privileges beyond reading audit data, and confirm you can uninstall it cleanly from the sandbox. The same scrutiny applies to any component that touches Dataverse security context, a topic I covered in depth in Can You Trust AI With Dataverse Security? - the perimeter is only as good as the components you let inside it.

The takeaway: the control is the easy part. Audit enablement, retention, and permissions are where deployments actually go wrong.

What changed for users

These walkthroughs are illustrative. They describe the intended usage pattern, not measured outcomes from any deployment.

The support agent. Before: a customer disputes a changed credit limit, the agent opens the account, clicks Related, finds Audit History, scrolls past two years of unrelated edits. After: the indicator sits on the credit limit field, one click shows who changed it and when, and the agent answers inside the same breath of the ticket.

The compliance reviewer. Before: reconstructing the edit sequence on a regulated field means exporting the audit grid and filtering in Excel. After: the deep dive view shows that one field’s full lineage, in order, with old and new values side by side.

The sales ops manager. Before: “who moved the close date” is a Teams message to an admin. After: it is a glance at the form.

Illustrative or not, the structural point stands on its own. Nothing about the underlying data changed in the after column. Dynamics 365 audit history was capturing every one of those changes all along. The control moved the answer from where admins keep it to where users look for it.

That is the pattern worth carrying beyond this one control. The fix for a “missing feature” is sometimes surfacing a feature that already exists. Dataverse hides a surprising amount of useful data behind the Related menu, and every one of those menus is a candidate for the same treatment: a small, focused, well-tested piece of custom UI that closes the distance between where the data lives and where the question gets asked. Audit history was never the problem. Its placement was.

Want this for your Dynamics 365 app?

Tell me which screens or steps slow your team down. I read every message and reply personally with what I would fix first, and whether it is a maker fix, a custom page, or a PCF control.

Stay in the loop

Get new posts delivered to your inbox. No spam, unsubscribe anytime.

Related articles