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

> ## Agent Instructions
> To search or read these docs, connect the Ringg docs MCP server at https://docs.ringg.ai/mcp (no key needed; tools search_ringg_ai and query_docs_filesystem_ringg_ai) instead of browsing pages one by one. Setup for each client: https://docs.ringg.ai/resources/mcp-server/docs-mcp-server/mcp-for-ai-assistants.md
> The dashboard labels agents "Assistants"; these docs say "agent". Both mean the same object, identified by agent_id.
> API base URL: https://prod-api.ringg.ai/ca/api/v0. Send the workspace API key in the X-API-KEY header, from server-side code only.
> Placing a call dials a real phone number and spends credits. Confirm the number with the user before calling.
> To act on a Ringg workspace (place calls, edit agents, read transcripts), use the separate Ringg workspace MCP server at https://mcp.ringg.ai/mcp: https://docs.ringg.ai/resources/mcp-server/workspace-mcp-server/overview.md

# Lesson: Analytics

> Filter Analytics to the EMI reminder agent and its dry-run campaign, read Connectivity rate and Goal achieved, judge retries, and drill into Logs.

export const Quiz = ({question, answers, correctFeedback, incorrectFeedback}) => {
  const [selected, setSelected] = React.useState(null);
  const [checked, setChecked] = React.useState(false);
  const quizId = React.useId();
  const isCorrect = checked && answers[selected]?.correct;
  const reset = () => {
    setSelected(null);
    setChecked(false);
  };
  const optionStyle = (answer, i) => {
    const base = {
      display: "flex",
      alignItems: "flex-start",
      gap: "0.6rem",
      padding: "0.6rem 0.8rem",
      marginTop: "0.5rem",
      borderRadius: "0.6rem",
      border: "1px solid rgba(128, 128, 128, 0.35)",
      cursor: checked ? "default" : "pointer",
      lineHeight: 1.45
    };
    if (checked && answer.correct) {
      return {
        ...base,
        borderColor: "rgba(22, 163, 74, 0.8)",
        background: "rgba(22, 163, 74, 0.12)"
      };
    }
    if (checked && selected === i && !answer.correct) {
      return {
        ...base,
        borderColor: "rgba(220, 38, 38, 0.8)",
        background: "rgba(220, 38, 38, 0.1)"
      };
    }
    if (!checked && selected === i) {
      return {
        ...base,
        borderColor: "currentColor",
        background: "rgba(128, 128, 128, 0.12)"
      };
    }
    return base;
  };
  const buttonStyle = disabled => ({
    marginTop: "0.9rem",
    padding: "0.45rem 0.9rem",
    borderRadius: "0.5rem",
    border: "1px solid rgba(128, 128, 128, 0.5)",
    background: "rgba(128, 128, 128, 0.1)",
    color: "inherit",
    font: "inherit",
    fontSize: "0.9em",
    cursor: disabled ? "not-allowed" : "pointer",
    opacity: disabled ? 0.5 : 1
  });
  return <div style={{
    marginTop: "1.5rem",
    padding: "1rem 1.1rem",
    borderRadius: "0.8rem",
    border: "1px solid rgba(128, 128, 128, 0.35)"
  }}>
      <Badge color="green">Quiz</Badge>
      <p id={quizId + "-question"} style={{
    fontWeight: 600,
    margin: "0.6rem 0 0.2rem"
  }}>
        {question}
      </p>
      <div role="radiogroup" aria-labelledby={quizId + "-question"} aria-disabled={checked}>
        {answers.map((answer, i) => <label key={i} style={optionStyle(answer, i)}>
            <input type="radio" name={"quiz-" + quizId} checked={selected === i} onChange={() => !checked && setSelected(i)} disabled={checked} style={{
    marginTop: "0.3rem",
    flexShrink: 0
  }} />
            <span>{answer.text}</span>
          </label>)}
      </div>
      {checked && <div role="status" aria-live="polite" aria-atomic="true" style={{
    marginTop: "0.9rem",
    padding: "0.7rem 0.9rem",
    borderRadius: "0.6rem",
    lineHeight: 1.5,
    background: isCorrect ? "rgba(22, 163, 74, 0.12)" : "rgba(220, 38, 38, 0.1)"
  }}>
          <strong style={{
    marginRight: "0.4rem"
  }}>{isCorrect ? "✓" : "✗"}</strong>
          {isCorrect ? correctFeedback : incorrectFeedback}
        </div>}
      {!checked ? <button type="button" onClick={() => selected !== null && setChecked(true)} disabled={selected === null} style={buttonStyle(selected === null)}>
          Check answer
        </button> : <button type="button" onClick={reset} style={buttonStyle(false)}>
          Try again
        </button>}
    </div>;
};

export const RelatedTopics = ({items}) => <div className="not-prose mt-12">
    <div className="text-sm font-medium text-gray-500 dark:text-zinc-400 mb-3">Related topics</div>
    <div className="flex flex-col gap-2.5">
      {items.map(([title, href]) => <a key={href} href={href} className="flex items-center gap-2.5 text-sm text-gray-700 hover:text-gray-950 dark:text-zinc-300 dark:hover:text-white">
          <Icon icon="file-text" size={16} color="currentColor" />
          {title}
        </a>)}
    </div>
  </div>;

