astro-loader-goodreads
TypeScript icon, indicating that this package has built-in type declarations

1.2.0 • Public • Published

astro-loader-goodreads

npm version npm downloads License JSDocs bundle

Astro Goodreads How to use Goodreads data in Astro

Load Goodreads data for books in shelves/lists, user updates, and author blogs into Astro.

[!NOTE] astro-loader-goodreads uses the Astro Content Loader API to fetch data from Goodreads RSS feeds.

See the Usage section below for instructions on how to use the package to load the fetched Goodreads data into Astro Content Collections.


Table of Contents


Features

  • Load Bookshelves: Import your Goodreads shelves to showcase your reading list, books you've read, or want to read.
  • User Updates: Display your latest Goodreads activity including reading status updates, reviews, and likes.
  • Author Blogs: Fetch author blogs from Goodreads to display updates from your favorite authors.
  • Astro Content Collections: Seamlessly integrates with Astro's content collection system for type-safe data access.

Community Examples

Below are some examples of websites that use astro-loader-goodreads. If you wish to add your site to this list, open a pull request!

Site Page Description Source
sadman.ca sadman.ca/about Books I'm currently reading and have recently finished.

Installation

npm add astro-loader-goodreads

Usage

Loader Options

Property Description Required Default
url The URL of your Goodreads shelf, user, or author. -
refreshIntervalDays Number of days to cache data before fetching again from Goodreads. 0

When refreshIntervalDays is set (e.g., to 7 for weekly updates), the loader will only fetch new data from Goodreads when that many days have passed since the last fetch. feat: Add optional loader option refreshIntervalDays. If not specified, no caching is done between builds (Astro's default data caching between page loads still applies).

Defining & Using Astro Content Collections

astro-loader-goodreads supports loading Goodreads data from 3 types of urls:

  1. Shelves: Load books from a Goodreads shelf.
  2. User Updates: Load a Goodreads user's updates feed.
  3. Author Blogs: Load a Goodreads author's blog.

In your content.config.ts or src/content/config.ts file, you can define your content collections using each type of URL with the goodreadsLoader function.

[!NOTE] For the full list of fields available for Astro content collections created using astro-loader-goodreads, see the Data Schema section below.


1. Goodreads Shelves

To load data for books from a Goodreads shelf, use the shelf's URL (e.g. https://www.goodreads.com/review/list/152185079-sadman-hossain?shelf=currently-reading). astro-loader-goodreads will convert it to the correct RSS feed URL automatically.

[!IMPORTANT] The RSS feed for a Goodreads shelf only includes the last 100 books added to that shelf. This means that if there are more than 100 books in a shelf, astro-loader-goodreads will not be able to retrieve them all.

You can, however, create multiple shelves (e.g. read-2025, read-2026, etc.) and then create a content collection for each shelf to get around this limitation.

// src/content/config.ts
import { defineCollection } from "astro:content";
import { goodreadsLoader } from "astro-loader-goodreads";

const currentlyReading = defineCollection({
  loader: goodreadsLoader({
    url: "https://www.goodreads.com/review/list/152185079-sadman-hossain?shelf=currently-reading",
    refreshIntervalDays: 7, // optional parameter; set to only fetch new data once per week
  }),
});

export const collections = { currentlyReading };
---
// src/pages/reading.astro
import { getCollection } from "astro:content";

const books = await getCollection("currentlyReading");
---

<h1>Books I'm Currently Reading</h1>

<div class="book-grid">
  {books.map((book) => (
    <div class="book-card">
      <img src={book.data.book_large_image_url} alt={`Cover of ${book.data.title}`} />
      <h2>{book.data.title}</h2>
      <p class="author">by {book.data.author_name}</p>
      {book.data.user_rating > 0 && (
        <p class="rating">My rating: {book.data.user_rating}/5</p>
      )}
      <a href={book.data.link} target="_blank" rel="noopener noreferrer">
        View on Goodreads
      </a>
    </div>
  ))}
</div>

<style>
  .book-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 2rem;
  }
  .book-card {
    border: 1px solid #eee;
    border-radius: 0.5rem;
    padding: 1rem;
    text-align: center;
  }
  .book-card img {
    max-width: 100%;
    height: auto;
  }
</style>

2. Goodreads User Updates

