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

# ClickUp on Vortex IQ

> Monitor ClickUp performance signals, run automated checks, and prepare approved work through Vortex IQ.

export const CapabilityPage = ({data}) => {
  const d = data || ({});
  const [tab, setTab] = useState('overview');
  const [sel, setSel] = useState(null);
  const [q, setQ] = useState('');
  const [outcome, setOutcome] = useState('');
  const [status, setStatus] = useState('');
  const [limit, setLimit] = useState(8);
  const monitor = d.monitor || [];
  const audits = d.audits || [];
  const autos = d.autos || [];
  const outcomes = useMemo(() => {
    const s = new Set();
    monitor.forEach(m => s.add(m.o));
    audits.forEach(a => s.add(a.o));
    return [...s].sort();
  }, [monitor, audits]);
  const rows = useMemo(() => {
    const t = q.trim().toLowerCase();
    if (tab === 'monitor') {
      return monitor.filter(m => (!t || (m.n + ' ' + (m.d || '')).toLowerCase().includes(t)) && (!outcome || m.o === outcome));
    }
    if (tab === 'audit') {
      return audits.filter(a => (!t || (a.n + ' ' + (a.why || '')).toLowerCase().includes(t)) && (!outcome || a.o === outcome) && (!status || a.s === status));
    }
    if (tab === 'automate') {
      return autos.filter(w => !t || (w.n + ' ' + (w.d || '')).toLowerCase().includes(t));
    }
    return [];
  }, [tab, q, outcome, status, monitor, audits, autos]);
  const pill = (text, kind) => {
    const tone = kind === 'good' ? {
      color: '#1f9e54',
      borderColor: '#1f9e54',
      background: '#ecf8f110'
    } : kind === 'warn' ? {
      color: '#c07a17',
      borderColor: '#c07a17',
      background: '#fdf6e910'
    } : kind === 'bad' ? {
      color: '#c53527',
      borderColor: '#c53527',
      background: '#fdf0ee10'
    } : kind === 'brand' ? {
      color: '#5529d6',
      borderColor: '#5529d6'
    } : {
      color: 'inherit',
      borderColor: 'currentColor',
      opacity: 0.65
    };
    return <span key={text} style={{
      fontSize: '10.5px',
      fontFamily: 'ui-monospace, monospace',
      border: '1px solid',
      borderRadius: '999px',
      padding: '2px 8px',
      whiteSpace: 'nowrap',
      ...tone
    }}>
        {text}
      </span>;
  };
  const sevKind = s => s === 'critical' ? 'bad' : s === 'high' ? 'warn' : 'muted';
  const fixKind = s => s === 'Prepared fix' ? 'good' : s === 'Candidate remediation' ? 'warn' : 'muted';
  const card = (item, kind) => {
    const title = item.n;
    const badges = kind === 'monitor' ? [pill(item.o, 'brand'), pill(item.a === 'Watch only' || item.a === 'Merchant rule' ? item.a : `Alert ${item.a}`, 'muted')] : kind === 'audit' ? [pill(item.sev, sevKind(item.sev)), pill(item.s, fixKind(item.s))] : [pill(item.role, 'brand'), pill(item.ready, 'good')];
    const body = kind === 'monitor' ? item.nc ? 'Description pending editorial review; the signal is live.' : item.d : kind === 'audit' ? item.why : item.d;
    return <button key={title} onClick={() => setSel({
      kind,
      item
    })} style={{
      display: 'block',
      width: '100%',
      textAlign: 'left',
      border: '1px solid rgba(128,128,128,.28)',
      borderRadius: '10px',
      padding: '12px 14px',
      marginBottom: '8px',
      background: 'transparent',
      cursor: 'pointer',
      font: 'inherit',
      color: 'inherit'
    }}>
        <div style={{
      display: 'flex',
      gap: '10px',
      justifyContent: 'space-between',
      alignItems: 'flex-start',
      flexWrap: 'wrap'
    }}>
          <strong style={{
      fontSize: '14px'
    }}>{title}</strong>
          <span style={{
      display: 'flex',
      gap: '5px',
      flexWrap: 'wrap'
    }}>{badges}</span>
        </div>
        {body ? <div style={{
      fontSize: '12.5px',
      opacity: 0.72,
      marginTop: '4px'
    }}>{body}</div> : null}
      </button>;
  };
  const tabBtn = (id, label) => <button key={id} onClick={() => {
    setTab(id);
    setLimit(8);
    setQ('');
  }} style={{
    border: 0,
    background: 'none',
    font: 'inherit',
    fontWeight: 600,
    fontSize: '14px',
    padding: '9px 14px',
    cursor: 'pointer',
    color: tab === id ? '#5529d6' : 'inherit',
    opacity: tab === id ? 1 : 0.65,
    borderBottom: tab === id ? '2px solid #5529d6' : '2px solid transparent'
  }}>
      {label}
    </button>;
  const inputStyle = {
    border: '1px solid rgba(128,128,128,.3)',
    borderRadius: '999px',
    padding: '7px 13px',
    font: 'inherit',
    fontSize: '13px',
    background: 'transparent',
    color: 'inherit'
  };
  return <div style={{
    position: 'relative'
  }}>
      {}
      <div style={{
    display: 'grid',
    gridTemplateColumns: 'repeat(auto-fit,minmax(120px,1fr))',
    gap: '10px',
    margin: '18px 0'
  }}>
        {(d.stats || []).map(([v, l]) => <div key={l} style={{
    border: '1px solid rgba(128,128,128,.28)',
    borderRadius: '10px',
    padding: '11px 13px'
  }}>
            <div style={{
    fontSize: v.length > 6 ? '15px' : '21px',
    fontWeight: 700,
    letterSpacing: '-.02em',
    color: v.length > 6 ? '#5529d6' : 'inherit'
  }}>{v}</div>
            <div style={{
    fontSize: '11px',
    opacity: 0.66
  }}>{l}</div>
          </div>)}
      </div>

      <div style={{
    display: 'flex',
    gap: '4px',
    borderBottom: '1px solid rgba(128,128,128,.25)',
    marginBottom: '16px',
    flexWrap: 'wrap'
  }}>
        {tabBtn('overview', 'Overview')}
        {tabBtn('monitor', `Monitor (${monitor.length})`)}
        {tabBtn('audit', `Audit (${audits.length})`)}
        {tabBtn('automate', 'Automate')}
      </div>

      {tab === 'overview' && <div>
          <div style={{
    display: 'grid',
    gridTemplateColumns: 'repeat(auto-fit,minmax(240px,1fr))',
    gap: '10px'
  }}>
            {outcomes.map(o => <div key={o} style={{
    border: '1px solid rgba(128,128,128,.28)',
    borderLeft: '3px solid #5529d6',
    borderRadius: '10px',
    padding: '11px 14px'
  }}>
                <strong style={{
    fontSize: '13.5px'
  }}>{o}</strong>
              </div>)}
          </div>
          <p style={{
    fontSize: '13px',
    opacity: 0.75,
    marginTop: '16px'
  }}>
            Every capability follows the same controlled sequence: connect, monitor, detect, recommend,
            approve, execute, verify. Nothing changes a connected system without the approval step.
          </p>
        </div>}

      {tab !== 'overview' && <div>
          <div style={{
    display: 'flex',
    gap: '8px',
    marginBottom: '12px',
    flexWrap: 'wrap'
  }}>
            <input style={{
    ...inputStyle,
    flex: 1,
    minWidth: '170px'
  }} placeholder={`Search ${tab === 'monitor' ? 'signals' : tab === 'audit' ? 'checks' : 'workflows'}...`} value={q} onChange={e => {
    setQ(e.target.value);
    setLimit(8);
  }} />
            {tab !== 'automate' && <select style={inputStyle} value={outcome} onChange={e => {
    setOutcome(e.target.value);
    setLimit(8);
  }}>
                <option value="">All outcomes</option>
                {outcomes.map(o => <option key={o} value={o}>{o}</option>)}
              </select>}
            {tab === 'audit' && <select style={inputStyle} value={status} onChange={e => {
    setStatus(e.target.value);
    setLimit(8);
  }}>
                <option value="">All fix statuses</option>
                <option>Prepared fix</option>
                <option>Candidate remediation</option>
                <option>Report only</option>
              </select>}
          </div>

          {rows.length === 0 && tab === 'automate' && <div style={{
    border: '1px dashed #5529d6',
    borderRadius: '10px',
    padding: '15px'
  }}>
              <strong style={{
    fontSize: '14px'
  }}>Ready to build your first {d.name} workflow</strong>
              <p style={{
    fontSize: '12.5px',
    opacity: 0.75,
    margin: '6px 0 0'
  }}>
                Vortex IQ is integrated with {d.reads} read and {d.writes} write operations on {d.name}.
                Pick a trigger, add them as steps, and every step that changes data pauses for approval.
              </p>
            </div>}
          {rows.length === 0 && tab !== 'automate' && <div style={{
    opacity: 0.6,
    fontSize: '13px'
  }}>Nothing matches this search or filter.</div>}

          {rows.slice(0, limit).map(r => card(r, tab))}

          {rows.length > limit && <button onClick={() => setLimit(rows.length)} style={{
    ...inputStyle,
    display: 'block',
    margin: '10px auto 0',
    cursor: 'pointer'
  }}>
              View all {rows.length}
            </button>}
        </div>}

      {}
      {sel && <>
          <div onClick={() => setSel(null)} style={{
    position: 'fixed',
    inset: 0,
    background: 'rgba(10,6,26,.45)',
    zIndex: 40
  }} />
          <aside style={{
    position: 'fixed',
    top: 0,
    right: 0,
    width: 'min(430px, 94vw)',
    height: '100vh',
    overflowY: 'auto',
    background: 'var(--background, #fff)',
    backgroundColor: 'light-dark(#fff, #0c061f)',
    borderLeft: '1px solid rgba(128,128,128,.3)',
    padding: '20px 22px',
    zIndex: 50
  }}>
            <button onClick={() => setSel(null)} style={{
    float: 'right',
    border: '1px solid rgba(128,128,128,.3)',
    background: 'transparent',
    color: 'inherit',
    borderRadius: '999px',
    width: '30px',
    height: '30px',
    cursor: 'pointer'
  }}>
              ×
            </button>
            <DetailBody sel={sel} d={d} pill={pill} sevKind={sevKind} fixKind={fixKind} />
          </aside>
        </>}
    </div>;
};

