Integration · Embed Signage
Switch content in real time from the player itself.
SignIQ Measure exposes a local HTTP + WebSocket API on 127.0.0.1:8765. Embed Signage running on the same Windows or Android player calls into it to switch playlists based on live audience — without any cloud round-trip.
TL;DR
- 1. SignIQ Measure runs as a service on the player — no UI after first pairing.
- 2. It exposes
127.0.0.1:8765with bearer-token auth. - 3. Embed Signage scripts poll or subscribe to audience data.
- 4. Your content rules pick playlists based on viewer counts, attention, dwell.
1. Get the local token
The first time SignIQ Measure runs on a player, it generates a random 32-byte token stored locally. The pairing screen displays this token (and a QR code) — paste it into your Embed Signage device config as the env var SIGNIQ_LOCAL_TOKEN.
The token never leaves the device. SignIQ does not see it. Lose it and you can regenerate from the SignIQ Measure tray icon.
2. Detect SignIQ is running
Hit /v1/health (unauthenticated) before doing anything else. If it returns 200, you're good. If it times out, SignIQ isn't installed or hasn't started — fall back to your default playlist.
curl http://127.0.0.1:8765/v1/health
# → { "ok": true, "service": "signiq-measure", "app_version": "0.0.1" }3. Poll current audience
For simple polling-based content switching, hit /v1/audience/current?seconds=30 on a timer. The response is a rolling-window aggregate; pick a playlist based on attention_viewers and switch.
curl -H "Authorization: Bearer $SIGNIQ_LOCAL_TOKEN" \
"http://127.0.0.1:8765/v1/audience/current?seconds=30"
# → {
# "from": "2026-05-11T11:30:00Z",
# "to": "2026-05-11T11:30:30Z",
# "total_viewers": 4,
# "notice_viewers": 3,
# "attention_viewers": 2,
# "peak_concurrent": 4,
# "avg_attention_quality": 0.78
# }JS example from Embed Signage content:
const TOKEN = process.env.SIGNIQ_LOCAL_TOKEN; // paste from device pairing screen
async function pickPlaylist() {
const r = await fetch('http://127.0.0.1:8765/v1/audience/current?seconds=30', {
headers: { Authorization: `Bearer ${TOKEN}` },
});
if (!r.ok) return 'default';
const { attention_viewers } = await r.json();
if (attention_viewers >= 5) return 'busy-promo';
if (attention_viewers >= 2) return 'engaged';
return 'ambient';
}
setInterval(async () => {
embedSignage.setActivePlaylist(await pickPlaylist());
}, 5000);4. Or subscribe via WebSocket (sub-second)
For sub-second reactions, open a WebSocket to /v1/realtime/ws. Events stream as JSON; react when the right one arrives.
const TOKEN = process.env.SIGNIQ_LOCAL_TOKEN;
const ws = new WebSocket(`ws://127.0.0.1:8765/v1/realtime/ws?token=${TOKEN}`);
ws.onmessage = (msg) => {
const event = JSON.parse(msg.data);
if (event.event === 'audience.snapshot') {
if (event.payload.attention_viewers >= 5) {
embedSignage.setActivePlaylist('busy-promo');
}
}
};Endpoint reference
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v1/health | none | Liveness probe — returns 200 OK if SignIQ Measure is running on this player. Use to detect installation before negotiating a token. |
| GET | /v1/audience/current?seconds=N | bearer | Rolling-window aggregate over the last N seconds (default 30, clamped 5–300). The primary content-switching endpoint. |
| GET | /v1/audience/window?from=…&to=… | bearer | Exact-range window query (RFC3339 timestamps, max 30-minute look-back buffer). Use for historical comparisons. |
| GET | /v1/measure/live | bearer | Instant snapshot: current viewers, audience composition, average attention. Updated every measurement tick. |
| GET | /v1/realtime/ws | bearer (token in query string) | WebSocket stream of audience and rule events. Subscribe once, react sub-second. |
| POST | /v1/playback/now-playing | bearer | Tell SignIQ what Embed Signage is currently showing — content_id, campaign_id, asset name, duration. Lets SignIQ attribute audience to content for analytics. |
Notes
- Cold start. The 30-minute rolling buffer takes a few seconds to fill. During that period
/v1/audience/currentreturns zeros withwarming_up: true— treat as default-content fallback. - Port fallback. If 8765 is taken the service tries 8766–8774 in order. The exact port is shown on the pairing screen and stored in the device's app data directory.
- CORS. The API accepts any origin so Embed Signage content loaded from
file://,http://localhost, or an embedded WebView all work. - Tizen. Samsung Smart Signage cannot reliably reach a localhost server. On Tizen, use the measure-bundle JS API instead — same data shape, in-process.
- No video leaves the device. The local API exposes only aggregates and event metadata. Raw frames stay in the SignIQ Measure process and are never persisted, never transmitted.
Need a custom integration?
We can help wire SignIQ Measure into any CMS that can run a script on the player.
Talk to engineering