Next.js
WriteTrack uses browser APIs and must run client-side only. Here’s how to integrate it with Next.js.
App Router (Next.js 13+)
Section titled “App Router (Next.js 13+)”Add the 'use client' directive to components using WriteTrack:
'use client';
import { useRef, useEffect } from 'react';import { WriteTrack } from 'writetrack';
export function ResponseForm() { const textareaRef = useRef<HTMLTextAreaElement>(null); const trackerRef = useRef<WriteTrack | null>(null);
useEffect(() => { if (textareaRef.current) { trackerRef.current = new WriteTrack({ target: textareaRef.current }); trackerRef.current.start(); }
return () => { trackerRef.current?.stop(); }; }, []);
const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (trackerRef.current) { const data = trackerRef.current.getData(); const events = trackerRef.current.getRawEvents(); console.log(`Captured ${events.length} events`, data.quality); } };
return ( <form onSubmit={handleSubmit}> <textarea ref={textareaRef} rows={10} /> <button type="submit">Submit</button> </form> );}Using the React Hook
Section titled “Using the React Hook”The writetrack/react hook handles client-side concerns automatically:
'use client';
import { useRef } from 'react';import { useWriteTrack } from 'writetrack/react';
export function ResponseForm() { const textareaRef = useRef<HTMLTextAreaElement>(null); const { isTracking, tracker } = useWriteTrack(textareaRef);
const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (tracker) { const data = tracker.getData(); console.log('Session:', data.quality); } };
return ( <form onSubmit={handleSubmit}> <textarea ref={textareaRef} rows={10} /> <button type="submit">Submit</button> </form> );}Pages Router
Section titled “Pages Router”For the Pages Router, either use the 'use client' approach above, or use dynamic imports:
import dynamic from 'next/dynamic';
const ResponseForm = dynamic(() => import('../components/ResponseForm'), { ssr: false,});
export default function Page() { return <ResponseForm />;}Server Actions
Section titled “Server Actions”Send captured data to Server Actions:
'use client';
import { useRef } from 'react';import { useWriteTrack } from 'writetrack/react';import { submitResponse } from './actions';
export function ResponseForm() { const textareaRef = useRef<HTMLTextAreaElement>(null); const { tracker } = useWriteTrack(textareaRef);
async function handleSubmit(formData: FormData) { if (tracker) { formData.set('keystrokeCount', String(tracker.getKeystrokeCount())); }
await submitResponse(formData); }
return ( <form action={handleSubmit}> <textarea ref={textareaRef} name="content" rows={10} /> <button type="submit">Submit</button> </form> );}'use server';
export async function submitResponse(formData: FormData) { const content = formData.get('content') as string; const keystrokeCount = formData.get('keystrokeCount') as string;
// Store or process the submission await db.responses.create({ content, keystrokeCount: Number(keystrokeCount), });}API Routes
Section titled “API Routes”Alternatively, send data to API routes:
const handleSubmit = async () => { if (!tracker) return;
const data = tracker.getData();
await fetch('/api/submit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: textareaRef.current?.value, typingData: data, }), });};