> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heify.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Participant Analysis

> Generate a personal performance dashboard for a participant — date-range filtering, degradation alerts, KPIs with score sparkline, per-criterion performance and evolution, evaluator rankings with click-to-filter, heatmap, and a filterable transcription table.

The Participant Analysis page aggregates all transcriptions evaluated for a selected participant and organizes the results into a degradation alert, KPI summaries, trend charts, a per-criterion evolution chart, a per-criterion performance ranking, a weekly quality heatmap, an evaluator-based ranking with click-to-filter, and a filterable transcription detail table. A period filter scopes the whole dashboard to a date range.

<Warning>
  Each analysis generation consumes **one unit** of your account's `analytics_participant` quota. Loading a previously cached result for the same participant ID does not consume quota.
</Warning>

***

## Generating an analysis

Select a participant from the searchable selector at the top of the page and click **Generate Analysis**. The selector shows each participant's name, ID, and evaluated calls count.

<Note>
  Navigating directly to a URL that includes a participant ID (e.g. from a bookmark or shared link) auto-loads the last cached result — no quota consumed.
</Note>

<Note>
  The **Generate Analysis** button is disabled when no participant is selected or when your quota is exhausted.
</Note>

***

## Dashboard header

Once data is loaded, the dashboard header shows:

| Control              | Behavior                                                                           |
| -------------------- | ---------------------------------------------------------------------------------- |
| **Participant name** | Displayed below the title once a participant is active                             |
| **Last updated**     | Relative time since the last fetch                                                 |
| **Download PDF**     | Generates and downloads a structured PDF report. Only visible when data is loaded. |
| **Refresh**          | Re-fetches the analysis for the current participant                                |

***

## Period filter

The first card of the dashboard — shown once an analysis has been run — scopes **everything below it** to a date range.

| Element           | Behavior                                                                                           |
| ----------------- | -------------------------------------------------------------------------------------------------- |
| **From** / **To** | Native date pickers. Neither accepts a future date; **From** is capped by **To** and vice versa.   |
| **Apply**         | Re-runs the analysis server-side over the selected range. Empty fields are omitted — full history. |
| **Clear**         | Blanks both dates and re-runs unfiltered. Only rendered when at least one date is set.             |

If the start date is after the end date, **Apply** is disabled and a message appears: *"The start date can't be after the end date."*

