Skip to main content
The Ablo SDK is designed for long-lived presentations that you update repeatedly. Rather than recreating a deck from scratch on every run, you create it once, store the IDs of the resources you care about, and then issue targeted patches on subsequent runs. This keeps your deck’s history intact, avoids unnecessary churn, and is significantly more efficient for large presentations.

The hold-the-ID pattern

ablo.decks.create() returns a DeckResource containing the id of every resource that was created — the deck itself, each slide, and each layer. Store these IDs in your own persistence layer (a database, a config file, an environment variable) on the first run, and use them directly on every subsequent run.
import { Decks, barChart } from '@abloatai/decks';

const ablo = new Decks(process.env.ABLO_API_KEY);

// ── First run: create and store IDs ──────────────────────────────────
const deck = await ablo.decks.create({
  title: 'Live Dashboard',
  slides: [
    {
      title: 'KPIs',
      layers: [
        {
          type: 'bar',
          data: initialData,
          at: { x: 160, y: 200, w: 1600, h: 700 },
        },
      ],
    },
  ],
});

const chartLayerId = deck.slides[0].layers[0].id;
// Store chartLayerId somewhere durable — e.g. a database or .env file

// ── Subsequent runs: update the existing layer with fresh data ────────
await ablo.layers.update({
  id: chartLayerId,
  data: barChart({ data: freshData }).data,
});
You only need to call decks.create() once per presentation. On every run after that, go straight to the update methods using your stored IDs.

Updating a deck

Use ablo.decks.update() to change deck-level metadata. All fields except id are optional; only the fields you provide are changed.
await ablo.decks.update({
  id: deckId,
  title: 'Live Dashboard — Updated',
  themeId: 'theme_dark_123',
  icon: 'chart-bar',
  color: '#0EA5E9',
});
Available fields:
FieldTypeDescription
idstringThe deck to update (required).
titlestringNew deck title.
themeIdstring | nullApply or remove a theme.
layoutIdstring | nullChange the layout container.
iconstringDeck icon key.
colorstringAccent color (hex).

Updating a slide

Use ablo.slides.update() to change a slide’s metadata or settings.
await ablo.slides.update({
  id: slideId,
  title: 'KPIs — Week 42',
  notes: 'Present after the revenue summary.',
  background: { type: 'solid', color: '#0F172A' },
});
Available fields:
FieldTypeDescription
idstringThe slide to update (required).
titlestringNew slide title.
notesstringSpeaker notes.
backgroundSlideBackgroundInputSolid color, gradient, or image.
sizeSlideSizePresetIdSwitch to a size preset (e.g. '16:9', '4:3').
templateIdstringApply a layout template.

Updating a layer

Use ablo.layers.update() for field-level patches. This overwrites the entire field you specify, so pass the complete new value.
// Move the layer to a new position
await ablo.layers.update({
  id: chartLayerId,
  position: { x: 160, y: 160, width: 1600, height: 800 },
});

// Replace the chart data entirely
await ablo.layers.update({
  id: chartLayerId,
  data: barChart({ data: freshData }).data,
});

// Update the layer's style
await ablo.layers.update({
  id: textLayerId,
  style: { color: '#FFFFFF', fontSize: '48px' },
});
Available fields:
FieldTypeDescription
idstringThe layer to update (required).
positionPartial<LayerPosition>Move or resize (x, y, width, height, rotation).
zIndexnumberStacking order.
contentJsonunknownFull TipTap document (text layers).
dataRecord<string, unknown>Chart / table payload.
styleRecord<string, unknown>CSS-like style properties.
imageFillLayerImageFillImage fill for shape layers.

Typed ops for charts, tables, and text

For chart, table, and text layers, ablo.layers.applyOp() lets you apply a targeted, typed operation instead of replacing the entire payload. The SDK reads the current layer, applies the op with the same reducer the editor uses, and writes the result back — all in one method call.
// Append a data series to a chart
await ablo.layers.applyOp(chartLayerId, {
  type: 'setDataSeries',
  seriesIndex: 0,
  values: [120, 168, 201, 245],
});

// Append a row to a table
await ablo.layers.applyOp(tableLayerId, {
  type: 'appendRow',
  cells: [{ value: 'Q4' }, { value: '$2.4M' }, { value: '+22%' }],
});

// Change the font weight on all text in a text layer
await ablo.layers.applyOp(textLayerId, {
  type: 'setFontWeight',
  weight: 700,
});
layers.applyOp() performs a read-modify-write internally, so it requires a readable client. The standard new Decks(apiKey) constructor always provides one. If you ever construct the SDK with a commit-only transport, applyOp will throw a descriptive error.

Reading resources

Before updating, you may need to read the current state of a resource. Every resource type has a retrieve() method, and collections have a list() method.
const deck = await ablo.decks.retrieve(deckId);
console.log(deck.title, deck.layoutId);

Deleting resources

Every resource type has a delete() method. Deletions are atomic commits like all other mutations.
// Delete a single layer
await ablo.layers.delete(layerId);

// Delete a slide (and all its layers)
await ablo.slides.delete(slideId);

// Delete a deck (and everything inside it)
await ablo.decks.delete(deckId);
decks.delete() removes the deck and all of its slides and layers permanently. There is no undo. Make sure you are operating on the correct ID before calling it.

Full live-update example

The following pattern is typical for a dashboard or report that regenerates on a schedule.
import { Decks, barChart } from '@abloatai/decks';

const ablo = new Decks(process.env.ABLO_API_KEY);

// On first run, create the deck and store the IDs you will reuse.
async function bootstrap(): Promise<{ deckId: string; chartLayerId: string }> {
  const deck = await ablo.decks.create({
    title: 'Weekly KPI Dashboard',
    slides: [
      {
        title: 'Revenue',
        layers: [
          {
            type: 'text',
            text: 'Revenue by Week',
            style: 'h1',
            at: { x: 160, y: 60, w: 1600, h: 120 },
          },
          {
            type: 'bar',
            data: [],
            at: { x: 160, y: 220, w: 1600, h: 720 },
          },
        ],
      },
    ],
  });

  return {
    deckId: deck.id,
    chartLayerId: deck.slides[0].layers[1].id,
  };
}

// On every subsequent run, update the chart with fresh data.
async function refresh(chartLayerId: string, weeklyData: Array<{ label: string; value: number }>) {
  await ablo.layers.update({
    id: chartLayerId,
    data: barChart({ data: weeklyData }).data,
  });
}

// Update the deck title to reflect the latest refresh time
async function stampTitle(deckId: string) {
  const now = new Date().toLocaleDateString('en-US', {
    month: 'short', day: 'numeric', year: 'numeric',
  });
  await ablo.decks.update({ id: deckId, title: `Weekly KPI Dashboard — ${now}` });
}