To load a Goodreads user's updates feed, use the user's profile URL (e.g. https://www.goodreads.com/user/show/152185079-sadman-hossain). astro-loader-goodreads will convert it to the correct RSS feed URL automatically.

[!IMPORTANT] The RSS feed for a Goodreads user's updates only includes the last 10 updates by that user. This means that astro-loader-goodreads cannot retrieve more than 10 updates for any single user.

// src/content/config.ts
import { defineCollection } from "astro:content";
import { goodreadsLoader } from "astro-loader-goodreads";

const userUpdates = defineCollection({
  loader: goodreadsLoader({
    url: "https://www.goodreads.com/user/show/152185079-sadman-hossain",
  }),
});

export const collections = { userUpdates };
---
// src/pages/activity.astro
import { getCollection } from "astro:content";

const updates = await getCollection("userUpdates");

// Sort updates by publication date (newest first)
const sortedUpdates = updates.sort((a, b) => 
  new Date(b.data.pubDate).getTime() - new Date(a.data.pubDate).getTime()
);
---

<h1>My Goodreads Activity</h1>

<div class="activity-feed">
  {sortedUpdates.map((update) => {
    const itemData = update.data.itemData;
    
    return (
      <div class="activity-item">
        <p class="date">{new Date(update.data.pubDate).toLocaleDateString()}</p>
        
        {itemData?.type === "ReadStatus" && (
          <div class="read-status">
            <img 
              src={itemData.bookImgUrl} 
              alt={`Cover of ${itemData.bookTitle}`} 
              width="50"
            />
            <div>
              <p>
                <strong>{itemData.readingStatus}</strong> 
                <a href={itemData.bookUrl}>{itemData.bookTitle}</a> 
                by {itemData.bookAuthor}
              </p>
            </div>
          </div>
        )}
        
        {itemData?.type === "Review" && (
          <div class="review">
            <img 
              src={itemData.bookImgUrl} 
              alt={`Cover of ${itemData.bookTitle}`} 
              width="50"
            />
            <div>
              <p>
                Rated <strong>{itemData.rating} stars</strong> for 
                <a href={itemData.bookUrl}>{itemData.bookTitle}</a> 
                by {itemData.bookAuthor}
              </p>
            </div>
          </div>
        )}
        
        {itemData?.type === "CommentReview" && (
          <div class="comment-review">
            <div>
              <p>
                Commented on <a href={itemData.reviewUrl}>{itemData.reviewUser}'s review</a> of 
                <a href={itemData.bookUrl}>{itemData.bookTitle}</a>:
              </p>
              <blockquote>"{itemData.comment}"</blockquote>
            </div>
          </div>
        )}
        
        {/* Add additional item types as needed */}
      </div>
    );
  })}
</div>

3. Goodreads Author Blogs

To load Goodreads author blog posts, use the author's URL (e.g. https://www.goodreads.com/author/show/3389.Stephen_King). astro-loader-goodreads will append the necessary parameters to fetch the blog RSS feed automatically.

// src/content/config.ts
import { defineCollection } from "astro:content";
import { goodreadsLoader } from "astro-loader-goodreads";

const authorBlog = defineCollection({
  loader: goodreadsLoader({
    url: "https://www.goodreads.com/author/show/3389.Stephen_King",
  }),
});

export const collections = { authorBlog };
---
// src/pages/author-updates.astro
import { getCollection } from "astro:content";

const posts = await getCollection("authorBlog");
---

<h1>Latest Updates from Stephen Kingn</h1>

<div class="blog-posts">
  {posts.map((post) => (
    <article class="blog-post">
      <h2>{post.data.title}</h2>
      <p class="date">Published: {new Date(post.data.pubDate).toLocaleDateString()}</p>
      {post.data.content && (
        <div class="content" set:html={post.data.content} />
      )}
      <a href={post.data.link}>Read on Goodreads</a>
    </article>
  ))}
</div>

Data Schema

Overview

The astro-loader-goodreads package provides three main schemas:

  1. BookSchema - For books from Goodreads shelves
  2. UserUpdateSchema - For user updates (with various activity types)
  3. AuthorBlogSchema - For author blog posts

1. BookSchema

This schema is used when loading data from a Goodreads shelf.

export const BookSchema = z.object({
  id: z.coerce.string(),
  title: z.coerce.string(),
  guid: z.string(),
  pubDate: z.string(),
  link: z.string(),
  book_id: z.coerce.string(),
  book_image_url: z.string(),
  book_small_image_url: z.string(),
  book_medium_image_url: z.string(),
  book_large_image_url: z.string(),
  book_description: z.string(),
  num_pages: z.string().optional(),
  author_name: z.string(),
  isbn: z.coerce.string(),
  user_name: z.string(),
  user_rating: z.number(),
  user_read_at: z.string(),
  user_date_added: z.string(),
  user_date_created: z.string(),
  user_shelves: z.string().optional(),
  user_review: z.string().optional(),
  average_rating: z.number(),
  book_published: z.coerce.string(),
});

Book Fields

Field Description
id Unique identifier for the book
title Book title
guid Global unique identifier for this entry
pubDate Publication date of this entry in the feed
link URL to the book's Goodreads page
book_id Goodreads ID for the book
book_image_url URL to the book cover image
book_small_image_url URL to small version of book cover (50×75 px)
book_medium_image_url URL to medium version of book cover (65×98 px)
book_large_image_url URL to large version of book cover (316×475 px)
book_description Description/synopsis of the book
num_pages Number of pages in the book (optional)
author_name Name of the book's author
isbn International Standard Book Number
user_name Username of who added the book to their shelf
user_rating Rating given by the user (0-5)
user_read_at Date when the user finished reading the book
user_date_added Date when the book was added to the user's shelf
user_date_created Date when this entry was created
user_shelves List of shelves the user assigned to this book (optional)
user_review User's review of the book (optional)
average_rating Average rating on Goodreads
book_published Book's original publication date

2. UserUpdateSchema

This schema is used when loading data from a Goodreads user's updates feed.

export const UserUpdateSchema = z.object({
  id: z.string(),
  title: z.string(),
  link: z.string().optional(),
  description: z.string().optional(),
  pubDate: z.string(),
  itemType: z.string().optional(),
  itemData: ItemDataSchema.optional()
});

UserUpdateSchema Item Types

The itemData field contains a discriminated union based on the type field:

AuthorFollowing

When a user follows an author:

{
  type: "AuthorFollowing",
  followId: string,
  userUrl: string, 
  authorId: string
}

UserStatus

When a user reports progress on a book:

{
  type: "UserStatus",
  userUrl: string,
  percentRead: string,
  bookUrl: string,
  bookTitle: string,
  bookAuthor: string,
  bookImgUrl: string
}

ReadStatus

When a user changes their reading status:

{
  type: "ReadStatus",
  userUrl: string, 
  readingStatus: string, // 'started reading', 'wants to read', or 'finished reading'
  bookUrl: string,
  bookTitle: string,
  bookAuthor: string,
  bookImgUrl: string
}

Review

When a user posts a review:

{
  type: "Review",
  userUrl: string,
  rating: number,
  bookUrl: string,
  bookTitle: string,
  bookAuthor: string,
  bookImgUrl: string
}

LikeReview

When a user likes someone's review:

{
  type: "LikeReview",
  userUrl: string,
  reviewUrl: string,
  reviewUser: string,
  bookUrl: string,
  bookTitle: string,
  bookImgUrl: string
}

LikeReadStatus

When a user likes someone's read status:

{
  type: "LikeReadStatus",
  userUrl: string,
  readStatusUser: string,
  readStatusUserImgUrl: string,
  readStatus: string,
  bookUrl: string,
  bookTitle: string
}

CommentStatus

When a user comments on a status:

{
  type: "CommentStatus",
  userUrl: string,
  statusUrl: string,
  statusUser: string,
  comment: string
}

CommentReview

When a user comments on a review:

{
  type: "CommentReview",
  userUrl: string,
  reviewUrl: string,
  reviewUser: string,
  bookUrl: string,
  bookTitle: string,
  bookAuthor: string,
  comment: string
}

3. AuthorBlogSchema

This schema is used when loading data from a Goodreads author's blog.

export const AuthorBlogSchema = z.object({
  id: z.string(),
  title: z.string(),
  link: z.string(),
  description: z.string(),
  pubDate: z.string(),
  author: z.string().optional(),
  content: z.string().optional(),
});

AuthorBlogSchema Fields

Field Description
id Unique identifier for the blog post
title Blog post title
link URL to the blog post
description Raw HTML description of the blog post
pubDate Publication date
author Author's name (if available)
content Main content of the blog post (if available)

License

astro-loader-goodreads is MIT licensed.


Built with ♥ by @sadmanca!

Package Sidebar

Install

npm i astro-loader-goodreads

Weekly Downloads

20

Version

1.2.0

License

MIT

Unpacked Size

174 kB

Total Files

9

Last publish

Collaborators

  • sadmanca