Skip to content

Headless Anomaly Detection, Custom UI Live Demo ​

DatastripesAnomaly is the fastest way to ship anomaly detection, but every piece of it is built on public APIs you can use directly when you want your own UI:

  • useAnomalyDetection, a React hook (@datastripes/anomaly/react) and a Vue composable (@datastripes/anomaly/vue) that run the engine and hand you reactive result, isLoading, error, and algorithm state, plus an execute() function.
  • executeAnomalyDetection(), the plain async function from the root @datastripes/anomaly entry, with no UI framework involved at all.

Live demo: a custom widget on useAnomalyDetection ​

Everything below (the algorithm picker, the metric tiles, the anomalies table) is ordinary page markup. The only Datastripes code is the useAnomalyDetection call from @datastripes/anomaly/vue.

Changing the algorithm re-runs detection automatically: algorithm is a reactive ref returned by the composable, and the composable re-executes when it changes. Recalculate calls execute() explicitly.

Source (Vue) ​

vue
<script setup>
import { computed } from 'vue';
import { useAnomalyDetection } from '@datastripes/anomaly/vue';

const { result, isLoading, algorithm, execute } = useAnomalyDetection({
  data: saasData,
  algorithm: 'ensemble',
  columnMapping: { timeKey: 'date', targetKey: 'annual_recurring_revenue' }
});

const anomalies = computed(() => (result.value?.points ?? []).filter((p) => p.isAnomaly));
</script>

<template>
  <select v-model="algorithm">
    <option value="ensemble">Ensemble (majority vote)</option>
    <option value="zscore">Z-score (global)</option>
    <option value="iqr">IQR</option>
  </select>
  <button @click="execute()">Recalculate</button>

  <p v-if="isLoading && !result">Scanning for anomalies…</p>
  <ul v-else-if="result">
    <li>Anomaly rate: {{ result.metrics.anomalyRate.toFixed(2) }}%</li>
    <li v-for="p in anomalies" :key="p.index">{{ p.dateStr }}: {{ Math.round(p.value) }} ({{ p.severity }})</li>
  </ul>
</template>

Source (React) ​

The React hook has the same shape, with setter functions instead of refs:

tsx
import { useAnomalyDetection } from '@datastripes/anomaly/react';

export function ArrAnomalyWidget({ data }) {
  const { result, isLoading, algorithm, setAlgorithm, execute } = useAnomalyDetection({
    data,
    algorithm: 'ensemble',
    columnMapping: { timeKey: 'date', targetKey: 'annual_recurring_revenue' }
  });

  if (isLoading && !result) return <p>Scanning for anomalies…</p>;
  if (!result) return null;

  return (
    <div>
      <select value={algorithm} onChange={(e) => setAlgorithm(e.target.value as any)}>
        <option value="ensemble">Ensemble (majority vote)</option>
        <option value="zscore">Z-score (global)</option>
        <option value="iqr">IQR</option>
      </select>
      <button onClick={() => execute()}>Recalculate</button>
      <p>Anomaly rate: {result.metrics.anomalyRate.toFixed(2)}%</p>
    </div>
  );
}

No UI at all: executeAnomalyDetection() ​

When you don't need any component state, for example to feed your own chart library or to run detection inside a Web Worker, call the engine directly from the root entry:

ts
import { executeAnomalyDetection } from '@datastripes/anomaly';

const result = await executeAnomalyDetection({
  data: myRecords,       // records, a CSV string, or a JSON array
  algorithm: 'ensemble'
});

const anomalies = result.points.filter((p) => p.isAnomaly);
console.log('Anomalies:', result.metrics.anomalyCount);
console.log('Execution time:', result.metrics.executionTimeMs, 'ms');

The Scatter detection demo is built the same way, but calls executeScatterAnomalyDetection() for bivariate (x, y) data instead. See Types for the full AnomalyOutput shape.