How-to: chart
Author system and user charts headlessly — list, get, create, and delete
savedqueryvisualization (system) and userqueryvisualization (user) records
without opening the chart designer. See the
CLI reference for every flag.
A chart binds to its host table via primaryentitytypecode (the logical-name
string) and carries two XML columns: datadescription (an aggregate FetchXML)
and presentationdescription (the rendering/series XML). Authoring a chart from
source control means committing those two XML files and recreating the chart
with chart create.
List a table's charts
crm chart list contact # system charts (the default)
crm chart list contact --user-owned # user-owned charts
Output columns: name, the id (savedqueryvisualizationid, or
userqueryvisualizationid with --user-owned), and isdefault (system charts only).
list returns only these list-oriented fields — to read a chart's
datadescription / presentationdescription XML, use chart get <id>.
Get a single chart
crm chart get 1111aaaa-2222-bbbb-3333-cccccccccccc
crm chart get 1111aaaa-2222-bbbb-3333-cccccccccccc --user-owned
get returns the chart's XML in the --json envelope — pipe it to files to
capture a chart into source control:
crm --json chart get <id> | jq -r '.data.datadescription' > chart.data.xml
crm --json chart get <id> | jq -r '.data.presentationdescription' > chart.pres.xml
Create a chart
A system chart is the default; --user-owned creates a user-owned chart. There are
two mutually exclusive authoring modes.
XML mode — from datadescription + presentationdescription files
crm chart create contact \
--name "Contacts by Method" \
--data-description chart.data.xml \
--presentation-description chart.pres.xml \
--solution cwx_crmworx
--solution is required on every mutating chart verb (create, update,
set-fetch, add-series, remove-series, set-groupby) — a component created
without an explicit target solution would otherwise land only in the system
Default Solution. Pass --solution Default for a deliberate
Default-Solution-only write.
Both files are required in XML mode. The server validates the XML (for example,
the number of chart areas in the presentation XML must match the number of
categories in the data XML), so a malformed pair is rejected with a 400.
Web-resource mode — script-based visualization
crm chart create contact --name "Custom Viz" --web-resource new_chartscript --solution cwx_crmworx
--web-resource takes a web resource name or GUID and is mutually exclusive
with --data-description / --presentation-description. A name is resolved to
its webresourceid automatically.
Create a user chart
crm chart create contact --name "My View" \
--data-description chart.data.xml \
--presentation-description chart.pres.xml \
--solution cwx_crmworx \
--user-owned
Publishing
chart create stages the change by default — no PublishAllXml runs (the
CLI-wide convention shared with form clone, metadata create-entity, etc.).
Pass --publish to make a new chart visible immediately, or batch several
operations and publish once at the end:
crm chart create contact --name "Q" \
--data-description d.xml --presentation-description p.xml \
--solution cwx_crmworx --publish
# ...more staged operations...
crm solution publish-all # publish everything once the batch is done
Preview without writing
crm --dry-run chart create contact --name "Q" \
--data-description d.xml --presentation-description p.xml \
--solution cwx_crmworx
Returns {_dry_run: true, would_create: {entity_set, body}} with the fully
resolved request body (a --web-resource name is resolved live first); no chart
is created. --solution is still required under --dry-run — it is validated
before any backend call.
Delete a chart
crm chart delete 1111aaaa-2222-bbbb-3333-cccccccccccc --yes
crm chart delete 1111aaaa-2222-bbbb-3333-cccccccccccc --user-owned --yes
delete is destructive: omitting --yes prompts on a TTY, and under --json
or a non-TTY it fails fast with an error that names --yes.
Under --dry-run, delete returns
{_dry_run: true, would_delete: true, savedqueryvisualizationid: <id>} (or
userqueryvisualizationid with --user-owned) without issuing the DELETE. To remove
a chart from a solution (rather than delete it), use
crm solution remove-component.
Update a chart's XML, name, or series type
chart update replaces one or both XML columns, the display name, the
description, or the chart type on every series — any combination, in one call:
crm chart update <id> --data-description new.data.xml --solution cwx_crmworx
crm chart update <id> --presentation-description new.pres.xml --solution cwx_crmworx
crm chart update <id> --name "Contacts by Region" --description "Q3 rollout" --solution cwx_crmworx
crm chart update <id> --type Bar --solution cwx_crmworx
crm chart update <id> --data-description d.xml --presentation-description p.xml --solution cwx_crmworx
--type sets ChartType on every <Series> element in the
presentationdescription (e.g. Column, Bar, Line, Pie).
Partial-XML update and the alias-coupling invariant
When only one of --data-description / --presentation-description is
supplied, the command reads the other column live from the server and validates
the cross-container alias-coupling pair before PATCHing. This means:
- Every
<attribute alias="…">in the fetch must match a<measurecollection>alias in the datadescription and a positionally-coupled<Series>in the presentationdescription. - A mismatched pair is rejected before any write is issued.
The chart's host entity (primaryentitytypecode) is never changed — re-homing
a chart to a different table is not supported.
Publishing and solution
update follows the same --publish / --no-publish / --solution contract
as create (see above) — --solution is required, and it stages by
default. For system charts the change is only visible in the UI after
PublishAllXml runs; user charts (--user-owned) are never published and take
effect immediately.
crm chart update <id> --type Line --solution cwx_crmworx --publish
crm chart update <id> --name "New Name" --solution cwx_crmworx # staged
crm solution publish-all # publish when ready
Replace the inner fetch query
chart set-fetch replaces the <fetch> element inside the datadescription
while leaving the <categorycollection> (grouping categories) intact:
crm chart set-fetch <id> --fetch new_query.xml --solution cwx_crmworx # staged
crm chart set-fetch <id> --fetch new_query.xml --solution cwx_crmworx --user-owned
crm chart set-fetch <id> --fetch new_query.xml --solution cwx_crmworx --publish # publish immediately
Use this when you need to change the query (entity, filters, linked entities)
without rebuilding the full datadescription. The --fetch file should contain
only the <fetch> element itself, not a full wrapped datadescription.
The alias-coupling invariant is validated after the splice: the replacement
<fetch> must still carry <attribute> elements whose aliases match the
existing <measurecollection> aliases.
Add an aggregate series
chart add-series adds one new aggregate series — a fetch attribute, a
measurecollection entry, and a presentation <Series> — in one call:
crm chart add-series <id> --column estimatedvalue --aggregate sum --alias total_value --solution cwx_crmworx
crm chart add-series <id> --column opportunityid --aggregate count --alias opp_count --solution cwx_crmworx
A chart is capped at 5 series. Per-series edits are not supported on a
comparison chart (one with 2 <categorycollection> categories — it pairs
two groupings against a single series); add-series / remove-series refuse it
with a hint to use chart update instead.
The --alias must be unique within the chart; the --column must be a logical
name that exists on the chart's host entity (validated against live metadata).
A series is modeled as one <measurecollection> per series — the server couples
the inner <Series> count to a category's measurecollection count, not to its
individual <measure> count. Keep that 1:1 mapping in mind when inspecting the
raw XML.
Remove a series
chart remove-series removes the series identified by its alias — the fetch
attribute, its measurecollection entry, and the positionally-coupled
presentation <Series>:
crm chart remove-series <id> --alias total_value --solution cwx_crmworx
crm chart remove-series <id> --alias opp_count --solution cwx_crmworx --user-owned
Removing the last series is refused — a chart must have at least one — as is
removing a series from a comparison chart (see add-series above).
Change the grouping column
chart set-groupby replaces the grouping (category) column in the fetch's
<entity> element and in the datadescription's <categorycollection>:
crm chart set-groupby <id> --column createdon --dategrouping month --solution cwx_crmworx
crm chart set-groupby <id> --column ownerid --solution cwx_crmworx
--dategrouping is only meaningful for date/datetime columns. It is rejected
for non-date columns.
The --column is validated against live entity metadata.
Publish gating — system vs user charts
This applies to all editor verbs (update, set-fetch, add-series,
remove-series, set-groupby):
- System charts (
savedqueryvisualization, the default) stage by default — noPublishAllXmlruns. The change is only reflected in the UI after publish. Pass--publishper edit, or batch a run of staged edits and publish once withcrm solution publish-all. - User charts (
userqueryvisualization,--user-owned) are never published — edits reflect immediately and--publish/--no-publishis accepted but has no effect.
Don't chain staged edits on a system chart
A system-chart editor reads the published snapshot before writing, so a
second staged (flagless) edit reads the chart without the first edit's
pending change and overwrites it. To make several system-chart edits
safely: either pass --publish on each one, or publish between edits with
crm solution publish-all. User charts (--user-owned) are unaffected — they
aren't published, so each edit reads the previous one's result.
Relationship to metadata clone-entity --with-charts
crm chart is the standalone surface for the chart logic that
crm metadata clone-entity --with-charts uses when duplicating a whole entity.
Use chart get + chart create to move or version a single chart without
cloning the table itself.