How I Built My Bookshelf

June 5, 2025

TL;DR: Since Goodreads doesn't provide an official API, I built a scraper that uses their RSS feeds to display my reading activity. It updates in real-time and requires zero maintenance.

The Problem

Goodreads doesn't provide an official API anymore, but I wanted to showcase my reading activity on my portfolio. I needed a solution that would:

  • Update automatically when I add new books
  • Work reliably without breaking
  • Be easy to maintain
  • Look cool

The Solution

I built a simple scraper with three main parts:

1. Scraper (Server-Side)

Instead of scraping HTML (which can break easily), I used Goodreads' RSS feeds. These are more reliable and easier to work with.

// Simple API route that fetches from Goodreads
const url = `https://www.goodreads.com/review/list_rss/${userId}?shelf=${shelf}`;
const response = await fetch(url, {
  headers: { 'User-Agent': 'Mozilla/5.0...' }
});

This code runs on my server and acts as a middleman between my website and Goodreads, avoiding any CORS issues.

2. Parser

The parser takes the RSS feed and extracts the book information:

// Extract book data from RSS feed
const title = item.getElementsByTagName('title')[0]?.textContent || '';
const author = item.getElementsByTagName('author_name')[0]?.textContent || '';
const image = item.getElementsByTagName('book_image_url')[0]?.textContent || '';

// Make the book cover image high quality
const highQualityImage = image.replace('._SX50_', '._SX318_');

This gives me clean, structured data about each book, including:

  • Title
  • Author
  • High-quality cover image
  • Reading status
  • Date added

3. Cache

To prevent hitting Goodreads too often, I added a simple caching system:

// Check if we have cached data
if (cachedData && !isExpired(cachedData)) {
  return cachedData.books;
}

// If not, fetch fresh data
const books = await fetchFromGoodreads();
// Cache it for an hour
saveToCache(books);

Why This Approach?

  1. Simple but Effective

    • RSS feeds are more reliable than HTML scraping
    • The code is easy to maintain
    • The system rarely breaks
  2. User-Friendly

    • Books update automatically
    • Book covers are high quality
    • Reading status is clearly displayed
  3. Developer-Friendly

    • The code is clean and readable
    • Debugging is straightforward
    • New features are easy to add