Design
llms.txt digitalcrew.tech

Analytics

InsightsCard

A meeting's numbers (sentiment, stat tiles, per-speaker talk share, an over-talk hint), all derived on the client from the transcript.

MaxAnalyticsDigitalCrew.InsightsCard
InsightsCard · liveOpen

Guidelines#

Use it for a recorded meeting's insights panel in the meeting hub.

What you provide: detail: MeetingSessionDetailDto. The card reads three parts of it:

  • currentTranscript.segments: sequenceNumber, participantId or speakerLabel, startMs and endMs, and text.
  • participants: id, displayName or email, isInternal, providerIdentity.
  • currentSummary.sentiment: { overall: "positive" | "neutral" | "negative", rationale }.

Behaviour:

  • Speaking time, pace and time-based shares appear only when at least 50% of segments carry timings. Otherwise share is counted in words.
  • Talk balance needs at least one speaker matched to a participant.
  • An internal share above 65%, with an external speaker present, shows the amber hint.
  • A speaker who never matched a participant keeps their raw label.
  • An empty transcript shows "Insights appear once this meeting has a transcript."

Anatomy:

  • A Card. The sentiment is an outline Badge (h-5 px-1.5 text-[10px]): emerald for positive, muted for neutral, red for negative.
  • Stat tiles sit in grid-cols-2 sm:grid-cols-3 gap-2; each tile is rounded-md border-border/60 px-2.5 py-1.5 with a text-[10px] uppercase label.
  • Share bars are h-1.5 rounded-full on bg-muted, at least 2% wide. Their colours cycle through eight -500 hues, starting blue, emerald, amber.
  • The hint is border-amber-500/40 bg-amber-500/10.

Don't present the sentiment as fact: it is model output. Don't turn a diarisation label into a person.

Facts#

GroupAnalytics
ProductMax
Globalwindow.DigitalCrew.InsightsCard
Sourcemax-agent: src/features/meeting-hub/ui/insights-card.tsx
Import in the appimport { InsightsCard } from "@/features/meeting-hub/ui/insights-card";

API#

TypeScript declarations emitted from src/features/meeting-hub/ui/insights-card.tsx.

export declare function InsightsCard({ detail }: {
    detail: MeetingSessionDetailDto;
}): JSX.Element;

Example#

The code of the preview above: plain React.createElement against window.DigitalCrew, with realistic data.

<div id="root" class="p-6"></div>
<script>
(function () {
  var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
  function participant(id, name, email, role, isInternal, relation) {
    return {
      id: id, providerIdentity: null, identityReviewedAt: null, displayName: name, email: email,
      role: role, isInternal: isInternal, prospectId: null,
      matchStatus: isInternal ? "unresolved" : "confirmed", matchConfidence: isInternal ? null : 0.96,
      relationType: relation, contact: null
    };
  }
  var PARTICIPANTS = [
    participant("p-sarah", "Sarah Lindqvist", "sarah@digitalcrew.ai", "organizer", true, "employee"),
    participant("p-claire", "Claire Dubois", "claire.dubois@northwind.com", "external", false, "prospect"),
    participant("p-tom", "Tom Becker", "tom.becker@northwind.com", "external", false, "prospect")
  ];
  // TranscriptSegmentDto rows. Timings follow a ~140 wpm speaking pace so the
  // time-based stats (speaking time, pace, talk share) are shown.
  var LINES = [
    ["p-sarah", "Thanks for making the time, Claire, and good to meet you, Tom. Before we dive in, what made you look at outbound automation this quarter?"],
    ["p-claire", "We doubled the SDR team last year and reply rates went the other way. The board now wants three times pipeline coverage by January, and hiring more reps is not the answer."],
    ["p-sarah", "That is the pattern we see most often. Max runs the research and the first touches across email and LinkedIn, then hands warm replies to your reps with the context already written up. Teams your size usually start with two Digital Workers on one segment and expand once the reply data is in. The workers follow your playbook, your tone and your exclusions, and every message they send is logged against the prospect, so your reps pick up a thread instead of starting one."],
    ["p-tom", "How does it handle the HubSpot sequences we already have running? We have about forty live ones."],
    ["p-sarah", "It reads the enrolments and skips anyone already in a sequence, so nobody gets a double touch. Replies land in HubSpot on the contact as well. Shall we walk through the sync settings with you and your RevOps team on Thursday?"],
    ["p-claire", "Yes, let's do that. And what would a pilot cost for the DACH segment?"],
    ["p-sarah", "One segment and two workers is the Growth plan, billed monthly with no annual commitment for the pilot. I will send the numbers in writing today, with the reply benchmarks we see for logistics."],
    ["p-tom", "That works for us."],
    ["p-sarah", "Great. Is Thursday at ten good for the technical session?"],
    ["p-claire", "Thursday at ten is fine. Send the invite to both of us."]
  ];
  var clock = 0;
  var SEGMENTS = LINES.map(function (l, i) {
    var words = l[1].split(/\s+/).length, start = clock, end = start + Math.round((words / 140) * 60000);
    clock = end + 700;
    return { sequenceNumber: i + 1, speakerLabel: null, participantId: l[0], startMs: start, endMs: end, text: l[1], confidence: 0.94 };
  });
  var DETAIL = {
    id: "mtg_7f3a", title: "Northwind Traders intro call", platform: "google_meet", source: "calendar",
    status: "ready", startedAt: "2026-09-24T09:00:00Z", endedAt: "2026-09-24T09:04:00Z", participantCount: 3,
    hasTranscript: true, hasSummary: true, hasRecording: true, openTaskCount: 2,
    correlationId: "corr_7f3a", captureProvider: "vexa", calendarEventId: "evt_91", bookingMeetingId: null,
    stages: [], participants: PARTICIPANTS,
    currentTranscript: { id: "tr_2", versionNumber: 1, versionType: "raw", createdByType: "provider", changeSummary: null, createdAt: "2026-09-24T09:12:00Z", segments: SEGMENTS },
    currentTranscriptVersionNumber: 1,
    currentSummary: {
      id: "sum_4", versionNumber: 1, status: "draft", summary: null, keyDecisions: [], discussionPoints: [],
      risksOpenQuestions: [], nextSteps: [], sourceTranscriptVersionId: "tr_2", sourceTranscriptVersionNumber: 1,
      generatedAt: "2026-09-24T09:14:00Z",
      sentiment: { overall: "positive", rationale: "Both buyers engaged on pricing and agreed to a technical follow-up on Thursday." }
    },
    summaryStale: false, recordingAvailable: true, recordingId: "rec_7f3a", recordingUrl: null,
    recordingMimeType: "video/webm", recordingPartCount: 1
  };
  function App() {
    return h("div", { className: "max-w-md" }, h(DC.InsightsCard, { detail: DETAIL }));
  }
  ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>