Monitor ClickUp performance signals, run automated checks, and prepare approved work through Vortex IQ.

No changes are made without the configured approval policy. Read-only operations do not modify the connected system; schedules, access scopes, API usage and data handling remain governed by Vortex IQ controls.

[Connect or manage this source](https://app.vortexiq.ai/workbench/settings/sources) · [How connecting works](/integrations/connector-catalogue) · [Create a workflow](https://app.vortexiq.ai/workbench/flows/create?connector=clickup)

<CapabilityPage data={{"name": "ClickUp", "reads": 9, "writes": 3, "stats": [["23", "performance signals"], ["6", "automated checks"], ["0", "prepared fixes"], ["0", "proven workflows"], ["12", "API operations"]], "resRows": [{"n": "listtasks", "r": 1, "w": 1}, {"n": "folderlists", "r": 1, "w": 0}, {"n": "lists", "r": 1, "w": 0}, {"n": "listmembers", "r": 1, "w": 0}, {"n": "spacefolders", "r": 1, "w": 0}, {"n": "spacelists", "r": 1, "w": 0}, {"n": "tasks", "r": 0, "w": 1}, {"n": "taskcomments", "r": 0, "w": 1}], "opsPhrase": "over 13,000", "connPhrase": "more than 200", "monitor": [{"n": "Abandoned Findings (\u003e14d no movement)", "o": "Protect revenue", "a": "5 / 15", "d": "Findings sat in the backlog with no date_updated change for two weeks - the ones losing money silently.", "nc": false}, {"n": "Finding Resolution Rate (90d)", "o": "Run operations", "a": "75 / 50", "d": "What share of audit findings actually got closed via ClickUp. Green \u003e=75%, amber 50-74%, red \u003c50%.", "nc": false}, {"n": "VortexIQ Findings Open", "o": "Run operations", "a": "Merchant rule", "d": "Tasks we filed from audit findings that aren't closed yet - the live backlog of things VortexIQ surfaced.", "nc": false}, {"n": "Avg Cycle Time (days)", "o": "Run operations", "a": "3 / 7", "d": "Avg time from in-progress to closed - how long work takes once it's started.", "nc": false}, {"n": "Avg Lead Time (days)", "o": "Run operations", "a": "Merchant rule", "d": "Avg time from task creation to closed - total turnaround including queue time.", "nc": false}, {"n": "Avg Time-to-Fix (days)", "o": "Run operations", "a": "Merchant rule", "d": "Avg days from finding creation to ClickUp task close, last 90 days.", "nc": false}, {"n": "Backlog by Priority", "o": "Run operations", "a": "Merchant rule", "d": "Open-task distribution across ClickUp priority levels (urgent / high / normal / low).", "nc": false}, {"n": "Backlog by Status", "o": "Run operations", "a": "Watch only", "d": "Open-task distribution across ClickUp custom statuses.", "nc": false}, {"n": "Blocked Tickets", "o": "Run operations", "a": "3 / 8", "d": "Tasks in a blocked / impeded status - the operational queue's stuck list.", "nc": false}, {"n": "Cycle Time by Priority", "o": "Run operations", "a": "Merchant rule", "d": "Cycle time split by priority - urgent work should not sit.", "nc": false}, {"n": "In Progress", "o": "Run operations", "a": "Watch only", "d": "Tasks in an in-flight custom status - the active work queue.", "nc": false}, {"n": "Oldest Open (days)", "o": "Run operations", "a": "Merchant rule", "d": "Age of the oldest open task - backlog rot signal when it climbs past 90 days.", "nc": false}, {"n": "Open Tickets", "o": "Run operations", "a": "Merchant rule", "d": "Open tasks across all VortexIQ Lists (status.type != closed, not archived) - top-of-funnel backlog volume.", "nc": false}, {"n": "Overloaded Assignees (\u003e10 open)", "o": "Run operations", "a": "0 / 1", "d": "People with \u003e10 open tasks - capacity bottleneck candidates.", "nc": false}, {"n": "Scope Added Mid-Sprint", "o": "Run operations", "a": "Merchant rule", "d": "Tasks added to the active sprint after start - scope-creep signal.", "nc": false}, {"n": "Sprint Progress", "o": "Run operations", "a": "80 / 50", "d": "Completed vs total sprint scope for the active sprint folder.", "nc": false}, {"n": "Sprint Velocity (avg)", "o": "Run operations", "a": "Merchant rule", "d": "Avg completed points/tasks over the last 5 sprints.", "nc": false}, {"n": "Throughput Trend", "o": "Run operations", "a": "Watch only", "d": "Rolling 30-day closed-task trend.", "nc": false}, {"n": "Tickets Resolved (7d)", "o": "Run operations", "a": "Merchant rule", "d": "Tasks closed in the last 7 days vs the prior 7 - drain rate.", "nc": false}, {"n": "Tickets by Assignee", "o": "Run operations", "a": "Merchant rule", "d": "Open-task count per ClickUp assignee - capacity at a glance.", "nc": false}, {"n": "Unassigned Tickets", "o": "Run operations", "a": "5 / 20", "d": "Open tasks with no assignee - work nobody owns.", "nc": false}, {"n": "VortexIQ Findings In Progress", "o": "Run operations", "a": "Watch only", "d": "Findings actively being worked - in a custom or done (review-pending) status.", "nc": false}, {"n": "VortexIQ Findings Resolved", "o": "Run operations", "a": "Watch only", "d": "Findings closed in the last 90 days - the proof the loop is working.", "nc": false}], "audits": [{"n": "API token / credential expired or about to expire", "o": "Control risk and change", "sev": "critical", "s": "Report only", "why": "Once this credential expires, VortexIQ stops seeing ticket and project activity from this tool entirely, and every backlog, capacity and cycle-time finding here goes stale from that moment, silently, until someone notices the numbers stopped updating.", "codes": ["PM-AUTH-001"]}, {"n": "VortexIQ finding resolution rate below 50%", "o": "Grow revenue", "sev": "high", "s": "Report only", "why": "Fewer than half of the tickets VortexIQ has created from its audit findings ever get resolved. That means the issues this dashboard surfaces, broken tracking, catalog problems, security gaps, are being logged but not fixed at better than a coin-flip rate, so the audit is producing visibility without", "codes": ["PM-RESOLUTION-001"]}, {"n": "VortexIQ-created findings abandoned (\u003e14d no status change)", "o": "Protect revenue", "sev": "high", "s": "Report only", "why": "More than 5 tickets VortexIQ created from its own audit findings have sat untouched for over two weeks. Whatever those findings flagged, whether it was a broken tracking pixel, a stockout, or a security gap, is still unresolved, and the audit that caught it is not doing its job if the resulting tick", "codes": ["PM-ABANDONED-001"]}, {"n": "Assignee overloaded (\u003e10 open tickets)", "o": "Protect revenue", "sev": "medium", "s": "Report only", "why": "At least one person is carrying more than 10 open tickets at once. Beyond the burnout risk, this usually means their tickets move slower than the team average simply from context-switching, which shows up later as missed deadlines that look unrelated to the real cause.", "codes": ["PM-CAPACITY-001"]}, {"n": "Backlog blocked-tickets count growing", "o": "Grow revenue", "sev": "medium", "s": "Report only", "why": "Blocked tickets grew more than 50% versus the prior period. Blocked work does not disappear, it queues up, so a growth rate this size now usually means a larger backlog crunch and slower delivery in the weeks ahead, once those tickets eventually unblock all at once.", "codes": ["PM-BACKLOG-001"]}, {"n": "Cycle time degrading \u003e 25% week-over-week", "o": "Run operations", "sev": "medium", "s": "Report only", "why": "Tickets are taking over 25% longer to complete than they did the prior week. A shift this fast usually has a specific, findable cause, catching it this week is far easier than after it has become the new normal and nobody remembers what changed.", "codes": ["PM-CYCLE-001"]}], "autos": [], "inValidation": 0}} />