**Part 6: Measuring and improving your agent · Lesson 2 of 4 · 15 minutes**

## Objective

Read connectivity and goal rate for Ananya's calls, and jump from a figure to the calls behind it.

## The scenario

With three calls the numbers are small, but the reading habit is the same at three thousand: did the calls connect, did Ananya get a promise to pay, and were the retries worth their cost? Analytics answers across all calls.

## Hands-on

<Frame caption="Filtering Analytics and drilling into Logs">
  <video alt="Filtering Analytics and drilling into Logs" aria-label="Filtering Analytics and drilling into Logs" controls muted playsInline className="w-full rounded-xl" style={{ aspectRatio: "16 / 10" }} preload="metadata" controlsList="nodownload noremoteplayback" poster="/media/monitor-analytics/poster.webp">
    <source src="https://mintcdn.com/ringgai-0da73d20/XUOcNie5hfK3q--Y/media/monitor-analytics/video.webm?fit=max&auto=format&n=XUOcNie5hfK3q--Y&q=85&s=557086fff3b00ff1ecc9dbb370a479b1" type="video/webm; codecs=&#x22;av01.0.09M.08&#x22;" data-path="media/monitor-analytics/video.webm" />
  </video>
</Frame>

<Steps>
  <Step title="Scope the page">
    On **Monitor → Campaigns**, click the dry run and then **Analytics**. The page opens scoped to the campaign and the date range drops away: a campaign covers all of its calls whenever they happened. For Ananya across every campaign, open **Monitor → Analytics** instead and tick her under **Filters → Assistants**, which selects all her versions.
  </Step>

  <Step title="Read Volume">
    Eight cards. With a date range, a card can carry a change badge against the previous period of the same length; scoped to a campaign, as here, there is no previous period and no badge. **Total calls**, **Calls connected** and **Connectivity rate** matter most here. Hover **Details** on **Connectivity rate** for **Campaign time exhausted** and **Retry exhausted**: calls stopped by the campaign's end time or its retry count. **Avg handle time** splits by duration on hover; many calls under 10 seconds is the cue to rework the opening.
  </Step>

  <Step title="Read Performance">
    **Goal achieved** is the share of analysed calls where `payment_promised` came back true, because you marked it **Use as goal** in part 3. **Cost per goal** divides the cost of connected calls by those calls. Both appear only with an agent or a campaign selected, and read `-` if the agent has no goal. **Latency** is Ananya's average response time in milliseconds.
  </Step>

  <Step title="Judge the retries">
    The **Connectivity** chart plots cumulative connectivity per attempt: **Attempt 1**, **Attempt 2** and so on. Hover a point for that attempt's attempted and connected counts. A flat line after attempt 2 means later retries reach no one, and **Retry count** should come down.
  </Step>

  <Step title="Read the cohorts">
    Each half-donut under **Cohort analysis** splits connected calls by one Boolean or enum field: `payment_promised` and `objection`. Hover a slice for its connected calls and average handle time. `promised_date` is not charted: only Boolean and enum fields are.
  </Step>

  <Step title="Drill into Logs">
    Click the **Calls connected** value. Logs opens with **Call status** **Completed** and the agent, campaign and date filters carried over. A slice of the `objection` donut does the same for one value, with exactly one agent selected.
  </Step>
</Steps>

## Checkpoint

<Check>
  Logs opens filtered to status **Completed** and to the agent or campaign you had selected, listing the connected calls.
</Check>

## Exercise

Scope the page to one version of Ananya. Under **Filters → Assistants**, untick V2 (from part 5) so only V1 is selected. Expected result: every card recomputes for V1's calls alone; once V2 has taken calls, swapping the ticks shows its figures. **Goal achieved** and **Avg handle time** are the two to compare between versions.

## What you learned

* Analytics is for trends and Logs for one call. Selecting a campaign drops the date range; otherwise the page covers the last month in your browser's timezone.
* **Goal achieved** needs a Boolean Advanced Analysis variable marked **Use as goal** and an agent or campaign selected.
* The connectivity-by-attempt chart tells you whether retries pay off, and clickable figures open Logs with the same filters.

<Quiz
  question="Performance shows Goal achieved as - for Ananya's campaign. Which is the likely cause?"
  answers={[
{ text: "Goal achieved needs a Boolean Advanced Analysis variable marked Use as goal, and the agent has none", correct: true },
{ text: "The date range is too short for the card", correct: false },
{ text: "Goal achieved only works on inbound calls", correct: false },
{ text: "The campaign has fewer than 100 calls", correct: false },
]}
  correctFeedback="Right. Goal achieved is the share of analysed calls where the goal variable came back true. It needs a Boolean marked Use as goal and an agent or campaign selected; without a goal the card reads -."
  incorrectFeedback="Not quite. Goal achieved and Cost per goal depend on one thing: a Boolean Advanced Analysis variable marked Use as goal on the agent, with an agent or campaign selected. Call volume, direction and date range do not make the card read -."
/>

<RelatedTopics items={[["Analytics", "/documentation/monitor/analytics"], ["Advanced Analysis", "/documentation/build-agents/customize-agent-behaviour/advanced-analysis"]]} />


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.