Custom
API Integration Guide
This guide covers how to integrate our fingerprinting and open-end tracking features, and how to call our API using both JavaScript and React.
JavaScript Implementation
Step 1: Setup Fingerprinting
Integrate our fingerprinting script using one of these methods:
-
HTML link (preferred):
<script src="https://roundtable.ai/js/fingerprinting.js"></script>
-
Dynamic JavaScript insertion:
const script = document.createElement('script'); script.src = 'https://roundtable.ai/js/fingerprinting.js'; document.head.appendChild(script);
The script adds fingerprint_id
to session storage. Retrieve it with:
const fingerprintId = sessionStorage.getItem('fingerprint_id');
Step 2: Setup Open-end Tracking
Use our JavaScript tracker to record changes in open-ended textboxes:
const textbox_id = 'exampleTextarea';
const max_characters_for_history = 25000;
document.addEventListener('DOMContentLoaded', function () {
let question_history = [];
let old_text = document.getElementById(textbox_id).value;
let text_over_length = false;
let start_time;
document.getElementById(textbox_id).addEventListener('input', function (e) {
// Input handling logic here
});
document.getElementById(textbox_id).addEventListener('copy', function (e) {
// Copy handling logic here
});
});
Step 3: Call the API
Use the collected data to make an API call:
const apiData = {
participant_id: "participant_123",
question_histories: {
Q1: question_history
},
questions: {
Q1: "How do you feel our software has impacted your daily workflow?"
},
responses: {
Q1: document.getElementById(textbox_id).value
},
survey_id: "survey_456",
fingerprint_id: fingerprintId
};
fetch('https://api.roundtable.ai/alias/latest', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'api_key': '<api_key>'
},
body: JSON.stringify(apiData)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
React Implementation
Step 1: Setup Fingerprinting
Create a custom hook to load the fingerprinting script and retrieve the fingerprint_id:
import { useState, useEffect } from 'react';
const useFingerprint = () => {
const [fingerprintId, setFingerprintId] = useState(null);
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://roundtable.ai/js/fingerprinting.js';
script.async = true;
script.onload = () => {
setTimeout(() => {
const id = sessionStorage.getItem('fingerprint_id');
setFingerprintId(id);
}, 100);
};
document.head.appendChild(script);
return () => {
document.head.removeChild(script);
};
}, []);
return fingerprintId;
};
Step 2: Setup Open-end Tracking
Create a custom hook to track changes in open-ended textboxes:
import { useState, useRef, useCallback } from 'react';
const useQuestionHistory = (maxCharactersForHistory = 25000) => {
const [history, setHistory] = useState([]);
const startTimeRef = useRef(null);
const textOverLengthRef = useRef(false);
const getTimeElapsed = useCallback(() => {
if (!startTimeRef.current) {
startTimeRef.current = Date.now();
return 0;
}
return Date.now() - startTimeRef.current;
}, []);
const addHistoryEntry = useCallback((newEntry) => {
if (textOverLengthRef.current) return;
setHistory(prevHistory => {
const updatedHistory = [...prevHistory, newEntry];
const lengthOfHistory = JSON.stringify(updatedHistory).length;
if (lengthOfHistory > maxCharactersForHistory) {
textOverLengthRef.current = true;
return prevHistory;
}
return updatedHistory;
});
}, [maxCharactersForHistory]);
const handleInput = useCallback((event) => {
const timeElapsed = getTimeElapsed();
addHistoryEntry({
s: event.target.value,
t: timeElapsed
});
}, [getTimeElapsed, addHistoryEntry]);
const handleCopy = useCallback((event) => {
const timeElapsed = getTimeElapsed();
addHistoryEntry({
s: event.target.value,
t: timeElapsed,
o: 'c',
ct: window.getSelection().toString()
});
}, [getTimeElapsed, addHistoryEntry]);
return { history, handleInput, handleCopy };
};
Step 3: Create Open-end Component
import React from 'react';
import useQuestionHistory from './useQuestionHistory';
const OpenEndQuestion = ({ id, question }) => {
const { history, handleInput, handleCopy } = useQuestionHistory();
return (
<div>
<label htmlFor={id}>{question}</label>
<textarea
id={id}
onChange={handleInput}
onCopy={handleCopy}
/>
</div>
);
};
export default OpenEndQuestion;
Step 4: Setup API Call
Create a custom function for making API calls:
const callApi = async (questionHistories, fingerprintId, responses) => {
if (!fingerprintId || Object.keys(questionHistories).length === 0) {
throw new Error('Missing required data');
}
const apiData = {
participant_id: "participant_123", // Replace with actual participant ID
question_histories: questionHistories,
questions: {
// Map of question IDs to question text
// e.g., Q1: "How do you feel our software has impacted your daily workflow?"
},
responses: responses,
survey_id: "survey_456", // Replace with actual survey ID
fingerprint_id: fingerprintId
};
const response = await fetch('https://api.roundtable.ai/alias/latest', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'api_key': '<api_key>' // Replace with your actual API key
},
body: JSON.stringify(apiData)
});
if (!response.ok) {
throw new Error('API call failed');
}
return await response.json();
};
Step 5: Implement in a Survey Component
import React, { useState } from 'react';
import OpenEndQuestion from './OpenEndQuestion';
import useFingerprint from './useFingerprint';
const Survey = () => {
const [questionHistories, setQuestionHistories] = useState({});
const [responses, setResponses] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState(null);
const [isCompleted, setIsCompleted] = useState(false);
const fingerprintId = useFingerprint();
const handleQuestionComplete = (id, history, response) => {
setQuestionHistories(prev => ({ ...prev, [id]: history }));
setResponses(prev => ({ ...prev, [id]: response }));
};
const handleSubmit = async () => {
setIsSubmitting(true);
setError(null);
try {
await callApi(questionHistories, fingerprintId, responses);
setIsCompleted(true);
} catch (err) {
setError(err.message);
} finally {
setIsSubmitting(false);
}
};
const questions = [
{ id: 'Q1', text: "How do you feel our software has impacted your daily workflow?" },
{ id: 'Q2', text: "What features would you like to see in future updates?" }
];
return (
<div>
{questions.map(q => (
<OpenEndQuestion
key={q.id}
id={q.id}
question={q.text}
onComplete={(history, response) => handleQuestionComplete(q.id, history, response)}
/>
))}
<button onClick={handleSubmit} disabled={isSubmitting}>
Submit Survey
</button>
{isSubmitting && <p>Submitting responses...</p>}
{error && <p>Error: {error}</p>}
{isCompleted && <p>Survey submitted successfully!</p>}
</div>
);
};
export default Survey;
This implementation:
- Sets up fingerprinting using a custom hook.
- Tracks open-end question responses and histories.
- Makes an API call when the submit button is clicked.
Remember to replace placeholder values (e.g. API key, participant ID, survey ID) with actual values in your implementation.