Skip to content

Headless Forecasting, Custom UI Live Demo ​

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

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

Live demo: a custom widget on useWasmForecast ​

Everything below (the algorithm picker, the metric tiles, the five-day table) is ordinary page markup. The only Datastripes code is the useWasmForecast call from @datastripes/forecast/vue.

Changing the algorithm re-runs the forecast 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 { useWasmForecast } from '@datastripes/forecast/vue';

const { result, isLoading, algorithm, execute } = useWasmForecast({
  data: saasData,
  horizon: 21,
  algorithm: 'holt_winters_add',
  columnMapping: { timeKey: 'date', targetKey: 'annual_recurring_revenue' }
});

const nextFive = computed(() =>
  (result.value?.points ?? []).filter((p) => p.forecast != null && p.actual == null).slice(0, 5)
);
</script>

<template>
  <select v-model="algorithm">
    <option value="holt_winters_add">Holt-Winters (additive)</option>
    <option value="prophet_lite">Prophet-lite</option>
    <option value="arima">ARIMA</option>
  </select>
  <button @click="execute()">Recalculate</button>

  <p v-if="isLoading && !result">Running the forecast…</p>
  <ul v-else-if="result">
    <li>R²: {{ (result.metrics.r2 * 100).toFixed(1) }}%</li>
    <li v-for="p in nextFive" :key="p.index">{{ p.dateStr }}: {{ Math.round(p.forecast) }}</li>
  </ul>
</template>

Source (React) ​

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

tsx
import { useWasmForecast } from '@datastripes/forecast/react';

export function ArrForecastWidget({ data }) {
  const { result, isLoading, algorithm, setAlgorithm, execute } = useWasmForecast({
    data,
    horizon: 21,
    algorithm: 'holt_winters_add',
    columnMapping: { timeKey: 'date', targetKey: 'annual_recurring_revenue' }
  });

  if (isLoading && !result) return <p>Running the forecast…</p>;
  if (!result) return null;

  return (
    <div>
      <select value={algorithm} onChange={(e) => setAlgorithm(e.target.value as any)}>
        <option value="holt_winters_add">Holt-Winters (additive)</option>
        <option value="prophet_lite">Prophet-lite</option>
        <option value="arima">ARIMA</option>
      </select>
      <button onClick={() => execute()}>Recalculate</button>
      <p>R²: {(result.metrics.r2 * 100).toFixed(1)}%</p>
    </div>
  );
}

No UI at all: executeForecast() ​

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

ts
import { executeForecast } from '@datastripes/forecast';

const result = await executeForecast({
  data: myRecords,          // records, a CSV string, or a JSON array
  algorithm: 'prophet_lite',
  horizon: 30
});

const forecastPoints = result.points.filter((p) => p.forecast != null && p.actual == null);
console.log('R²:', result.metrics.r2);
console.log('Execution time:', result.metrics.executionTimeMs, 'ms');

The What-if scenarios demo is built this way: it calls executeForecast() on every scenario change and passes the result to the standalone DatastripesKpiDeck and DatastripesForecastChart components. See Types for the full ForecastOutput shape.