Guides

Analyse performance

Five reads from the Team overview to one concrete change. CLI first; every step has its API and MCP form. Each read is small: a summary by default, with the exact next call on every flag and row.

The overview reads (GET /v1/analytics/motions, GET /v1/analytics/motions/{motion_id}, get_analytics over MCP) share one grammar: include picks sections, fields keeps dotted paths, sort and limit order and cut the Motion and Account lists, compare=previous_period adds previous and delta to every rate, and flags says what to look at. What each number means is in How Curviate counts.

The curviate analytics get (with --motion <id> for one Motion), curviate analytics events list and curviate account overview commands arrive with the next CLI release. Until then, use the API form or get_analytics over MCP: the bodies are the same.

1. Read the Team overview

Start with the summary: the three headline rates with their numerators and denominators, the top 5 Motions and Accounts by what they sent, and the flags. Compare with the previous period so a change stands out.

curviate analytics get --range 30d --compare previous_period

Over MCP: get_analytics with {"range": "30d", "compare": "previous_period"}. With no include, MCP always answers with the summary. On REST, a call with no grammar parameter still returns the full body of before, with a Deprecation header; pass any one of them (here limit=5) to get the summary.

A window that reaches back more than 12 months still answers: beyond 12 months you get daily counts only. window.counts_only_through names the last day counted that way; step and variant rates, seen and paths cover the days after it, so do not set paths against totals across that date. Judge a step or an A/B lead on the last 12 months.

Read the flags first. small_sample and still_maturing say a rate cannot carry a decision yet; rate_moved says it changed by a quarter or more; limit_reached and account_attention point at an Account, not a Motion.

2. Find the weakest Motion

Sort the Motions by the rate your goal depends on, lowest first, and keep only what you need.

curviate analytics get --range 30d --include motions --sort reply.rate \
  --fields motions.motion_id,motions.name,motions.reply,motions.next

A Motion whose rate has low_sample: true is not the weakest yet, only the least known. Skip it, or widen the period. Each row's next is the call for step 3.

3. Read its steps and A/B

curviate analytics get --motion mot_YOUR_MOTION_ID --include steps,variants,flags --range 30d

Two flags matter here. biggest_drop_off names the step where the most Enrollments were skipped, failed or left through else; its reasons are on the step row, and its next lists that step's events. ab_leader names the variant with the highest rate when every variant has at least 30 sends. It is a lead, not a proven difference: it carries every variant's rate and denominator and no significance figure.

4. Check its Accounts' health

A weak Motion is often a stalled Account. The Motion overview's flags cover the Accounts it sends from: limit_reached (refused for a ceiling on 3 or more days of the period) and account_attention (reconnect needed, or restricted). Their next opens the Account.

curviate analytics get --motion mot_YOUR_MOTION_ID --include accounts,flags --range 30d \
  --fields accounts.account_id,accounts.account_name,accounts.acceptance,flags

5. Make one concrete change

Change one thing, the one the reads point at, and say why in one sentence with the numbers behind it:

  • the drop-off step's reason is fixable (for example, a step skipped because the person is already connected): change the step or its condition;
  • an A/B lead holds on both sides at 30 sends or more: keep the leading variant's text and retire the other;
  • an Account hit its ceiling: move the Motion to an Account with room, or lower its pace;
  • an Account needs reconnecting: reconnect it first, and read the Motion again after a week.

Then wait. Rates are "sent in the period, outcome so far": a change shows once its sends are a week old (still_maturing clears). Read the same overview again with compare=previous_period.