Skip to main content

Data Push

Data Push automatically sends NeoMind device telemetry to external systems — either the moment a device publishes new data or on a fixed interval, to a Webhook endpoint or MQTT Broker you configure. Typical uses:

  • Forward sensor data to an enterprise data platform / data lake
  • Sync device state in real time to third-party monitoring systems (e.g. Grafana, ThingsBoard)
  • Push AI inference results to a business system to trigger downstream workflows
  • Bridge NeoMind to another IoT platform

Data Push lives under the Push tab on the Data Explorer page, complementing Rules (condition-triggered actions) and Data Transforms (real-time data processing).

Interface Overview

Open Data Explorer (database icon) in the left nav and switch to the Push tab:

Data push list — target name, type, status, schedule, data sources

The page lists all push targets in a table, each row containing:

ColumnDescription
NameDisplay name of the push target
TypeWebhook / MQTT
StatusRunning / Stopped
ScheduleEvent Driven / Interval
Data SourcesMatched source patterns (e.g. device:sensor-01:*)
UpdatedLast modified time
ActionsEdit, delete, test, view logs

Creating a Push Target

Click Create to open the full-screen configuration dialog:

Push target create dialog — name, type, target URL, schedule

1. Basic Info

FieldDescription
NameIdentifier for the push target
Target TypeWebhook — HTTP POST to a URL; MQTT — publish to an MQTT Broker

2. Target Configuration

Webhook type:

FieldDescription
URLHTTP endpoint that receives data (e.g. https://api.example.com/ingest)
MethodHTTP method (default POST)
HeadersCustom request headers (e.g. Authorization: Bearer <token>, Content-Type: application/json)

MQTT type:

FieldDescription
BrokerMQTT Broker host (e.g. broker.example.com; port is a separate field, default 1883)
TopicPublish topic (e.g. factory/line1/sensors)
Username / PasswordAuthentication credentials (optional)

3. Schedule

Schedule typeDescriptionUse case
Event DrivenPush as soon as new data arrivesReal-time sync, low-latency scenarios
IntervalBatch push every N secondsReduce request frequency, batch scenarios

4. Data Source Filter

Push target — data source selection panel, multi-select grouped by type

Choose which data sources to push:

SettingDescription
Source PatternsWildcard matching. device:sensor-01:* = all metrics of sensor-01; device:sensor-01:temperature = sensor-01's temperature metric. Note: patterns match by prefix — a * in the middle has no effect (device:*:temperature actually matches all device data)
Only ChangesWhen enabled, pushes only when the data value actually changes, skipping duplicates to reduce traffic. Configured via the API's data_filter.only_changes field (the create dialog doesn't expose this toggle yet; off by default)

The source panel is grouped by type (Device / Extension / Transform / System) with search and multi-select.

5. Retry & Batch

Push target — retry strategy and batch config

Retry Config — configured via the API's retry_config field; when omitted, the following defaults apply:

FieldDescriptionDefault
Max RetriesMaximum retry attempts3
Backoff (secs)Initial backoff seconds5
Max Backoff (secs)Maximum backoff cap300

Retry uses exponential backoff: 1st retry waits 5s, 2nd 10s, 3rd 20s … up to the Max Backoff cap. Note that Max Retries: 3 counts retries — including the initial send, one data point gets at most 4 attempts. If the target replies with 429/503 (rate limiting), NeoMind switches to a longer fixed backoff and honors the Retry-After response header when present (defaulting to 60 seconds without it), so an already-throttled endpoint isn't hammered further.

Batch Config:

FieldDescription
Batch SizeMaximum items per batch (default 1, i.e. no batching — push each item immediately)
Batch Interval (ms)Batch send interval in milliseconds (default 2000)

With batching enabled (batch_size > 1), multiple data points are accumulated into one request with the payload shape { "batch": […], "count": N, "items": [{"source_id", "value", "timestamp"}, …] } (format: "flat", the default; format: "nested" organizes items nested by source type / ID / field instead).

Click Save when done.

Complete Lifecycle Example: Webhook from Creation to Verification

Walk the whole flow with real requests/responses: pushing sensor-01's data to a local receiver.

