Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.discovr.media/llms.txt

Use this file to discover all available pages before exploring further.

When someone watches a movie or episode, they pause, rewind, and skip around. Scrobbling is how you tell Discovr about those moments—it’s the everyday heartbeat that keeps watch history and resume position in sync. Every time the user pauses, seeks, or finishes watching, you send a scrobble with their progress. Discovr uses that data to:
  • Keep the Continue Watching row up-to-date with how far they got
  • Track what they’ve watched for the history log
  • Unlock completion-based features (auto-add to lists, mark complete)

The two scrobbling calls

scrobble() — progress updates

Track progress as the user watches. Send the media ID and current progress (0–100%).
TypeScript
const resp = await discovr.scrobble(mediaId, progress);
For TV, optionally include the season and episode:
TypeScript
const resp = await discovr.scrobble(mediaId, progress, {
	tv: { season: 1, episode: 5 },
});

scrobbleSkip() — recording skips

When the user jumps around (fast-forward, rewind, skip intro), log it. This helps us understand viewing patterns.
TypeScript
const resp = await discovr.scrobbleSkip(mediaId, progress);

When to call scrobble

Call scrobble() during the typical player lifecycle:
EventExampleWhat to send
PauseUser pauses videoCurrent progress
ResumeUser un-pausesCurrent progress
SeekUser scrubs to new positionNew progress
CompletionVideo finishes or reaches thresholdprogress: 100
Don’t spam. Scrobbling every 100ms will create noise. A reasonable approach:
  • On pause / resume / completion: scrobble immediately
  • During playback: scrobble every 10–30 seconds (or on significant seeks)

Example: A simple player heartbeat

Here’s how you might wire a player to scrobble as the user watches:
import { DiscovrClient } from "discovr";
import type { ScrobbleResponse } from "discovr";

const discovr = new DiscovrClient("your-client-id", {
	basePath: "https://api.discovr.media",
});

// Call this when user pauses
async function onPause(mediaId: string, progress: number) {
	const resp: ScrobbleResponse = await discovr.scrobble(mediaId, progress);
	console.log("Paused at:", resp.playback?.data?.progress);
}

// Call this when user skips (e.g., skip intro button)
async function onSkip(mediaId: string, fromProgress: number, toProgress: number) {
	await discovr.scrobbleSkip(mediaId, toProgress);
	await discovr.scrobble(mediaId, toProgress);
}

// Call this periodically during playback (e.g., every 10 seconds)
async function heartbeat(mediaId: string, progress: number) {
	const resp: ScrobbleResponse = await discovr.scrobble(mediaId, progress);
	return resp;
}

About skip data

At the moment scrobbleSkip() has no effect on the user’s data, but we’re hoping to use the data for automatic detection of intros and outros so Discovr can help make “Skip Intro” buttons in the future. If your player supports skip detection, please send it via scrobbleSkip().

Playback vs History

Scrobble is the everyday path during viewing—it updates the Continue Watching queue and feeds the history log. If you need to correct or backfill history (e.g., marking a title watched after the fact, or adjusting completion metadata), use the history APIs instead. See Profile context for the distinction between playback (resume queue) and history (event log).