# Agent Session: Analytics Setup

> An agent adds a signup funnel to a product analytics dashboard. The card arrives with its file, then each bar fills as the tracking call for that step is written.

A shadcn/ui block from the [@keyframeui](https://keyframeui.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/keyframeui/agent-session-demo).

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/agent-session-demo
- Screenshot: https://shadcn.exchange/shot/keyframeui/agent-session-demo/light.png
- Registry item: https://keyframeui.com/r/agent-session-demo.json
- Categories: ai, code, developer
- Listed: 2026-11-02, source last changed 2026-11-02

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/keyframeui/agent-session-demo.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `https://keyframeui.com/r/agent-session.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/agent-session#agent-session-demo

## Files

### `registry/demos/agent-session-demo.tsx`

```tsx
"use client";

import { motion } from "motion/react";

import {
  AgentSession,
  AgentSessionTarget,
  useAgentSessionEffect,
  type AgentSessionStep,
} from "@/components/ui/agent-session";

const script: AgentSessionStep[] = [
  { prompt: "Add a signup funnel to the dashboard and track each step" },
  {
    run: "npx tern events list --match signup",
    ms: 900,
    output: [
      "signup_viewed      page     /signup",
      "signup_submitted   form     #signup-form",
      "email_verified     server   POST /api/verify",
    ],
    more: 4,
  },
  {
    run: "npx tern add funnel signup --to app/dashboard",
    ms: 1100,
    output: [
      { text: "+ app/dashboard/signup-funnel.tsx   SignupFunnel", tone: "added", effect: "funnel" },
      { text: "~ app/dashboard/layout.tsx          Funnels (1)", effect: "nav" },
    ],
  },
  {
    run: "npx tern track signup_viewed signup_submitted email_verified",
    ms: 1200,
    pace: 420,
    output: [
      { text: '+ app/signup/page.tsx       track("signup_viewed")', tone: "added", effect: "step-1" },
      { text: '+ app/signup/form.tsx       track("signup_submitted")', tone: "added", effect: "step-2" },
      { text: '+ app/api/verify/route.ts   track("email_verified")', tone: "added", effect: "step-3" },
    ],
  },
  {
    say: "Added a three-step signup funnel to the dashboard. Last week 1,204 of 12,480 visitors finished, and most of the drop happens before the form is sent.",
  },
];

const steps = [
  { effect: "step-1", label: "Viewed signup", count: "12,480", share: 1 },
  { effect: "step-2", label: "Sent the form", count: "2,911", share: 0.233 },
  { effect: "step-3", label: "Verified email", count: "1,204", share: 0.096 },
];

const nav = ["Overview", "Funnels", "Events", "Retention", "Settings"];

export function AgentSessionDemo() {
  return (
    <AgentSession
      script={script}
      title="web — agent"
      url="localhost:3000/dashboard"
      className="max-w-5xl [--agent-session-height:26rem]"
    >
      <div className="@container/app flex h-full text-zinc-900 dark:text-zinc-100">
        <aside className="hidden w-32 shrink-0 flex-col gap-0.5 border-r border-zinc-950/[0.06] bg-zinc-50/70 p-2.5 @[24rem]/app:flex dark:border-white/[0.06] dark:bg-white/[0.02]">
          <div className="mb-3 flex items-center gap-1.5 px-1.5 pt-1 text-[13px] font-semibold tracking-tight">
            <svg viewBox="0 0 16 16" className="size-3.5" aria-hidden>
              <path d="M2 13 8 3l6 10H2Z" fill="currentColor" />
            </svg>
            Tern
          </div>
          {nav.map((item, i) => (
            <div
              key={item}
              className={
                i === 0
                  ? "flex items-center justify-between rounded-md bg-white px-2 py-1.5 text-xs font-medium shadow-sm ring-1 ring-zinc-950/5 dark:bg-white/10 dark:ring-white/5"
                  : "flex items-center justify-between rounded-md px-2 py-1.5 text-xs text-zinc-500 dark:text-zinc-400"
              }
            >
              {item}
              {item === "Funnels" && (
                <AgentSessionTarget effect="nav" className="[--agent-session-ring-radius:999px]">
                  <span className="rounded-full bg-zinc-900 px-1.5 text-[10px] leading-4 font-medium text-white tabular-nums dark:bg-white dark:text-zinc-900">
                    1
                  </span>
                </AgentSessionTarget>
              )}
            </div>
          ))}
        </aside>

        <main className="flex min-w-0 flex-1 flex-col gap-3 p-4">
          <div className="flex items-baseline justify-between">
            <h3 className="text-sm font-semibold tracking-tight">Overview</h3>
            <span className="text-[11px] text-zinc-400">Last 7 days</span>
          </div>
          <div className="grid grid-cols-2 gap-2">
            <Stat label="Visitors" value="12,480" delta="+8.2%" />
            <Stat label="Signups" value="1,204" delta="+3.1%" />
          </div>

          <AgentSessionTarget
            effect="funnel"
            className="[--agent-session-ring-radius:14px]"
            fallback={
              <div className="flex h-full min-h-36 flex-col items-center justify-center gap-1 rounded-xl border border-dashed border-zinc-950/15 text-center dark:border-white/15">
                <p className="text-xs font-medium">No funnels yet</p>
                <p className="text-[11px] text-zinc-400">Ask for one, or add it from Funnels.</p>
              </div>
            }
          >
            <div className="rounded-xl bg-white p-3 ring-1 ring-zinc-950/[0.08] shadow-sm dark:bg-white/[0.04] dark:ring-white/10">
              <div className="mb-2.5 flex items-baseline justify-between">
                <p className="text-xs font-semibold">Signup funnel</p>
                <p className="text-[11px] text-zinc-400 tabular-nums">9.6% convert</p>
              </div>
              <div className="flex flex-col gap-2">
                {steps.map((step) => (
                  <FunnelRow key={step.effect} {...step} />
                ))}
              </div>
            </div>
          </AgentSessionTarget>
        </main>
      </div>
    </AgentSession>
  );
}

function Stat({ label, value, delta }: { label: string; value: string; delta: string }) {
  return (
    <div className="rounded-xl bg-white p-2.5 ring-1 ring-zinc-950/[0.08] dark:bg-white/[0.04] dark:ring-white/10">
      <p className="text-[11px] text-zinc-500 dark:text-zinc-400">{label}</p>
      <p className="mt-0.5 flex items-baseline gap-1.5">
        <span className="text-base font-semibold tracking-tight tabular-nums">{value}</span>
        <span className="text-[10px] font-medium text-emerald-600 dark:text-emerald-400">{delta}</span>
      </p>
    </div>
  );
}

// Each row fills once its tracking call lands, so the bars arrive in the order the agent wrote them.
function FunnelRow({ effect, label, count, share }: (typeof steps)[number]) {
  const landed = useAgentSessionEffect(effect);
  return (
    <AgentSessionTarget effect={effect} enter="none" className="[--agent-session-ring-radius:8px]">
      <div className="flex flex-col gap-1">
        <div className="flex items-baseline justify-between text-[11px]">
          <span className="text-zinc-600 dark:text-zinc-300">{label}</span>
          <motion.span
            initial={false}
            animate={{ opacity: landed ? 1 : 0.35 }}
            className="font-medium tabular-nums"
          >
            {landed ? count : "—"}
          </motion.span>
        </div>
        <div className="h-1.5 overflow-hidden rounded-full bg-zinc-100 dark:bg-white/[0.07]">
          <motion.div
            initial={false}
            animate={{ transform: `scaleX(${landed ? share : 0})` }}
            transition={{ type: "spring", visualDuration: 0.6, bounce: 0 }}
            className="h-full origin-left rounded-full bg-zinc-900 dark:bg-zinc-100"
          />
        </div>
      </div>
    </AgentSessionTarget>
  );
}
```
