One Customer Timeline Across Sales, Service and Marketing When the Systems Are Siloed
A technical guide to giving agents the full customer history: copy or read live, the interaction-event table, adapters per source, identity resolution, the timeline control and a Power BI single customer view.
You either copy customer interactions into one place or read them live from each system. For an agent-facing timeline where one legacy system has a broken API, copy: a lightweight interaction-event table in Dataverse beats a virtual table experiment, because the timeline then never waits on the weakest source. Design one event table with source system, source record ID, event type, timestamp, a customer key and a deep link back. Write to it through one adapter per source, using file drops or database reads where no API works. Resolve identity at capture with deterministic matching and a review queue, show the table in the timeline control, and demo a read-only Customer 360 in a month.
Why can agents not see the full customer history today?
Because each system records its own slice of the relationship and nothing joins them. Sales activity sits in the CRM, complaints and cases in a service tool, campaign responses in a marketing platform, orders or contracts in a legacy line-of-business system. Each has its own customer identifier, and the agent is expected to search all of them by name while the customer waits.
The visible symptoms are familiar: a complaint handled without knowing an order failed last week, a renewal call made in the middle of an open escalation, a marketing email sent to someone who asked to stop in a service call. Reports built across the systems disagree because each counts a different version of the customer. The fix is not another screen per system; it is one ordered history per customer that every channel writes into. If the problem is mainly that agents juggle many applications, composing one agent surface over them is covered in our guide to agent desktop unification. This page is about the history itself.
Should you copy interaction data into Dataverse or read it live from each system?
Read live when the source has a usable API with predictable latency, the data changes constantly, and you only need it on one form. Copy when the history must be fast, sortable across sources, reportable, and available when a source is down. A customer timeline almost always needs the second set of properties, and a legacy system with a broken API rules out the first.
Virtual tables are the live option in Dataverse. They present external data as a table in views, lookups and subgrids without copying it, through an OData v4 endpoint, one of the virtual connector providers, or a custom data provider you write. They are a good fit for a clean, well-indexed source. Every read goes to the source at query time, so the source latency becomes the form latency, and a source that times out or pages inconsistently produces an empty or partial timeline in front of the agent. Check current Microsoft documentation for which providers and capabilities are supported before planning on one.
| Question | Read live (virtual table or API call) | Copy (interaction-event table) |
|---|---|---|
| Does the source have a usable OData or REST API? | Required, with reasonable and stable response times. | Not required. Files, database reads or exports will do. |
| Must the timeline load when a source is down? | No. The panel fails with the source. | Yes. Events already captured still show. |
| Must events from several sources sort together? | Hard. Each source is queried separately. | Natural. One table, one timestamp column. |
| Is the history reported on in Power BI? | Awkward and slow against the source. | Straightforward from the same table. |
| How fresh must it be? | Current at the moment of reading. | As fresh as the adapter schedule or event trigger. |
| Where does detail live? | In the source, shown in place. | Summary in Dataverse, full detail through a deep link to the source. |
What should the interaction-event table look like?
Keep it thin. The event table is an index of what happened to a customer, not a second copy of every source system. Each row says which system, which record, what kind of event, when, for which customer, a short human summary, and where to click to see the detail. Full order lines, email bodies and call recordings stay in their systems.
The decision to make first is whether the table is an activity table. A custom table created as an activity table (a name such as Interaction Event) behaves like email, phone call and task: it has a Regarding lookup, participates in activity views, and can appear in the timeline control on contact and account forms alongside native activities. The activity setting has to be chosen when the table is created; it cannot be switched on later, so decide before the first solution import. If you create a regular table instead, it is usually shown as a related subgrid or a custom control beside the timeline rather than inside it. Verify the current timeline configuration options in Microsoft documentation, because they change with release waves.
| Column | Purpose | Notes |
|---|---|---|
| Source system | Which system produced the event. | A choice column, not free text, so filters and reports stay clean. |
| Source record ID | The identifier of the record in that system. | Stored exactly as the source gives it. |
| Event type | Order placed, complaint logged, campaign clicked, contract renewed. | A controlled list agreed with the business, per source. |
| Occurred on | When the event happened in the source. | Not when it was loaded. Keep a separate captured-on column for troubleshooting. |
| Customer key | Lookup to the contact or account, or the Regarding lookup on an activity table. | Set by identity resolution at capture, never by the agent. |
| Summary | One or two lines an agent can read at a glance. | No sensitive detail the agent is not allowed to see. |
| Deep link | URL back to the source record. | Opens the detail in the system of record. |
| Alternate key | Source system plus source record ID. | Makes every write an idempotent upsert, so a rerun or duplicate message updates rather than duplicates. |
How do adapters get events from each source into the table?
One adapter per source, each owning only the translation from that source into the event shape. Adapters never talk to each other, and a failing adapter stops only its own source. Every adapter writes with an upsert on the source system plus source record ID key, so replaying a day of events is safe.
For sources with a working API or change feed, a Power Automate cloud flow is often enough at modest volume, and Azure Functions or Logic Apps suit higher volume or heavier transformation. How we engineer flows with retries, error paths and service accounts is on our Power Automate consulting page. Where adapters need an outbox, backoff and dead-lettering, follow the patterns in point-to-point integration rationalisation rather than inventing new ones.
- API or webhook source: subscribe to events where the source can push, poll with a watermark where it cannot, and map each record to one or more event rows.
- Source with a broken or no usable API: read what it can produce reliably. A scheduled export file dropped to a monitored folder, or a read-only query against its database or reporting replica through the on-premises data gateway, is usually more dependable than a half-working API.
- Source with no export and no database access: a desktop flow reading screens is a last resort for low volume, with alerting, because screen changes break it silently.
- Every adapter records a run log: rows read, rows upserted, rows rejected and why, so silence is detectable.
- Backfill history once with the same adapter logic in bulk, then switch to incremental. Loading at volume is covered in our Dataverse bulk import guide.
How do you match events from different systems to the right customer?
Resolve identity at capture, once, deterministically, and never let the timeline guess. The adapter looks up the customer when it writes the event, using identifiers that cannot be ambiguous, and stores the result as the customer lookup. Fuzzy name matching at read time is how a complaint ends up on the wrong customer's history.
Hold a cross-reference table in Dataverse of external identifiers per customer: source system, external ID and the contact or account it belongs to. The adapter's first step is a lookup on that table. Deduplicate contacts and accounts before you start, because duplicates break resolution before any code does; our duplicate data cleanup guide covers the method. For marketing-led unification of profiles across many sources, Customer Insights - Data has its own identity resolution, described on our Customer Insights page.
- Match rule order: an existing cross-reference entry first, then exact matches on strong identifiers such as customer number, registration or VAT number, then a normalised email address. Stop at the first single match.
- Several candidates or none: write the event with no customer and put it on an unmatched queue for a person to resolve, rather than attaching it to the most likely record.
- When a person resolves an item, create the cross-reference entry, so the next event from that external ID matches automatically.
- When two contacts are merged, repoint the cross-reference entries and the events, and keep a log of the change.
- Monitor the unmatched queue size per source. A growing queue means a match rule or a source identifier has changed.
How does the timeline control show events from other systems?
With an activity table, events appear in the timeline on the contact or account form in date order next to emails, calls and notes, filtered by activity type like any other activity. Configure the timeline to include the new type, give the rows a clear subject line built from the summary, and make the deep link one click from the record. Check how your environment rolls up activities from related records, for example contact activities on the parent account, because that behaviour is configurable and has changed over releases.
Keep the timeline fast: index the customer lookup and occurred-on columns through normal Dataverse practice, show a sensible default date range, and archive or summarise very old events instead of loading decades of rows on every form open. Security applies as normal, so an agent sees only the event rows their role allows; decide at design time whether sensitive event types need their own ownership or column security. The Customer Service side of the agent experience is scoped on our Dynamics 365 Customer Service page.
How do you build a Power BI single customer view over the same data?
Report from the same event table and cross-reference, not from a separate integration. That way the agent's timeline and the board's Customer 360 count the same events for the same customers, and a disagreement means a data problem you can trace, not two pipelines with different rules.
Model the event table as a fact with customer, event type, source system and date dimensions. For anything beyond small volumes, report from an analytical copy of Dataverse, such as Azure Synapse Link for Dataverse or Link to Microsoft Fabric, rather than querying the transactional store directly; the reasons and the options are in our guide to Dynamics 365 reporting limits. Put the unmatched queue on the dashboard too. A Customer 360 that hides how many events could not be attributed will be trusted until the first time it is wrong.
How can you demo a Customer 360 to the board within a month?
By cutting scope, not corners. The first month proves the pattern end to end on a slice small enough to finish, and leaves the design unchanged for the next sources. Promise the board a working, read-only history for real customers, not a finished platform.
| Week | Deliverable | Scope limit |
|---|---|---|
| 1 | Event table (created as an activity table if you want native timeline display), cross-reference table, event type list and match rules agreed. | Two sources only: usually the CRM activity already in Dataverse plus the legacy system agents miss most. |
| 2 | Adapter for the second source, including the file or database route if its API is unusable, with run logging and upserts on the alternate key. | One customer segment, such as key accounts or one region. |
| 3 | Historical backfill for the segment, unmatched queue worked through, timeline configured on contact and account forms. | Read-only. No write-back to the source systems. |
| 4 | Power BI single customer view over the same tables, agent walkthrough, and a written list of the next sources in order. | No new source added this month, however tempting. |
Is Dataverse the right home for a unified customer history?
Usually, if your agents already work in Dynamics 365 or a model-driven app, because the timeline, security model and reporting routes are already there and the event table is a small addition. It is a weaker fit if no team works in Dynamics 365 and the only goal is analytics, in which case the events can land directly in an analytical store, or if licensing for the users who need the history does not fit.
We recommend the right solution - whether that's Microsoft Dynamics 365, Power Platform, or a custom-built CRM. Some businesses need the Microsoft ecosystem. Others need full control without licensing. We deliver both. Where Microsoft licensing does not suit the people who need the history, a custom-built CRM on React, Node.js, PostgreSQL or .NET can hold the same event model, adapters and identity rules under your own control.
Should your unified customer history live in Dynamics 365 or in a CRM you own outright?
Can afford licensing and want the Microsoft ecosystem
Dynamics 365
Microsoft 365, Teams and Outlook integration, a mature partner ecosystem, Copilot, and apps for sales, service and field operations that are configured rather than built.
Need full control and zero licensing
Custom CRM
A CRM built on React, Node.js, PostgreSQL or .NET that you own outright: your data model, your hosting, no per-user subscription, and features shaped exactly to your process.
Not sure which fits
We help you decide
A short discovery weighs licensing budget, process complexity, integrations and long-term ownership, then recommends one path. We deliver both, so the recommendation has no reason to lean.
How does Solzet help unify customer history across siloed systems?
We start with the two sources and the customer segment that matter most, agree the event types and match rules with the people who will rely on them, and build the event table, cross-reference, adapters, timeline configuration and Power BI view in that order. Every adapter is idempotent and logged, the unmatched queue has an owner, and the design is written down so your team can add the next source without us.
Solzet delivers remotely from Yerevan, Armenia, with senior consultants and full-stack developers and 8+ years of Dynamics 365 Customer Engagement and Power Platform work, directly or white-label for Microsoft partners.
What do people ask us?
Should we use virtual tables or copy data for a unified customer timeline?
Use virtual tables only when every source has a usable API with stable, low latency, because each read goes to the source when the form loads. When a legacy system has a broken or slow API, copy interactions into a thin interaction-event table in Dataverse instead. The timeline then loads from one table, sorts across sources, survives a source outage and can be reported on in Power BI.
What columns does an interaction-event table need in Dataverse?
Source system, source record ID, event type, the timestamp the event occurred, a customer lookup to the contact or account, a short summary and a deep link back to the source record. Add an alternate key on source system plus source record ID so every adapter write is an idempotent upsert, and a separate captured-on timestamp for troubleshooting.
Can an existing custom table be turned into an activity table later?
No. Whether a custom table is an activity table is set when the table is created and cannot be changed afterwards. If you want interaction events to appear in the timeline control like emails and phone calls, create the table as an activity table from the start. Otherwise you would need a new table and a data migration.
How do you get data out of a legacy system with no usable API?
Use whatever the system can produce reliably. A scheduled export file to a monitored folder, or a read-only query against its database or reporting replica through the on-premises data gateway, is usually more dependable than a failing API. A desktop flow reading screens is a last resort for low volumes. Whatever the route, the adapter upserts on the source key and logs every run.
How do you link events from different systems to the same customer?
Resolve identity when the event is captured, not when the timeline is read. Keep a cross-reference table of external IDs per contact or account, match first on that table, then on exact strong identifiers such as customer number or normalised email. When there are several candidates or none, send the event to an unmatched queue for a person to resolve rather than guessing.
Can Power BI use the same data as the agent timeline?
Yes, and it should. Model the interaction-event table as a fact table with customer, event type, source and date dimensions, and report from an analytical copy of Dataverse such as Azure Synapse Link or Link to Microsoft Fabric at any real volume. The agent timeline and the board view then count the same events for the same customers.
What can realistically be shown in a one-month Customer 360 demo?
A read-only unified history for one customer segment across two sources: the event table and cross-reference, one new adapter with logging, a historical backfill for that segment, the timeline configured on contact and account forms, and a Power BI single customer view over the same data. Adding more sources or write-back in the first month is what makes these demos slip.
Where should you go next?
Dynamics 365 Customer Service implementation
Case management, routing, SLAs, knowledge and omnichannel for the agents who use the unified history.
Dynamics 365 Customer Insights implementation
Journeys and unified customer profiles for marketing teams working from several data sources.
Power Automate consulting and RPA
Cloud flows and desktop flows engineered with retries, error paths and monitoring for adapters.
Agent desktop unification over legacy systems
Composing one agent surface in Dynamics 365 over systems that stay where they are.
Point-to-point integration rationalisation
Outbox, retry, idempotent consumers and the order of work for a fragile integration estate.
Custom CRM Development
CRM on React, Node.js, PostgreSQL and .NET for organizations that need full control without Microsoft licensing.
Which solution is right for your business?
Tell us what you need. A senior consultant replies within one business day with a recommendation - Dynamics 365, Power Platform, or a custom-built CRM - not a sales script.