What it does
Customer Insights - Data writes its output — unified profiles, segment membership, unified activities, measures, enrichments and prediction results — into the linked Dataverse environment as system-managed tables with an msdynci_ prefix. Once they're there, anything that can talk to Dataverse (Web API, model-driven apps, Power Automate, Power BI, Fabric) can read them without going near the Customer Insights APIs.
Key facts
- Tables are exposed through the standard Dataverse Web API at
{Organization URI}/api/data/v9.2/, so the same OData syntax, auth and service protection limits you already know apply. - The entity sets documented are
msdynci_customerprofiles,msdynci_segmentmemberships,msdynci_unifiedactivities,msdynci_customermeasures,msdynci_enrichmentsandmsdynci_predictions. - Real-time web personalisation adds
msdynci_p13nprofile,msdynci_p13nviewsandmsdynci_p13nactions, and changes how unified activity data is surfaced — the docs qualifymsdynci_unifiedactivitiesas the path when web personalisation isn't in use. - Read only. Microsoft is explicit that POST, PATCH and PUT against these tables can break Customer Insights processing. GET is the only supported verb.
- Microsoft's stated direction is to move off the Customer Insights - Data APIs onto the Dataverse APIs for filtering, sorting, scale and consistency. Treat the old API surface as legacy on new builds.
- Calling app needs the usual three things: an Entra app registration, Dataverse API permissions, and at least Viewer permission inside Customer Insights - Data. All three, not two.
- Segment membership is not a relational join table. The documented filter pattern is a
contains()onmsdynci_segments, i.e. you're string-matching against a serialised list on the customer row. - Profile lookups by business key work through alternate keys —
?$filter={alternate_column} eq '{value}'— but only for columns you've actually set up as such. - Metadata is not queryable yet. Segment definitions and workflow/run management were still listed as coming, so orchestration and admin calls stay on the Customer Insights APIs for now.
- The tables only exist in Dataverse if the environment is using Customer Insights managed storage, or a bring-your-own-lake environment with Dataverse data sharing switched on.
When to use / skip
This is the default integration surface now, and for most projects it's the only one worth building against. If a client wants unified profiles inside a model-driven app, a canvas app, a Power BI report over Dataverse, a plugin, or any bespoke service, point them here rather than at the Customer Insights REST API or a nightly export to blob storage. The exception is genuine bulk movement — pulling every profile for a downstream warehouse. Dataverse service protection limits will make that miserable, and you want an ADLS or Fabric export instead. Skip it entirely on bring-your-own-lake environments where nobody has enabled Dataverse data sharing, because the tables simply won't be there.
Configuration decisions
- Whether output lands in Dataverse at all — that's decided by the storage choice made at environment creation, and it's not casually reversible.
- Which columns get promoted into the unified profile, since the shape of
msdynci_customerprofilesis whatever unification produced, not a fixed schema. - Which alternate keys you need on the profile table so downstream apps can look a customer up by email, CRM contact ID or loyalty number rather than the Customer Insights CustomerId.
- Service principal versus user context for each consumer, and which Customer Insights permission level that principal gets.
- Whether measures and predictions are consumed from these tables directly, or copied into your own Dataverse columns for a nicer form experience and audit history.
- How segment membership gets consumed given the serialised column — filter in the query, or flatten it into your own table on a schedule.
Gotchas
- Someone will eventually try to write to
msdynci_tables from a plugin, a flow or a data migration tool. It looks like an ordinary Dataverse table and it isn't. Lock this down in your solution review before it corrupts a refresh. - The profile table's column set moves when unification changes. Add a source field, rerun unification, and a canvas app or Power BI report bound to the old shape can quietly stop returning what it used to.
- Rows are replaced by the refresh cycle, not updated transactionally. Anything that assumes stable record timestamps or Dataverse-style change tracking behaviour on these tables needs testing, not assumption.
- Dataverse API limits are per user or per service principal, per server. A chatty integration on a single app registration will get throttled long before Customer Insights runs out of steam.
- Viewer permission in Customer Insights is easy to forget because the Dataverse call fails in a way that looks like a Dataverse security problem rather than a Customer Insights one.
- Segment membership filtering by name means renaming a segment breaks every consumer silently. Nothing errors, you just get zero rows.
Consultant notes
- Demo this early. Showing a client that unified profiles are already sitting in their own Dataverse environment, queryable with tooling they own, kills a surprising amount of "so how do we get the data out" anxiety.
- Push back hard on any design that treats these tables as writable. The correct pattern is: read
msdynci_, write to your own table. - Agree a contract on the unified profile schema with whoever builds the downstream apps, and make changes to unification go through the same change control as a Dataverse schema change.
- Before go-live, check the consuming app registrations have Customer Insights permissions assigned, not just Dataverse ones — this is the single most common day-one failure.
- If the client is still on the older Customer Insights - Data REST APIs, flag the migration now while it's a small piece of work rather than after they've built ten flows on it.
Worth another look when the metadata APIs land, or if the profile schema changes shape again.