Skip to content

Realtime Events Quickstart

Get live updates in your application with Centrali's Realtime service. Subscribe to record events and receive instant notifications when data changes.

Overview

Centrali Realtime uses Server-Sent Events (SSE) to stream record changes to your application in real-time. No polling required.

// Subscribe to order updates
centrali.realtime.subscribe({
  structures: ['order'],
  events: ['record_created', 'record_updated'],
  onEvent: (event) => {
    console.log(`Order ${event.recordId} was ${event.event}`);
  }
});

Installation

Install the Centrali SDK:

npm install @centrali-io/centrali-sdk
# or
yarn add @centrali-io/centrali-sdk

Quick Start

1. Initialize the SDK

import { CentraliSDK } from '@centrali-io/centrali-sdk';

const centrali = new CentraliSDK({
  baseUrl: 'https://api.centrali.io',
  workspaceId: 'my-workspace',
  token: 'your-bearer-token'  // or use clientId/clientSecret
});

2. Subscribe to Events

const subscription = centrali.realtime.subscribe({
  // Filter by structures (optional)
  structures: ['order', 'customer'],

  // Filter by event types (optional)
  events: ['record_created', 'record_updated'],

  // Handle incoming events
  onEvent: (event) => {
    console.log('Event received:', event);
    console.log('Structure:', event.recordSlug);
    console.log('Record ID:', event.recordId);
    console.log('Data:', event.data);
  },

  // Handle errors (optional)
  onError: (error) => {
    console.error('Realtime error:', error.code, error.message);
  },

  // Connection callbacks (optional)
  onConnected: () => console.log('Connected!'),
  onDisconnected: (reason) => console.log('Disconnected:', reason)
});

3. Unsubscribe When Done

// Stop receiving events
subscription.unsubscribe();

Event Types

Event Description
record_created A new record was created
record_updated An existing record was modified
record_deleted A record was deleted

Event Payload

Each event includes:

interface RealtimeRecordEvent {
  event: 'record_created' | 'record_updated' | 'record_deleted';
  workspaceSlug: string;
  recordSlug: string;     // Structure's slug (e.g., "order")
  recordId: string;
  data: object;           // Record data (or {before, after} for updates)
  timestamp: string;      // ISO timestamp
  createdBy?: string;     // User who created (for creates)
  updatedBy?: string;     // User who updated (for updates)
}

Complete Example: React Dashboard

import { useEffect, useState } from 'react';
import { CentraliSDK, RealtimeRecordEvent } from '@centrali-io/centrali-sdk';

function OrderDashboard() {
  const [orders, setOrders] = useState<Order[]>([]);
  const [connected, setConnected] = useState(false);

  useEffect(() => {
    const centrali = new CentraliSDK({
      baseUrl: 'https://api.centrali.io',
      workspaceId: 'my-workspace',
      token: localStorage.getItem('token')
    });

    // 1. Fetch initial data
    centrali.queryRecords('order', { sort: '-createdAt', limit: 50 })
      .then(response => setOrders(response.data));

    // 2. Subscribe to realtime updates
    const subscription = centrali.realtime.subscribe({
      structures: ['order'],
      onEvent: (event) => {
        switch (event.event) {
          case 'record_created':
            setOrders(prev => [event.data as Order, ...prev]);
            break;
          case 'record_updated':
            setOrders(prev => prev.map(o =>
              o.id === event.recordId ? event.data.after : o
            ));
            break;
          case 'record_deleted':
            setOrders(prev => prev.filter(o => o.id !== event.recordId));
            break;
        }
      },
      onConnected: () => setConnected(true),
      onDisconnected: () => setConnected(false)
    });

    // 3. Cleanup on unmount
    return () => subscription.unsubscribe();
  }, []);

  return (
    <div>
      <div className={connected ? 'status-online' : 'status-offline'}>
        {connected ? 'Live' : 'Reconnecting...'}
      </div>
      <ul>
        {orders.map(order => (
          <li key={order.id}>{order.customerName} - ${order.total}</li>
        ))}
      </ul>
    </div>
  );
}

Filtering Events

By Structure

Only receive events for specific structures:

centrali.realtime.subscribe({
  structures: ['order', 'invoice'],  // Only these structures
  onEvent: handleEvent
});

By Event Type

Only receive specific event types:

centrali.realtime.subscribe({
  events: ['record_created'],  // Only new records
  onEvent: handleEvent
});

By Data Values (CFL Filter)

Filter events based on record data using Centrali Filter Language:

centrali.realtime.subscribe({
  structures: ['order'],
  filter: 'data.status:shipped',  // Only shipped orders
  onEvent: handleEvent
});

See Filtering Guide for complete filter syntax.

Important: Initial Sync Pattern

Realtime only delivers events that occur after you connect. To build a complete UI:

  1. Fetch current data first - Query records to get the initial state
  2. Subscribe to realtime - Start receiving live updates
  3. Merge updates - Apply incoming events to your local state
// 1. Fetch initial data
const initialData = await centrali.queryRecords('order', { limit: 100 });
setOrders(initialData.data);

// 2. Subscribe to updates (events are applied to initialData)
const subscription = centrali.realtime.subscribe({
  structures: ['order'],
  onEvent: (event) => {
    // Merge event into existing state
    updateLocalState(event);
  }
});

Connection Behavior

Automatic Reconnection

The SDK automatically reconnects with exponential backoff: - Initial delay: 1 second - Max delay: 30 seconds - Max attempts: 10

Connection Timeout

Connections automatically close after 1 hour. The SDK will reconnect automatically.

Keep-Alive

The server sends ping comments every 30 seconds to maintain the connection.

Next Steps