<Warning>
  Both **Apply** and **Clear** issue a real API call and consume one unit of analytics quota, exactly like **Generate Analysis**. This is the key difference from the [evaluator click-to-filter](#click-to-filter) further down, which is a free client-side recalculation — the two filters sit on the same page and behave completely differently.
</Warning>

<Note>
  Clicking **Apply** also clears any active evaluator filter.
</Note>

<Note>
  Navigating to another page and back keeps both the data and the From/To inputs. A **browser reload does not** — the dashboard re-queries unfiltered and the inputs come back empty.
</Note>

<Tip>
  There is no "quarter" mode — a quarter is just a range. For Q2 2026, set From `2026-04-01` and To `2026-06-30`.
</Tip>

The filter matches on each transcription's **recording date** (which the [recording date controls](/sandbox/transcribe#recording-date) set at upload) — so calls uploaded late but dated correctly land in the right period.

***

## Degradation Banner

A red alert banner appears **directly above the KPI grid** when the participant's recent performance has dropped significantly.

**Trigger condition:** The average score of the last 20 evaluated records is more than **10 points lower** than the average of the previous 20 records.

<Warning>
  A **Degradation Alert** indicates a statistically significant performance decline. Review recent transcriptions to identify contributing factors before it becomes a deeper trend.
</Warning>

This banner is purely informational and has no interactive actions. It is hidden when no significant decline is detected. If an evaluator filter is active (see [Evaluators Ranking](#evaluators-ranking)), the trend comparison also applies only to records from that evaluator.

***

## KPI Grid

Four metric cards summarize this participant's overall performance across all their evaluations.

| KPI               | Description                                                                                                                                 |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| **Total Calls**   | Count of all transcriptions evaluated for this participant                                                                                  |
| **Average Score** | Score out of 100. Color: Emerald ≥91 · Green 71–90 · Amber 51–70 · Orange 31–50 · Red \<31. Includes a **sparkline** and a **trend badge**. |
| **Pass Rate**     | Percentage of calls that passed. Badge: **Excellent** ≥80% · **Good** 60–79% · **Fair** 40–59% · **Low** \<40%                              |
| **Criticals**     | Calls where a Strict criterion failed. Red badge if >0; *"No critical incidents"* if 0                                                      |

<Note>
  When **Average Score** or **Pass Rate** has no value, the card shows **—** (an em dash) with its `/100` or `%` suffix, rather than a misleading `0`.
</Note>

### Average Score — sparkline and trend badge

The **Average Score** card includes two extra elements not found in the Evaluator Analysis:

**Sparkline** — an inline chart of the last 20 scores plotted in chronological order (left to right). The line color matches the current score color. Shown when at least 2 data points exist; a progress bar is shown otherwise.

**Trend badge** — compares the last 20 records against the previous 20:

| Direction         | Color | Meaning                           |
| ----------------- | ----- | --------------------------------- |
| Improving         | Green | Recent average is higher          |
| Declining         | Red   | Recent average is lower           |
| Stable            | Grey  | No significant change             |
| Insufficient data | Grey  | Not enough records for comparison |

### Critical alert banner

If pending critical calls exist, a clickable amber/orange banner appears above the KPI grid:

> *"N pending critical calls — Pending review · Click for details"*

Clicking it jumps directly to the [Transcription Details](#transcription-details) table with the *Pending Critical* filter pre-applied.

***

## Charts

When an evaluator filter is active, all chart data is sourced from the filtered dataset.

### Monthly Comparison

Two side-by-side period cards — **This Month** and **Previous Month** — each showing Calls · Average Score · Pass Rate.

A delta summary below the cards shows the score change and pass rate change between periods.

| State                     | Display                                                  |
| ------------------------- | -------------------------------------------------------- |
| One period has no data    | Amber warning on that card                               |
| Both periods have no data | *"Data in both months is needed to show the comparison"* |

### Duration Analysis

Three tiles grouping calls by duration using p25/p75 thresholds:

| Tier       | Threshold           |
| ---------- | ------------------- |
| **Short**  | Below p25           |
| **Medium** | Between p25 and p75 |
| **Long**   | Above p75           |

Each tile shows call count and average score for that tier.

<Note>
  Duration thresholds are dynamically calculated from p25 and p75 percentiles of the dataset — they adapt to the actual distribution of this participant's calls.
</Note>

### Timeline Evolution

A dual-axis chart overlaying:

* **Left Y-axis** — Average Score (line)
* **Right Y-axis** — Call Volume (bars)

Hover over any point to see both metrics simultaneously.

### Score Distribution

A bar chart grouping transcriptions into 20-point score ranges: **0–20 · 20–40 · 40–60 · 60–80 · 80–100**.

***

## Evolution by criterion

A multi-line chart — one line per criterion, plotted per period — showing whether each criterion is getting better or worse over time. Rendered only when the analysis contains per-period criteria data. The header shows the covered range (e.g. `Jan 2026 - Jun 2026`) and an **"N periods"** pill.

| Control             | Options                                    | Notes                                                                                                                                                                     |
| ------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Grouped by**      | **Month** *(default)* · **Quarter**        | Quarter aggregation happens in the browser — no extra query, no quota consumed.                                                                                           |
| **View mode**       | **Native** *(default)* · **%**             | **Native** plots each criterion's real 1–5 score — scale criteria only. **%** plots everything as a compliance percentage (0–100%), comparable across any criterion type. |
| **Criterion pills** | One per criterion, plus **All** / **None** | The first 5 criteria are selected by default; click a pill to toggle its line.                                                                                            |

In **Native** mode, the pills for Yes/No and Strict criteria are disabled (*"Yes/No criteria are only shown in %"*) — a 0–1 compliance rate and a 1–5 score cannot share a Y axis. If there are no scale criteria at all, the **Native** button itself is disabled and the chart opens in **%**.

When the same criterion name occurs on more than one evaluator — common on this page, since several campaigns score the same person — the series is labelled **`Name · evaluator`** to disambiguate. Hovering a data point shows `85% (4.25/5)` in % mode, `4.25/5` in Native mode, and *"No data"* where a period has none.

**Empty states:**

* No criterion selected → *"Select at least one criterion to see its evolution."*
* No evolution data at all → **"No criterion evolution yet"** — *"There's no per-period criteria data yet. Assign a period when uploading recordings to see their evolution."*

<Note>
  Per-criterion data (this chart and the section below) only accumulates for transcriptions evaluated **after this feature was released** — older calls are not backfilled. If all your calls predate it, the chart stays empty until new recordings are evaluated. Set the [recording date](/sandbox/transcribe#recording-date) at upload so each call lands in the right period.
</Note>

***

## Performance by criterion

A ranked list of **every criterion with data in the analysed range**, across all the participant's evaluators — scrollable, with no top-5 cut-off. Two sort buttons in the section header (the choice also drives the [PDF report](#pdf-export)):

* **To improve** *(default)* — worst first, highest fail rate. Subtitle: *"To improve first · average score and fail %"*
* **Best** — best first.

The sort is not persisted; it resets to **To improve** on reload.

Each row shows: rank circle → criterion name → type badge (**Scale** / **Yes/No** / **Strict**) → **evaluator badge** → average-score badge *(scale criteria only)* → progress bar. On the right, the **fail rate** large (one decimal), with **"fails · of N evaluated"** beneath.

The evaluator badge matters here: several evaluators score the same person and criterion names repeat across them — two campaigns can both define a "Manejo de Objeciones". The badge tells you which evaluator each row belongs to.

<Note>
  The large number is the **fail** %, computed over the calls where the criterion was actually evaluated — the *"of N evaluated"* count — **not** over total calls. A criterion evaluated in 5 of the participant's 25 calls with 2 fails shows 40%, not 8%.
</Note>

**Color tiers.** The fail rate drives the rank circle, the progress bar, and the big number — a fuller bar is always a **worse** criterion:

| Fail rate | Color  |
| --------- | ------ |
| ≥ 50%     | Red    |
| 30–50%    | Orange |
| 15–30%    | Yellow |
| \< 15%    | Green  |

The **average-score badge** has its own scale (higher = greener), because a low fail rate and a good score are different things — a criterion can pass every call and still score mediocre:

| Average score | Badge  |
| ------------- | ------ |
| ≥ 3.5         | Green  |
| 3.0–3.5       | Yellow |
| 2.5–3.0       | Orange |
| \< 2.5        | Red    |

The average badge is deliberately hidden for Yes/No and Strict criteria: for those, the average is just the mirror of the fail rate already shown.

<Note>
  Criteria with **no data** in the range are hidden entirely — not shown as perfect, not shown at all. This typically means their only calls in range were evaluated before per-criterion tracking was released (no backfill). If the participant is scored on 12 criteria and you only see 9, this is why.
</Note>

***

## Weekly Heatmap

A day-of-week × hour-of-day grid showing the **average quality score** per time slot. This heatmap is built **client-side** from the raw data — it updates automatically when an evaluator filter is active, without consuming quota.

| Color   | Score range |
| ------- | ----------- |
| Grey    | No data     |
| Emerald | ≥ 80        |
| Green   | 60–79       |
| Amber   | 40–59       |
| Red     | \< 40       |

Two auto-generated insights are shown above the grid:

| Insight                   | Content                                         |
| ------------------------- | ----------------------------------------------- |
| **Best Performing Hour**  | The day and hour with the highest average score |
| **Worst Performing Hour** | The day and hour with the lowest average score  |

Hover over any cell to see the exact average score for that time slot.

<Note>
  The hour axis comes from each call's recording time. Recordings uploaded with a **date-only** recording date land at midnight UTC and pile into that column — [add the time at upload](/sandbox/transcribe#the-time-field) for an accurate heatmap.
</Note>

***

## Evaluators Ranking

A table of the **top 8 evaluators** this participant has been evaluated under, sorted by average score. Only rendered when evaluator data is present.

| Column          | Detail                                                                                                                            |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **#**           | Rank number. Top 3 show Trophy / Medal / Award icons. Rows where the critical fail rate exceeds 30% have a red-tinted background. |
| **Evaluator**   | Tag + ID (monospace)                                                                                                              |
| **Calls**       | Total evaluated calls under this evaluator                                                                                        |
| **Score**       | Average score — color-coded badge                                                                                                 |
| **Criticals**   | Critical fail count. Red badge if >0; *"—"* if none.                                                                              |
| **% Criticals** | Critical fail rate — red if >30%, amber if >15%, grey otherwise                                                                   |
| **Consistency** | Standard deviation badge                                                                                                          |
| **Duration**    | Average call duration (MM:SS)                                                                                                     |
| **Link**        | Opens the evaluator's analysis dashboard in a new tab                                                                             |

**Consistency thresholds:**

| Badge           | Threshold    |
| --------------- | ------------ |
| Very consistent | σ ≤ 5        |
| Consistent      | 6 \< σ ≤ 10  |
| Variable        | 11 \< σ ≤ 15 |
| Very variable   | σ > 15       |

### Click-to-filter

Clicking any row in the Evaluators Ranking activates a **client-side filter** for that campaign:

* The clicked row is highlighted; all other rows are dimmed.
* An **active filter tag** (evaluator name + X button) appears in the table header.
* Clicking the X button, or clicking the same row again, clears the filter.
* While a filter is active, the KPIs, charts, heatmap, and the transcription table are instantly recalculated using only records from that evaluator. No new API call is made.
* The two criteria sections — [Evolution by criterion](#evolution-by-criterion) and [Performance by criterion](#performance-by-criterion) — **disappear entirely** while the filter is active.

<Note>
  Click-to-filter is a purely client-side operation. Exploring a specific campaign does not consume any quota — all recalculations happen locally from the already-loaded data.
</Note>

<Note>
  The criteria sections cannot follow the evaluator filter: their data (per-criterion rates, average score, criterion type) is computed **server-side** and returned pre-aggregated — it cannot be re-sliced per evaluator in the browser. Recomputing it client-side is exactly what used to produce misleading fail rates, so correct-but-absent was chosen over present-but-wrong. The evaluator badge on each row of the unfiltered list already tells you which evaluator a criterion belongs to. Applying or clearing the [period filter](#period-filter), refreshing, or re-running the analysis all reset the evaluator filter, bringing both sections back.
</Note>

***

## Transcription Details

A full paginated table (10 per page) of every transcription included in the analysis.

### Group tabs

Filter by workflow group with a single click:

| Tab                | Color   |
| ------------------ | ------- |
| **All**            | Default |
| **No Group**       | Grey    |
| **Pending Review** | Amber   |
| **Under Review**   | Blue    |
| **Archived**       | Purple  |

### Filters

Click **Filters** to open the filter panel:

| Filter            | Type                                                        |
| ----------------- | ----------------------------------------------------------- |
| **Search**        | Text — matches by transcription ID or evaluator tag         |
| **From**          | Date — lower bound for transcription date                   |
| **To**            | Date — upper bound for transcription date                   |
| **Min Score**     | Number input                                                |
| **Max Score**     | Number input                                                |
| **Critical only** | Checkbox — shows only calls where a Strict criterion failed |

### Table columns

| Column        | Detail                                                                   |
| ------------- | ------------------------------------------------------------------------ |
| **Date**      | Full date and time                                                       |
| **Score**     | Color-coded badge (same thresholds as KPI grid)                          |
| **Duration**  | `MM:SS` formatted                                                        |
| **Evaluator** | Evaluator tag — clickable link opens the evaluator analysis in a new tab |
| **Critical**  | Red alert icon if a Strict criterion failed                              |
| **Failed**    | Failure count. Tooltip lists the names of all failed criteria.           |
| **Group**     | Group badge + pencil icon to update the group inline                     |

Click any row to open the full transcription detail in a new tab.

<Note>
  Group changes made from this table are applied immediately and reflected without requiring a full page re-fetch.
</Note>

***

## PDF Export

The **Download PDF** button in the header is available once analysis data is loaded.

Report filename: `Participant_Report_[name]_[date].pdf`

**Report contents:**

* Participant name and evaluation date
* Period range — only when a date range is applied, e.g. `Period: 2026-01-01 → 2026-03-31` (a missing side prints an ellipsis; dates print raw as `YYYY-MM-DD`)
* KPIs: Total Calls · Average Score · Pass Rate · Critical Fails
* Critical fails warning (if applicable)
* Monthly comparison — **omitted when a date range is applied**
* Performance by criterion — color-coded bars
* Evolution by criterion — table
* Evaluators ranking table
* Transcription detail table (ID · Date · Score · Duration · Evaluator · Critical · Group)

<Note>
  The period line reflects the range that was **applied** — what the report's numbers actually cover — not whatever is typed in the From/To boxes. Typing dates and downloading without pressing **Apply** produces a report with no period line and full-history figures.
</Note>

<Note>
  With a date range applied, **Monthly Comparison** disappears from the PDF: it compares the current calendar month against the previous one, which is meaningless — and misleading — inside an arbitrary range. Its absence is intentional.
</Note>

**Performance by criterion** mirrors the on-screen section: every criterion with data (no cap — the report paginates), following the sort you selected on screen, with the same four fail-rate color tiers on the bars and % labels, and `avg 3.4/5` shown for scale criteria only. Each criterion name is prefixed with its **evaluator tag in blue** (truncated), since names repeat across evaluators.

**Evolution by criterion** is printed as a **table**, not a chart — one row per criterion, with an **Evaluator** column (printing `—` when a criterion has no evaluator tag) and one column per month. It deliberately differs from the on-screen chart in three ways: it is always monthly (the Quarter toggle has no effect), period labels are raw keys (`2026-01`, not `Jan 2026`), and it includes **every** criterion with data regardless of which pills are selected. Cells show `3.4` for scale criteria, `78%` for Yes/No and Strict, and `—` where a month has no data.

<Warning>
  With an [evaluator filter](#click-to-filter) active, one PDF can mix scopes: the KPIs, evaluators ranking, score distribution, comparison, duration, timeline, and transcription sections use the **evaluator-filtered** values, while the two criteria sections are always built from the **whole participant's** server data — they ignore the evaluator filter, exactly like their on-screen counterparts. The Evaluator column and the blue evaluator prefixes keep the scope legible on the page.
</Warning>

***

<CardGroup cols={2}>
  <Card title="Participants" icon="users" href="/sandbox/participants">
    Manage your participants
  </Card>

  <Card title="Evaluator Analysis" icon="chart-bar" href="/sandbox/analytics-evaluator">
    View evaluator-level dashboards
  </Card>
</CardGroup>