Step 1 · Create the push target

curl -X POST http://localhost:9375/api/data-push \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{
"name": "Temperature to Local Receiver",
"target_type": "webhook",
"config": {"url": "http://192.168.1.50:9999/ingest", "method": "POST"},
"schedule": {"type": "event_driven", "event_types": ["device_metric"]},
"data_filter": {"source_patterns": ["device:sensor-01:*"], "only_changes": false},
"enabled": true
}'

Real response:

{
"success": true,
"data": {
"id": "f95bd869-0acb-41d2-a75a-a8c879d53f99",
"name": "Temperature to Local Receiver",
"target_type": "webhook",
"enabled": true
}
}

Note: an event-driven schedule must include event_types (e.g. device_metric for device data, extension_output for extension output); interval scheduling instead uses {"type": "interval", "interval_secs": 60}.

Step 2 · Start and send test data

# Start
curl -X POST http://localhost:9375/api/data-push/<id>/start

# Push one sample payload to verify the pipeline
curl -X POST http://localhost:9375/api/data-push/<id>/test

Step 3 · Confirm what the receiver got

test makes NeoMind actually POST a sample payload to the target URL. The HTTP request as received on the other side:

POST /ingest
Content-Type: application/json

{"source_id":"test:sample:value","value":{"test":true,"value":42},"timestamp":1788930335}

That is, the default payload always has three fields: source_id (data source ID), value (metric value — scalar or object), timestamp (Unix seconds). When real device data flows, source_id is the matched data source (e.g. device:sensor-01:temperature) and value is the metric value.

If the receiving side needs a different shape, use the target's template field — a Handlebars template with access to source_id / value / timestamp, plus two helpers: {{json value}} (serialize to a JSON string) and {{timestamp_format …}} (format a timestamp):

{ "template": "{ \"device\": \"{{source_id}}\", \"reading\": {{json value}}, \"time\": {{timestamp}} }" }

Step 4 · Check the delivery log

curl http://localhost:9375/api/data-push/<id>/logs

A real delivery log entry (produced by test):

{
"id": "d9c8122f-2419-42a2-a45c-66eea410ec43",
"target_id": "f95bd869-0acb-41d2-a75a-a8c879d53f99",
"status": "success",
"data_source_id": "test:sample:value",
"payload_sent": "{\"source_id\":\"test:sample:value\",\"value\":{\"test\":true,\"value\":42},\"timestamp\":1788930335}",
"response": null,
"attempts": 1,
"created_at": 1788930335,
"completed_at": 1788930335,
"error": null
}

Field-by-field meanings are in Delivery Logs.

Step 5 · Check aggregate stats

curl http://localhost:9375/api/data-push/stats
{
"success": true,
"data": {
"total_targets": 1,
"active_targets": 1,
"total_deliveries": 0,
"successful_deliveries": 0,
"failed_deliveries": 0
}
}

The delivery counters accumulate as real data is pushed — if failed_deliveries climbs, go to Delivery Logs and read the error field to find out why.

Push Target Actions

Each push target supports the following actions:

ActionDescription
Start / StopStart / stop the push
TestSend a test payload to verify the connection
LogsView delivery logs (success / failure / retries)
EditEdit the configuration
DeleteDelete the push target

Delivery Logs

Click Logs on a push target (or GET /api/data-push/<id>/logs) to view delivery history. Fields per entry:

FieldDescription
idLog entry ID
target_idThe push target this entry belongs to
statuspending / success / failed / retrying
data_source_idThe pushed data source ID (e.g. device:sensor-01:temperature)
payload_sentThe exact payload sent (after template rendering)
responseThe response body returned by the target (truncated; useful to confirm how the receiver processed it)
attemptsActual attempt count — 1 means first-try success; >1 means retries happened
created_at / completed_atUnix timestamps of delivery start and final completion (or giving up)
errorFailure reason (target 5xx, connection timeout, TLS errors, etc.)

Debugging recipe: for status: failed, read error first; a large attempts count means an unstable target, and the created_at/completed_at delta tells you how long retries dragged on; diff payload_sent byte-for-byte against receiver-side logs to settle "what was actually sent".

