This guide covers read progress tracking, including marking books as read/unread, tracking page progress, and managing series-level read status.
Book read progress
Mark a book as read
Mark a book as completely read:
import { markBookReadProgress } from 'komga-sdk' ;
await markBookReadProgress ({
client ,
path: { bookId: 'book-123' },
body: {
completed: true ,
},
});
Update page progress
Track which page the user is currently on:
import { markBookReadProgress } from 'komga-sdk' ;
await markBookReadProgress ({
client ,
path: { bookId: 'book-123' },
body: {
page: 42 ,
completed: false ,
},
});
The page parameter is 1-indexed. Page 1 is the first page of the book.
Mark a book as unread
Remove all read progress for a book:
import { deleteBookReadProgress } from 'komga-sdk' ;
await deleteBookReadProgress ({
client ,
path: { bookId: 'book-123' },
});
Series read progress
Mark an entire series as read
Mark all books in a series as read:
import { markSeriesAsRead } from 'komga-sdk' ;
await markSeriesAsRead ({
client ,
path: { seriesId: 'series-123' },
});
Mark an entire series as unread
Remove read progress from all books in a series:
import { markSeriesAsUnread } from 'komga-sdk' ;
await markSeriesAsUnread ({
client ,
path: { seriesId: 'series-123' },
});
OPDS progression (position tracking)
OPDS progression provides detailed position tracking for e-readers and reading apps. It stores the exact position within a book, including device information.
Get book progression
Retrieve the current reading position:
import { getBookProgression } from 'komga-sdk' ;
const result = await getBookProgression ({
client ,
path: { bookId: 'book-123' },
});
if ( result . data ) {
console . log ( `Last position: ${ result . data . locator ?. locations ?. position } ` );
console . log ( `Progress: ${ ( result . data . locator ?. locations ?. totalProgression ?? 0 ) * 100 } %` );
console . log ( `Device: ${ result . data . device ?. name } ` );
}
Update book progression
Save the current reading position with device info:
import { updateBookProgression } from 'komga-sdk' ;
await updateBookProgression ({
client ,
path: { bookId: 'book-123' },
body: {
device: {
id: 'device-unique-id' ,
name: 'My Kindle' ,
},
locator: {
href: '/chapter1.xhtml' ,
type: 'application/xhtml+xml' ,
locations: {
position: 1250 ,
totalProgression: 0.45 ,
},
},
modified: new Date (). toISOString (),
},
});
OPDS progression is designed for EPUB readers. For simpler page-based tracking (comics, manga), use markBookReadProgress instead.
Common workflows
Build a reading tracker
Track reading progress across your library:
import { getBooks , markBookReadProgress } from 'komga-sdk' ;
async function getReadingStats () {
const result = await getBooks ({
client ,
body: {},
query: { page: 0 , size: 100 },
});
if ( ! result . data ) return ;
const stats = {
total: result . data . totalElements ,
unread: 0 ,
inProgress: 0 ,
completed: 0 ,
};
for ( const book of result . data . content ) {
const progress = book . readProgress ;
if ( ! progress ) {
stats . unread ++ ;
} else if ( progress . completed ) {
stats . completed ++ ;
} else {
stats . inProgress ++ ;
}
}
return stats ;
}
Resume reading
Find where the user left off:
import { getBooks } from 'komga-sdk' ;
async function getInProgressBooks () {
const result = await getBooks ({
client ,
body: {
readStatus: [ 'IN_PROGRESS' ],
},
query: {
page: 0 ,
size: 10 ,
sort: [ 'readProgress.readDate,desc' ],
},
});
if ( ! result . data ) return [];
return result . data . content . map ( book => ({
id: book . id ,
title: book . metadata . title ,
currentPage: book . readProgress ?. page ?? 1 ,
totalPages: book . media . pagesCount ,
lastRead: book . readProgress ?. readDate ,
}));
}
Mark multiple books as read
Batch mark books as read (e.g., catch up on a series):
import { getBooksBySeriesId , markBookReadProgress } from 'komga-sdk' ;
async function markBooksAsReadUpTo ( seriesId : string , upToBookNumber : number ) {
// Get all books in the series
const result = await getBooksBySeriesId ({
client ,
path: { seriesId },
query: { sort: [ 'metadata.numberSort,asc' ] },
});
if ( ! result . data ) return ;
// Mark books up to the specified number as read
for ( const book of result . data . content ) {
const bookNumber = book . metadata . numberSort ;
if ( bookNumber <= upToBookNumber ) {
await markBookReadProgress ({
client ,
path: { bookId: book . id },
body: { completed: true },
});
}
}
}
Sync progress across devices
Use OPDS progression to maintain consistent position across devices:
import { getBookProgression , updateBookProgression } from 'komga-sdk' ;
const DEVICE_ID = 'unique-device-identifier' ;
const DEVICE_NAME = 'Web Reader' ;
async function syncReadingPosition ( bookId : string , newPosition : number , totalProgress : number ) {
// Get current server position
const current = await getBookProgression ({
client ,
path: { bookId },
});
// Only update if our position is newer
const serverModified = current . data ?. modified ? new Date ( current . data . modified ) : new Date ( 0 );
const now = new Date ();
if ( now > serverModified ) {
await updateBookProgression ({
client ,
path: { bookId },
body: {
device: {
id: DEVICE_ID ,
name: DEVICE_NAME ,
},
locator: {
href: '' ,
type: 'application/octet-stream' ,
locations: {
position: newPosition ,
totalProgression: totalProgress ,
},
},
modified: now . toISOString (),
},
});
}
}
Read status filtering
Use read status when searching for books:
import { getBooks } from 'komga-sdk' ;
// Get unread books
const unread = await getBooks ({
client ,
body: { readStatus: [ 'UNREAD' ] },
query: { page: 0 , size: 20 },
});
// Get in-progress books
const inProgress = await getBooks ({
client ,
body: { readStatus: [ 'IN_PROGRESS' ] },
query: { page: 0 , size: 20 },
});
// Get completed books
const completed = await getBooks ({
client ,
body: { readStatus: [ 'READ' ] },
query: { page: 0 , size: 20 },
});
Read status values are: UNREAD, IN_PROGRESS, and READ.
Error handling
import { markBookReadProgress } from 'komga-sdk' ;
const result = await markBookReadProgress ({
client ,
path: { bookId: 'book-123' },
body: { completed: true },
});
if ( result . error ) {
switch ( result . response ?. status ) {
case 404 :
console . error ( 'Book not found' );
break ;
case 401 :
console . error ( 'Not authenticated' );
break ;
default :
console . error ( 'Error updating progress:' , result . error );
}
}
Next steps
Books Learn more about book operations.
Series Manage series and their metadata.