Browser & feedback
Feedback is telemetry: it lands next to the session it grades, and the same loop that clusters failures clusters bad feedback — negative feedback becomes bug candidates; directional asks become idea candidates whose text IS the spec.
Your feedback_key (lk_feedback_*) is browser-safe — it can submit feedback and targeted events, plus read its own project's ingest health; nothing else (no telemetry reads).
Typed feedback
Target one of session_id / trace_id / span_id, plus at least one valence (score 0..1, polarity up|down, rating 1..5, comment, or expected — "what it should have said", a golden-answer seed):
POST /v1/feedback
Authorization: Bearer <feedback_key>
Content-Type: application/json
{ "session_id": "sess_abc", "polarity": "down", "labels": ["export"],
"comment": "the export button does nothing on mobile" }
Spoken feedback
POST raw recording bytes (audio/*, ≤ 4 MiB); the worker transcribes at the edge and the transcript enters the same lane. Raw audio is not retained:
POST /v1/feedback/audio?session_id=sess_abc
Authorization: Bearer <feedback_key>
Content-Type: audio/webm
<recording bytes>
@getloopops/sdk ships feedback() / feedbackAudio() plus a drop-in widget (feedback-widget.js: thumbs, comment panel, mic).
Product / UX events
Standard OTLP logs with EventName — regenerations, retries, abandons, escalations, slow-UX markers. Actionable friction becomes a bug candidate; positive actions stay context:
POST /v1/logs
Authorization: Bearer <feedback_key>
Content-Type: application/json
{ "resourceLogs": [{ "scopeLogs": [{ "logRecords": [{
"traceId": "tr_123",
"eventName": "chat.response_regenerated",
"body": { "stringValue": "user regenerated the response" },
"attributes": [
{ "key": "session.id", "value": { "stringValue": "sess_abc" } },
{ "key": "loopops.event.action", "value": { "stringValue": "regenerated" } }
]
}] }] }] }
With the feedback_key, events must be targeted (carry session.id, trace_id, span_id, or a message id). Ordinary application logs use the producer key.
Evaluator results — the OTel standard just works
Automated evals instrumented to the OpenTelemetry GenAI semantic conventions need no LoopOps-specific shape: a gen_ai.evaluation.result log event (semconv v1.39) posted to /v1/logs is recognized at ingest and folds into this same feedback lane as agent feedback. gen_ai.evaluation.score.label (pass/fail-style verdicts) or score.value becomes the polarity, gen_ai.evaluation.explanation the comment, and gen_ai.response.id the join back to the evaluated call. The standard defines no human-feedback event — human 👍/👎 stays on /v1/feedback above, where the rater split (end user / reviewer / auto) already goes further than the spec.
Next: Run your first loop →