Timing Fields

When submitting answers, accurate timing data is critical for the learning algorithm to function correctly. The API uses this data to determine spaced repetition intervals, assess fluency progress, and calculate XP rewards.

Required Fields

timeTookToAnswerMs

Time in milliseconds for this specific question.

How to track it:

  • Start timing when question is displayed
  • Stop timing when user submits answer
  • Include think time and interaction time for this question only

Example:

const questionStartTime = Date.now();
// ... show question, wait for user answer
const timeTookMs = Date.now() - questionStartTime;

activeSessionDurationSec

Total active play time in seconds since session started.

How to track it:

  • Only count active learning time (when user is answering questions)
  • Exclude: menu navigation, pauses, game-over screens, loading times, etc.
  • Track using a game timer that pauses during non-learning activities

Example:

let activeSessionTime = 0; // seconds

function onQuestionDisplayed() {
  const questionStartTime = Date.now();

  // ... wait for user answer

  const questionDurationMs = Date.now() - questionStartTime;
  activeSessionTime += questionDurationMs / 1000; // Add to total
}

Full Example

const sessionId = crypto.randomUUID();
let activeSessionTime = 0;

async function askQuestion() {
  const questionStartTime = Date.now();

  // Get question
  const questionRes = await fetch(`${API_URL}/learning/v1/skills/${skillId}/algorithms/practice/questions`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${idToken}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ sessionId }),
  });
  const { question } = await questionRes.json();

  // Show question and wait for answer
  const selectedChoiceId = await getUserAnswer(question);

  // Calculate timing
  const timeTookMs = Date.now() - questionStartTime;
  activeSessionTime += timeTookMs / 1000;

  // Submit answer with timing
  const answerRes = await fetch(
    `${API_URL}/learning/v1/skills/${skillId}/algorithms/practice/questions/${question.id}/answers`,
    {
      method: 'POST',
      headers: { Authorization: `Bearer ${idToken}`, 'Content-Type': 'application/json' },
      body: JSON.stringify({
        sessionId,
        answer: { choiceId: selectedChoiceId },
        timeTookToAnswerMs: timeTookMs,
        state: 'Answered',
        activeSessionDurationSec: activeSessionTime,
        capabilities: { intervention: false },
      }),
    },
  );
}

Common Mistakes

Including pause time in active session duration:

// ❌ Bad: Counts everything
const activeTime = Date.now() - sessionStart;

// ✅ Good: Only counts learning time
let activeTime = 0;
onQuestionShow(() => startTimer());
onPause(() => stopTimer());

Using fixed timing instead of actual measurements:

// ❌ Bad: Fake timing
const timeTookMs = 3000; // Breaks algorithm

// ✅ Good: Real timing
const start = Date.now();
const timeTookMs = Date.now() - start;

Getting Started

Authentication and basic learning loop showing where timing fields fit into answer submission.

Complete Example

Production code demonstrating proper timing tracking with pause/resume handling and state persistence.

API Reference

Complete schema documentation for the answer submission endpoint, including timing field requirements and validation rules.