CloudSignal Docs
Getting StartedFeatures

Message retention

Use MQTT retained messages to store last-known-state and deliver immediate updates to new subscribers on CloudSignal.

Retained messages let CloudSignal store the last message published to a topic. When a new client subscribes, it immediately receives the retained message, useful for last-known-state scenarios like agent status, configuration, or current values.

How it works

StepWhat happens
Publisher sends retained messageSet retain=true when publishing
CloudSignal stores the messageOnly the latest message per topic is kept
Subscriber connects laterImmediately receives the retained message
Updates replace old valuesNew retained messages overwrite previous ones
Retained message delivery
Publisher
CloudSignal
Subscriber
PUBLISH agents/agent-01/state {status:idle} retain=true
Store latest for topic
SUBSCRIBE agents/agent-01/state (later)
Deliver retained {status:idle}

Publishing retained messages

JavaScript (CloudSignal SDK)

// Publish with retain flag
client.transmit('agents/agent-01/state', { status: 'idle' }, { retain: true });

// Clear a retained message by publishing an empty payload
client.transmit('agents/agent-01/state', '', { retain: true });

Python (paho-mqtt)

# Publish with retain flag
client.publish('agents/agent-01/state', '{"status":"idle"}', retain=True)

# Clear retained message
client.publish('agents/agent-01/state', '', retain=True)

To clear a retained message, publish an empty payload with retain=true to the same topic.

Use cases

Agent presence

Show whether agents are online or offline:

// Agent publishes its status (retained)
client.transmit('agents/agent-01/state', { status: 'online' }, { retain: true });

// Dashboard subscribes - immediately knows agent status
await client.subscribe('agents/+/state');

Current values

New subscribers immediately see the most recent value:

// Service publishes latest load (retained)
client.transmit('agents/agent-01/load', { load: 0.42 }, { retain: true });

// New dashboard component gets the value the moment it subscribes

Configuration distribution

Publish configuration that clients pick up when they connect:

// Admin publishes config (retained)
client.transmit('config/agent-type-a/settings', {
  reportInterval: 60,
  alertThreshold: 100,
}, { retain: true });

// Agents subscribe on boot and get the config immediately

Last will and testament (LWT)

Combine retained messages with LWT for presence detection:

import CloudSignal from '@cloudsignal/mqtt-client';

const client = new CloudSignal({
  preset: 'desktop',
  will: {
    topic: 'agents/agent-01/state',
    payload: JSON.stringify({ status: 'offline' }),
    retain: true,
  },
});

// On connect, publish online status
await client.connectWithToken({ organizationId, externalToken });
client.transmit('agents/agent-01/state', { status: 'online' }, { retain: true });

Retained messages vs. persistent sessions

These features complement each other.

FeaturePurposeScope
Retained messagesLast-known-state for a topicPer topic, visible to every subscriber
Persistent sessionsQueue messages for offline clientsPer client, private to that client
  • Retained messages answer "what's the current value?"
  • Persistent sessions answer "what did I miss while offline?"

Use both together for resilient apps:

import CloudSignal from '@cloudsignal/mqtt-client';

// Agent uses persistent session so it doesn't miss commands
const client = new CloudSignal({
  preset: 'server',
  clean: false,
  clientId: 'agent-01',
});

await client.connectWithToken({ organizationId, secretKey });

// Agent publishes retained status
client.transmit('agents/agent-01/state', { status: 'online' }, { retain: true });

Limits

PlanRetained messages
Free100 topics
Pro1,000 topics
Max10,000 topics

Each topic can hold one retained message (the latest one).

Retained messages persist until explicitly cleared or the topic limit is reached. Clean up unused retained messages to stay within limits.

Best practices

Use descriptive topics

# Good: clear hierarchy
agents/agent-01/state
agents/agent-01/load
chat/conv-7/last-message

# Avoid: flat structure
agent01-state

Include timestamps

client.transmit('agents/agent-01/load', {
  load: 0.42,
  timestamp: Date.now(),
}, { retain: true });

Clean up on shutdown

process.on('SIGTERM', () => {
  // Clear retained status before exit
  client.transmit('agents/agent-01/state', '', { retain: true });
  client.destroy();
});

On this page