VIABLE sees only your app's agent runs. Send the rest from your server: what learners did and wrote, how they rated replies and how they scored. It joins the learners your runs already name.
What you get
- Insights in Build → Apps: active learners, time writing, pauses, pastes, drafts handed in, ratings and learner groups, day by day.
- A timeline per learner in Teach → Learners: their work in your app by activity, and their scores.
- The research export with your app's data (
writing.csvmeasures how each draft was written), ready for Coding.
To have your coding AI wire it up, paste this message in your app's code:
Read https://www.viablelab.org/downloads/viable-cli.md and set up VIABLE CLI and its Agent Skill if they are missing, then follow the Skill's "Connect an app to VIABLE" with https://developers.viablelab.org/docs/connect/first-run.md and https://developers.viablelab.org/docs/connect/learning-data.md: make this app's server send user, X-Platform-ID, include: ["trace"] and its learning data, then verify with viable developer apps list and viable developer apps insights <platform-id>.
Before you start
- Give the key the scope. In Operate → API keys, choose Edit key on your app's key and turn on Record learning data (
learning:write). - Tag every call. Send
X-Platform-ID, such aswriting-app. Events and drafts are filed under your app's ID and the activity, so they need it. - Reuse your
user. Theuseryou send on runs is the same learner here. A newusercreates a learner.
Send events
POST /v1/learning/events takes one learner's events in one activity, up to 200 per call. Use VIABLE's event kinds, such as writing.progress (keys, pastes, pauses, active time), writing.snapshot (the text at a pause), writing.submit and panel.view, or app.event for your own, with a flat data object. Each kind keeps only its own fields. The response lists any event it skipped, by index.
// On your server, never in the browser.
const res = await fetch('https://api.viablelab.org/v1/learning/events', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VIABLE_API_KEY}`,
'Content-Type': 'application/json',
'X-Platform-ID': 'writing-app'
},
body: JSON.stringify({
user: 'writing-app:7f3a9c21',
activity: 'persuasive-essay-1',
events: [{ type: 'writing.progress', at: new Date().toISOString(), data: { field: 'draft', keys: 140, pasted: 0, pauses: 3, active_ms: 95000 } }]
})
})
if (!res.ok) console.error((await res.json()).error)
Save drafts
POST /v1/learning/drafts saves the draft, and the plan if your app has one, as they are now: send the whole text each time. Add submit: true when the learner hands it in.
Rate replies
When a learner marks a reply helpful or not, send POST /v1/agents/{slug}/runs/{run_id}/rating with rating set to 1, -1, or null to take it back. It uses Run agents and works only for runs this key made.
Send scores
POST /v1/learning/outcomes records one measure, such as a rubric total, for up to 1,000 users. A user that no run, event or draft has named yet comes back in unmatched.
Where it lands
- Research → Export, with Your apps (API), or one app from its Insights: events in
workspace_events.csv, drafts and how they were written inwriting.csv, ratings inturns.csv, scores inoutcomes.csv. A run withuseralso keeps itscontextas the turn'sworkspace. - Build → Apps: the checklist marks each kind your app has sent, and Insights counts it.
Warning
Consent is your app's to handle: tell learners what it records before you send anything. Keep
useropaque, as on your runs: never a name or an email.
- Learners and traces: name your users and keep each run's trace.
- Export: download it all for analysis.
