Schema
@galya/schema defines the JSON the browser sends and the ingest worker accepts. Every event is one content interaction window: signals while the user had a tagged component in view, plus an optional snapshot when they left.
interface GalyaEvent {
eventId: string;
sessionId: string;
userId: string; // from your app
contentId: string; // data-galya-id
contentType: "text" | "image" | "video" | "audio" | "mixed";
signals: {
dwellMs: number;
dwellNormalized: number; // vs expected read time
scrollDepthPct: number;
terminalAction: "save" | "share" | "click_through" | "dismiss" | "expand" | null;
// hover, revisit, scroll direction …
};
snapshot?: ContentSnapshot; // optional rrweb capture
pageUrl: string;
timestamp: number;
sessionSequence: number;
}Batches wrap many events for one POST:
interface GalyaEventBatch {
events: GalyaEvent[];
batchId: string;
sentAt: number;
}clientId is attached server-side after auth—omit it from the SDK payload.