cja-top-movers-watchlist
Identifies which items (pages, campaigns, products, channels, regions) had the biggest increases or decreases for a key metric between two time periods. Use this skill when someone asks "what's up and what's down," "which campaigns moved the most," "top gainers and losers," "what pages are trending," "show me what changed by channel," or any variation of identifying the biggest movers and decliners for a metric.
What this skill does
# Top Movers Watchlist (Customer Journey Analytics)
Surface the biggest gainers and decliners for a metric across any dimension in
two time periods. The output tells the user exactly what moved, by how much, and
whether items appeared or disappeared entirely — which is often the most
interesting signal.
This skill is a faster, more targeted alternative to a full anomaly triage.
Use it when the user wants to scan the landscape of changes rather than drill
into a single anomaly.
---
## CJA MCP Tools Used
- `describeCja(DATAVIEW_CONTEXT_GUIDE)` — load data view calendar/timezone
- `findMetrics` — resolve the metric being watched
- `findCalculatedMetrics` — if the metric is a custom KPI
- `findDimensions` — resolve the dimension to break down by
- `runReport` — pull dimension-metric data for both periods
- `searchDimensionItems` — validate dimension values if user specifies names
---
## Phase 0 — Setup
1. Call `findDataViews` and `setDefaultSessionDataViewId` as needed.
2. Call `describeCja("DATAVIEW_CONTEXT_GUIDE")` to load data view context.
Record the first-day-of-week as `WEEK_START_DOW` and timezone as
`TIMEZONE`. If the context guide does not return a week-start value,
default to **Monday** (ISO 8601). You will use both in Phase 1.3.
---
## Phase 1 — Clarify Inputs
### 1.1 Metric
If the user specified a metric, resolve it:
```
findMetrics(search: "<user's metric name>")
```
If not specified, suggest the top 3 metrics from usage:
> "Which metric would you like to track? I can suggest: Sessions, Revenue,
> Orders based on what your team uses most."
### 1.2 Dimension (what to break down by)
Common dimension choices and their typical use cases:
| Dimension | Use Case |
|--------------------|-----------------------------------------|
| Marketing Channel | "Which channels moved?" |
| Page Name | "Which pages are trending?" |
| Campaign | "Which campaigns improved?" |
| Product | "Which products gained/lost traction?" |
| Country / Region | "Which markets moved?" |
| Device Type | "Did mobile or desktop shift?" |
| Referring Domain | "Which referrers changed?" |
If the user did not specify, ask:
> "Which dimension should I break down by — for example, marketing channel,
> page, campaign, country, or product?"
Call `findDimensions(search: "<dimension keyword>")` to resolve the dimension ID.
### 1.3 Periods
Define Period A (current) and Period B (comparison). Defaults:
- **Period A**: this week (or last 7 days)
- **Period B**: last week (or the 7 days before that)
If the user specifies "this month vs last month" or a custom range, map
accordingly. Always confirm the periods before running reports:
> "I'll compare **this week (Mar 13–19)** vs **last week (Mar 6–12)**. Sound right?"
**Calendar rule (mandatory):**
Use `WEEK_START_DOW` from Phase 0 to define what "week" means. Period A and
Period B MUST use the same first-day-of-week — i.e., both periods'
`startDate` fall on the same day-of-week, both are exactly equal length,
and Period B ends immediately before Period A starts. Never mix conventions
(e.g., a Mon–Sun Period A with a Sun–Sat Period B) within the same run.
Pick the boundary once, then derive both periods from it. For custom date
ranges, compute Period B as the equal-length window ending immediately
before Period A starts.
**Sanity check before calling `runReport`:** confirm `periodA.startDate`
and `periodB.startDate` are the same day-of-week and that
`periodA.startDate - periodB.endDate == 1 day`. If not, recompute.
---
## Phase 2 — Pull Data for Both Periods
Run two reports — one per period — with the same dimension breakdown:
```
runReport(
dimensionIds: "<dimension id>",
metricIds: "<metric id>",
startDate: "<period A start>T00:00:00",
endDate: "<period A end>T23:59:59",
page: 0,
limit: 50
)
```
```
runReport(
dimensionIds: "<dimension id>",
metricIds: "<metric id>",
startDate: "<period B start>T00:00:00",
endDate: "<period B end>T23:59:59",
page: 0,
limit: 50
)
```
Use `limit: 50` to capture enough items to surface meaningful movers.
If the user's dimension has thousands of values (e.g., page names), limit to
top 100 by Period A volume to keep the comparison meaningful.
Row data is in the `rows` array — each row has `value` (dimension item name)
and `data[0]` (the metric value). There is no limit on dimension cardinality
but results default to sorted by metric descending, which is what you want.
Always verify the dimension ID with `findDimensions(searchQuery: "<name>")`
before running — dimension IDs can vary from what you might guess
(e.g., `variables/marketing_channel` not `variables/marketingchannel`).
---
## Phase 3 — Compute Rankings
Build a unified table joining both result sets on dimension value:
For each dimension value present in either period:
- `valueA` = metric value in Period A (0 if not present)
- `valueB` = metric value in Period B (0 if not present)
- `delta` = valueA − valueB
- `pctChange` = (delta / valueB) × 100 if valueB > 0, else "New Entry"
- `status`:
- Present in A but not B → **New Entry** (appeared this period)
- Present in B but not A → **Disappeared** (dropped out this period)
- Both present → normal mover
Sort by:
1. **Top Gainers**: sort by delta descending (biggest absolute gains first)
2. **Top Decliners**: sort by delta ascending (biggest absolute drops first)
3. **% Gainers**: sort by pctChange descending
4. **% Decliners**: sort by pctChange ascending
Limit each list to **Top 10**. New Entries and Disappeared items get their
own sections regardless of count (they are always interesting signals).
---
## Phase 4 — Generate HTML Report
Generate the movers report inline and write to
`/tmp/cja_top_movers_report_<YYYY-MM-DD_HHMMSS>.html`.
### Rendering rules — apply consistently across runs
Two runs of this skill on the same data view + metric/dimension + period must
render identically (modulo the generation timestamp). The rules below pin the
formatting choices that the AI would otherwise drift on.
#### Number formatting
- **KPI values** (the big number in each summary tile, and per-row mover
values) — use full digits with thousands separators (`8,160`, `77,584`,
`1,250,000`). Do **NOT** use SI suffixes like `K` or `M`, even for large
values. Stakeholders want exact numbers, not abbreviations.
- **Percent change** (in pills and narrative bullets) — always one decimal
place, rounded **half-away-from-zero**. For example, `−23.55%` displays as
`−23.6%`, never `−23.5%`. Compute on full-precision values; round only at
display time.
- **Percentage-point change** (for already-percentage metrics like Conversion
Rate or Bounce Rate) — same rounding, suffix `pp`. Example: `+0.40 pp`.
- **Currency** — `$` prefix with thousands separators and no decimals for
values ≥ $100 (`$1,240,000`); cents only when value < $100 (`$45.20`).
#### Null / missing data handling
A KPI tile or mover row must reflect what the data view actually returned.
The AI must **not** silently substitute a different metric or hide a tile to
make the report look cleaner.
- **Both periods return 0 or NULL** for the tracked metric in a summary tile:
render the tile with `kpi-value` = `Data unavailable`, pill class `flat`,
pill text `⚠ N/A`, and `prior` text = `Both periods returned no data —
validate instrumentation`. The tile stays in the grid; do not omit it.
- **One period returns valid data, the other 0 / NULL**: render the tile with
the valid value as `kpi-value`, pill class `flat`, pill text `⚠ N/A`, and
`prior` text = `Prior {period_noun}: no data`.
- **Never** substitute a different metric (e.g., switching from Revenue to
Orders because Revenue came back $0). The metric being analyzed MUST be the
metric rendered.
### HTML Template
```html
<!DOCTYPE html>
<html lang=Related in Data & Analytics
clawarr-suite
IncludedComprehensive management for self-hosted media stacks (Sonarr, Radarr, Lidarr, Readarr, Prowlarr, Bazarr, Overseerr, Plex, Tautulli, SABnzbd, Recyclarr, Unpackerr, Notifiarr, Maintainerr, Kometa, FlareSolverr). Deep library exploration, analytics, dashboard generation, content management, request handling, subtitle management, indexer control, download monitoring, quality profile sync, library cleanup automation, notification routing, collection/overlay management, and media tracker integration (Trakt, Letterboxd, Simkl).
querying-soql
IncludedSOQL query generation, optimization, and analysis with 100-point scoring. Use this skill when the user needs SOQL/SOSL authoring or optimization: natural-language-to-query generation, relationship queries, aggregates, query-plan analysis, and performance or safety improvements for Salesforce queries. TRIGGER when: user writes, optimizes, or debugs SOQL/SOSL queries, touches .soql files, or asks about relationship queries, aggregates, or query performance. DO NOT TRIGGER when: bulk data operations (use handling-sf-data), Apex DML logic (use generating-apex), or report/dashboard queries.
app-store-optimization
IncludedApp Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklists, and tracking ranking changes.
habit-flow
IncludedAI-powered atomic habit tracker with natural language logging, streak tracking, smart reminders, and coaching. Use for creating habits, logging completions naturally ("I meditated today"), viewing progress, and getting personalized coaching.
app-store-optimization
IncludedApp Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklists, and tracking ranking changes.
visualizing-data
IncludedBuilds dashboards, reports, and data-driven interfaces requiring charts, graphs, or visual analytics. Provides systematic framework for selecting appropriate visualizations based on data characteristics and analytical purpose. Includes 24+ visualization types organized by purpose (trends, comparisons, distributions, relationships, flows, hierarchies, geospatial), accessibility patterns (WCAG 2.1 AA compliance), colorblind-safe palettes, and performance optimization strategies. Use when creating visualizations, choosing chart types, displaying data graphically, or designing data interfaces.