Synthetic Data Engine for CDPs

Generate realistic user journeys with proper event sequences, timing, and cross-dataset relationships. Quickly, reliably, and at scale.

$ npm install -g @synode/cli

Performance

Generates millions of events on a single machine. Scales linearly with worker threads.

~0
Events / sec
single thread
~0
Events / sec
4 worker threads
<0ms
Cold start
zero config
0
Dependencies
at runtime
Live throughput
5,127 events/sec
8k 6k 4k 2k 0
-30s -20s now

Quick Start

Use the CLI to scaffold a project, or import the library directly.

CLI
# Install the CLI globally
npm install -g @synode/cli

# Scaffold a new project
synode init

# Generate 1,000 users from config
synode generate synode.config.ts --users 1000

# Validate config without generating
synode validate synode.config.ts
Library
import {
  defineAction,
  defineAdventure,
  defineJourney,
} from '@synode/core';

const viewProducts = defineAction({
  id: 'view',
  name: 'page_view',
  wait: '10s',
  fields: {
    url: '/products',
    referrer: (ctx) => ctx.faker.internet.url(),
  },
});

const productList = defineAdventure({
  id: 'product-list',
  name: 'Product List',
  wait: '2m',
  actions: [viewProducts],
});

const browse = defineJourney({
  id: 'browse',
  name: 'Browse Products',
  weight: 5,
  cooloff: '30m',
  adventures: [productList],
});
import { generate, FileAdapter } from '@synode/core';

await generate([browse, purchase], {
  time: {
    start: new Date('2026-01-01'),
    duration: '90d',
  },
  simulation: {
    users: 500,
    lanes: 8,
    tick: '15m',
    scatter: 0.15,
  },
  adapter: new FileAdapter({ dir: './output' }),
});
// → Simulated 90 days of activity across 500 users
Reverse Engineering

Already have event data?

Drop a CSV, JSONL, or JSON export and Synode builds your entire config automatically. Journeys, field distributions, datasets, and personas. All detected from your data.

GA4 Segment Mixpanel CSV Custom
$ synode analyze Learn more →
incoming events
page_view /home
click cta
page_view /products
add_to_cart SKU-42
page_view /checkout
purchase $149
page_view /home
search chairs
view_item SKU-17
add_to_cart SKU-17
page_view /home
click cta
page_view /products
add_to_cart SKU-42
page_view /checkout
purchase $149
detected config
Browse → Cart → Purchase
Journey · weight: 0.72 · bounce: 15%
page_view.url
weighted({'/home': 0.5, '/products': 0.3})
Products
Dataset · 42 items · 5 fields
Persona
locale, device, country distributions

How It Works

Three pillars feed into a tick-driven simulation pipeline that produces realistic event streams.

Input
Users

Synthetic identities with weighted persona distributions

Define synthetic identities with weighted persona distributions. Each user gets a unique profile with consistent attributes across all journeys.
Datasets

Pre-generated entity tables with typed row access

Pre-generate entity tables (products, locations, etc.) that actions can reference. Typed with InferDatasetRow for compile-time safety.
Journeys

Behavioral flows with weights, cooloffs, and prerequisites

Behavioral flows with weights, cooloffs, and prerequisites. Weights control how often a journey is selected each tick. Cooloffs prevent re-entry for a configurable duration.
Pipeline
Tick Clock Time driver
Advances simulated time in configurable steps (e.g. 15m). Each tick wakes lanes and schedules user activity within the time window.
Lanes User slots
Concurrent user slots processed each tick. Each lane pulls the next available user from the pool and runs their journey selection.
Journey Selection
Weighted random selection filters out journeys blocked by cooloffs or unmet prerequisites, then picks one proportional to its weight.
Adventure Session
A session or interaction block with configurable wait time before the first action. Scatter adds jitter to timestamps for realism.
Event[] Output
Atomic tracking points with id, userId, sessionId, name, timestamp, and payload. Sent to your chosen OutputAdapter.