The idea
The learning app emits envelope-shaped events as they happen — session started, activity completed, skill progress, the child got stuck — and batches them to an HTTPS endpoint defined by the collector. The collector validates each event against a JSON Schema, deduplicates by id, and stores or forwards as it sees fit.
There is no streaming, no shared skill taxonomy, no analytics, no queries back. v1 is just ingest. Anything richer is left to the consumer.
The flow
┌────────────┐ 1. authenticated POST ┌──────────────┐
│ Learning │ ──────────────────────► │ Collector │
│ app │ { events: [...] } │ (launcher, │
│ (reporter) │ │ dashboard) │
│ │ ◄────────────────────── │ │
└────────────┘ 202 { accepted: N } └──────────────┘
The event envelope
Every event has the same outer shape. The data field is type-specific.
{
"event_id": "01HX5XYV6FPK3R3D6T2H8E2VPR",
"type": "activity.completed",
"occurred_at": "2026-05-20T14:32:17.412Z",
"child_ref": {
"iss": "https://issuer.example-launcher.com",
"sub": "child:abc123",
"email": "student@example.com"
},
"app_ref": { "app_id": "your-app-id", "version": "2.4.1" },
"session_id": "01HX5XYTX5N3DTSXJC9MFAV0QH",
"data": {
"activity_id": "fractions-intro-3",
"score": 0.85,
"time_ms": 124000,
"attempts": 3,
"passed": true
}
}
Core event types
session.started |
Child begins using the app. |
|---|---|
session.ended |
Session ends for any reason. Carries active_ms and reason. |
activity.started |
Child begins a unit of work — a lesson, exercise, level. |
activity.completed |
The unit ends with a result. score, attempts, passed. |
skill.progress |
Mastery of a skill changes meaningfully. level and delta. |
struggle.signal |
Child is stuck, thrashing, or abandoning. The negative-signal channel. |
skill_id and topic are opaque strings, defined by each app. The protocol standardizes the envelope, not the pedagogy.
Transport
POST <collector_url>/v1/events
Authorization: Bearer <reporter_token>
Content-Type: application/json
{ "events": [ /* envelope objects */ ] }
Batched HTTPS. ≤ 500 events or ≤ 1 MB per batch. Reporters retry transient failures; collectors deduplicate by event_id.
Read the spec
- Overview & FAQ specs/edu-progress/protocol.md
- Reporter implementation spec specs/edu-progress/reporter.md
- Collector implementation spec specs/edu-progress/collector.md
- Conformance checklist specs/edu-progress/conformance.md
- JSON Schemas specs/edu-progress/schema/
- Sample batch specs/edu-progress/examples/sample-batch.json
