Book tracker !
My Books by Year v.2
Every book I read is organized by year using Goodreads.
The first version of this project relied on manually importing a CSV file containing all the books saved on Goodreads into the hardcover.app website. I wasn’t satisfied with that approach because of the manual step in the middle. After a sudden spark of inspiration, I realized I could use Goodreads’ RSS functionality to fetch information about the books I’ve read and build a cleaner, more streamlined version—where the only manual action required is updating my Goodreads shelves.
The original version is still available, but I decided not to maintain it anymore. You can still take a look at it through this link.
Each list corresponds to a specific year.
You might be wondering what the point of all these trackers is… well, I just enjoy them.
Loading...
Technical Details
This page works thanks to a small front-end script + a Cloudflare Worker acting as a proxy/parser for Goodreads RSS feeds.
Architecture Overview
Front-end Workflow (UI + Fetch)
When the Book Tracker page loads, the JavaScript running in the browser first determines the current year using new Date().getFullYear() and generates an array of years from the defined START_YEAR up to the current year, reversing the order so that the most recent years appear first. This array is then passed to the generateMenu() function, which dynamically constructs the navigation menu in the user interface, creating a clickable link for each year. After generating the menu, the script simulates a click on the first year in the list—usually the most recent one—and calls the loadYear() function to fetch and load the books for that year. During this process, the book data is retrieved and the books grid in the UI is populated with cards for each book, displaying the cover image, title, and a link to Goodreads, allowing users to immediately browse the books read in the selected year.
Backend Workflow (Worker RSS Parser)
When the front-end requests book data for a specific Goodreads shelf, it sends a GET request to the Cloudflare Worker with the rssUrl parameter. The Worker first validates that the URL is well-formed and that the hostname includes goodreads.com to prevent invalid or malicious requests. Once validated, the Worker fetches the RSS feed from Goodreads, receiving the XML containing multiple <item> blocks, each representing a book. The Worker then parses each <item> block, extracting relevant information such as the book title, author name, cover image URL (falling back to medium or small images if necessary), Goodreads link, and the description. Optionally, it also parses the user’s completion date if available. After processing all items, the Worker returns a clean JSON object to the front-end containing the total count of books and an array of book objects with all the extracted metadata, ready to be rendered in the UI.
Data Extraction (from RSS - )
Each RSS
Resulting object example:
{
"title": "Example Title",
"author": "Example Author",
"cover": "https://...",
"goodreadsUrl": "https://www.goodreads.com/book/show/...",
"description": "Clean description text",
"readAt": "2024-01-03T08:00:00.000Z"
}
Why the Worker is Needed
Goodreads RSS is served as XML and cannot be easily consumed directly in the browser as structured data. The Worker solves this by:
-
acting as a CORS-friendly proxy
-
converting RSS XML → JSON
-
providing a consistent output format for the UI
Summary
What's New in This Version
- Added dynamic year-based navigation menu (from START_YEAR to current year).
- Implemented JSON parsing of RSS feed with proper handling of CDATA and plain text titles.
- Added filtering by year of completion (`user_read_at`) on the Worker.
- Updated front-end to fetch parsed JSON from Worker and render books grid per year.
- Added detailed documentation and Mermaid diagrams for front-end and back-end workflow.
- CORS support added to Worker for cross-origin requests.
Notes mentioning this note
There are no notes linking to this note.