MQTT Target Differences

Choosing the MQTT type changes the configuration and delivery behavior in these ways:

DimensionWebhookMQTT
Target configurl + method + headersbroker (hostname) + port (separate field, default 1883) + topic (publish topic) + optional username / password
Extra parametersqos (default 1), client_id (defaults to neomind-push)
DeliveryOne HTTP POST per pushPublishes one message to the topic; payload identical to Webhook (default {"source_id", "value", "timestamp"}, template also supported)
Connection modelStateless — connect, send, disconnectPersistent connection to the Broker; unreachable Brokers are retried per the retry policy
TestingTest issues a real POSTTest actually publishes to the topic (verify with a client like mosquitto_sub -t '<topic>')
Best forREST business systems, data platform ingest APIsPlatforms with existing MQTT infrastructure (ThingsBoard, EMQX, …)
Embedded broker

NeoMind ships an embedded MQTT Broker (default port 1883) — device data already flows in through it. Pointing a push target at the local broker on a different topic creates a "data loopback" that gives MQTT-only external programs the same stream as the platform internals.

CLI Management

# List all push targets
neomind push list

# Create a push target (webhook / mqtt; --config takes the target config JSON)
neomind push create --name "Temperature to API" --type webhook \
--config '{"url":"https://api.example.com/ingest","headers":{"Content-Type":"application/json"}}'

# Start / stop
neomind push start <target_id>
neomind push stop <target_id>

# Test push
neomind push test <target_id>

# View delivery logs / stats
neomind push logs <target_id>
neomind push stats

# Delete
neomind push delete <target_id>

REST API

# Create push target (event-driven schedule requires event_types; interval uses {"type": "interval", "interval_secs": 60})
curl -X POST http://localhost:9375/api/data-push \
-H "Content-Type: application/json" \
-d '{
"name": "Temperature to API",
"target_type": "webhook",
"config": {"url": "https://api.example.com/ingest", "method": "POST"},
"schedule": {"type": "event_driven", "event_types": ["device_metric"]},
"data_filter": {"source_patterns": ["device:*:temperature"], "only_changes": false},
"enabled": true
}'

# List all push targets
curl http://localhost:9375/api/data-push

# Start push
curl -X POST http://localhost:9375/api/data-push/<id>/start

# Test push
curl -X POST http://localhost:9375/api/data-push/<id>/test

# View delivery logs
curl http://localhost:9375/api/data-push/<id>/logs

# View stats
curl http://localhost:9375/api/data-push/stats

Typical Scenarios

Scenario 1: Real-time Temperature Push to Enterprise API

  • Type: Webhook
  • Schedule: Event Driven (push on new data)
  • Source: device:*:temperature (prefix-matched — effectively all device data; list device:<id>:temperature per device to target the metric precisely)
  • Only Changes: enabled (avoid duplicate values)
  • Retry: 3 attempts, exponential backoff

Scenario 2: Batch Sync Device Status to MQTT Broker

  • Type: MQTT
  • Schedule: Interval, every 60 seconds
  • Source: device:*:online
  • Batch: 100 items per batch, 5-second interval
  • Only Changes: enabled (push only state changes)

Scenario 3: Push AI Inference Results to Business System

  • Type: Webhook
  • Schedule: Event Driven
  • Source: extension:yolo-video:detections
  • Target URL: The business system's ingest endpoint

Integration with Other Modules

ModuleDescription
DevicesPush raw telemetry published by devices
Data TransformsPush derived metrics generated by Transforms
ExtensionsPush metrics output by extensions (e.g. YOLO detections)
RulesRules evaluate data internally; Push sends data externally

Best Practices

  • Enable Only Changes: For state-like data (e.g. online), this drastically cuts redundant pushes
  • Batch wisely: High-frequency data should use Interval + batch to avoid request storms on the target system
  • Configure retry: With network instability, 3 exponential-backoff retries cover most transient faults
  • Test before enabling: After creating, use Test to verify the connection works before starting the push
  • Monitor delivery logs: Periodically review failed logs to catch target-system issues early

Next Steps


Last updated: 2026-09-09