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.

How sessions work

A session is a 30-minute browsing window. When you call selectProfile(), the SDK mints a session credential automatically. You never manage it directly — it’s included in every page and row request behind the scenes. When a session expires, page fetches return SESSION_EXPIRED. Profile-scoped operations (lists, playback, scrobbling) still work — they use the long-lived identity credential, not the session.
Sessions are per-profile. Switching profiles starts a new session automatically. New session = new recommendation snapshot = fresh results.

Recommendation snapshots

Within a session, pages with the same filters always return the same page ID and results. This is intentional — it keeps your user’s experience consistent while they browse.
ScenarioResult
Same filters, same sessionSame page ID, same rows
Same filters, new sessionNew page ID, fresh rows
Different filters, same sessionDifferent page ID, different rows
When a user opens Home, drills to Movies, then hits Back — they expect to land exactly where they were. Snapshots make this possible without you managing any local state.
// Within session A, same filters → same page ID
const home1 = await client.createPage({ name: "Home" });
const home2 = await client.createPage({ name: "Home" });
// home1.id === home2.id

Keeping sessions alive

The SDK refreshes sessions in the background automatically — subscribe to onSessionRefreshed once after sign-in and your pages always use a fresh session:
client.onSessionRefreshed(({ profileId, expiresAt }) => {
	// Page snapshots from the previous session are stale — recreate pages to get fresh recommendations
	recreateCurrentPage();
});
The expiresAt timestamp tells you exactly when the current session will auto-refresh — useful for pre-warming data before the snapshot turns over.

Handling SESSION_EXPIRED

Even with automatic refresh, SESSION_EXPIRED can reach your code — the user may browse without activity for over 30 minutes, or switch profiles just as a session lapses. When it happens, the error echoes back the page’s original pageLevelFilters. Use them to recreate the page in the current session:
async function getPageSafely(pageId: string) {
	try {
		return await client.getPage(pageId);
	} catch (err) {
		if (err.code === "SESSION_EXPIRED") {
			const newPage = await client.createPage({
				pageFilters: err.pageLevelFilters,
			});
			return await client.getPage(newPage.id);
		}
		throw err;
	}
}
Paginating row items with getRowItems() intentionally skips the freshness check — so users can keep scrolling a rail they’re already in without interruption.

Recovery checklist

When you get SESSION_EXPIRED:
  • Read err.pageLevelFilters from the error — this is the filter set for the stale page
  • Call createPage() with those filters to create a fresh snapshot
  • Fetch the new page with getPage()
  • Render fresh content — optionally show a brief “Updated” toast

Profile switching

Switching profiles creates a new session immediately. Page IDs from the previous profile’s session are stale:
await client.selectProfile(aliceId);
const aliceHome = await client.createPage({ name: "Home" }); // Session A

await client.selectProfile(bobId); // New session B starts

const bobHome = await client.createPage({ name: "Home" });
// bobHome.id !== aliceHome.id — different session, different snapshot
Don’t reuse page IDs across profiles — each profile gets its own recommendations.
Next: Lazy Loading & Performance