Data Quality & Validation
Forsta HX Platform - API Scripting Guide
Data Quality & Validation
Speeder Detection:
/**
* questionTimes - Object storing time spent on each question
* @type {Object.}
* @description Keys are question IDs, values are seconds spent on each.
* Used for speeder detection and data quality analysis.
*/
var questionTimes = {};
/**
* currentQuestionStart - Timestamp when current question was displayed
* @type {number}
* @description Stores Date.now() value when question becomes active.
* Used to calculate elapsed time when moving to next question.
*/
var currentQuestionStart = Date.now();
/**
* trackQuestionTime - Records time spent on a question and flags speeders
* @param {string} qid - The question ID to track time for
* @description Calculates elapsed seconds since currentQuestionStart,
* stores in questionTimes object, and logs warning if
* respondent spent less than 2 seconds (potential speeder).
*/
function trackQuestionTime(qid) {
var elapsed = (Date.now() - currentQuestionStart) / 1000;
questionTimes[qid] = elapsed;
// Flag if too fast (less than 2 seconds)
if(elapsed < 2) {
console.warn('Speeding detected on ' + qid);
// Could trigger warning or flag response
}
currentQuestionStart = Date.now();
}
// Call on next button click
$('.next-button').on('click', function() {
trackQuestionTime(getCurrentQuestionId());
});
Straight-lining Detection:
/**
* detectStraightLining - Detects if respondent gives same answer repeatedly
* @param {Array} questions - Array of question IDs to analyze
* @param {number} threshold - Percentage threshold to flag (e.g., 80 = 80%)
* @returns {Object} - Object with detected (boolean), percentage, and mostCommon answer
* @description Analyzes response patterns across multiple questions.
* If the same answer appears more than threshold% of times,
* flags as potential straight-lining (low quality response).
*/
function detectStraightLining(questions, threshold) {
// Get all responses for the specified questions
var responses = questions.map(function(qid) {
return f(qid).val();
});
// Count most common response
var counts = {};
responses.forEach(function(val) {
counts[val] = (counts[val] || 0) + 1;
});
var maxCount = Math.max(...Object.values(counts));
var percentage = (maxCount / responses.length) * 100;
if(percentage >= threshold) {
return {
detected: true,
percentage: percentage,
mostCommon: Object.keys(counts).find(key =>
counts[key] === maxCount
)
};
}
return {detected: false};
}
// Usage
var scaleQuestions = ['BQ1', 'BQ2', 'BQ3', 'BQ4', 'BQ5'];
var result = detectStraightLining(scaleQuestions, 80);
if(result.detected) {
alert('Please vary your responses');
}
Response Quality Scoring:
/**
* calculateQualityScore - Computes an overall quality score for the response
* @returns {number} - Quality score from 0-100+ (higher = better quality)
* @description Starts with 100 points and applies penalties/bonuses:
* - Penalty for speeding (< 2 seconds per question)
* - Penalty for straight-lining responses
* - Penalty for short open-end answers
* - Bonus for passing attention checks
* Minimum score is clamped to 0.
*/
function calculateQualityScore() {
var score = 100; // Start with perfect score
// Penalize for speeding
Object.values(questionTimes).forEach(function(time) {
if(time < 2) score -= 5;
});
// Penalize for straight-lining
if(detectStraightLining(['BQ1','BQ2','BQ3','BQ4'], 75).detected) {
score -= 20;
}
// Penalize for incomplete open-ends
$('textarea').each(function() {
var words = countWords($(this).val());
if(words < 5) score -= 10;
});
// Reward for consistency checks passed
if(passedAttentionCheck()) score += 10;
return Math.max(0, score);
}
// Flag low quality responses
var quality = calculateQualityScore();
if(quality < 50) {
console.warn('Low quality response detected');
// Could trigger review or rejection
}