Skip to content

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 — no PublishAllXml runs. The change is only reflected in the UI after publish. Pass --publish per edit, or batch a run of staged edits and publish once with crm solution publish-all.
  • User charts (userqueryvisualization, --user-owned) are never published — edits reflect immediately and --publish / --no-publish is 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.