How I turned my Goodreads data into a self-hosted website with Eleventy

In the last week of 2020, I decided to export my Goodreads data to display it on my personal website. This post is about what I did and how.

Screenshot

Why export?

First, I quite like Goodreads. It lets me see the reads of friends and acquaintances. It lets me share my own. This is all splendid, but it is still somebody else’s site. Somebody with very different life goals from my own, in fact. For more control on what I display and how, I decided to create a new section of this website dedicated to books, fed by an export of my Goodreads data.

The two main reasons I use Goodreads are people and books. I want to connect with (internet) friends and be inspired by what they read. I also want to keep track of what I have read and plan to read, for instance when a person or article mentions an interesting book. When I’m reading a book review in the paper, I’l sometimes grab my phone and add the thing to the list. Goodreads has an easy to use catalog that usually lists what I searched.

Some things to dislike about the platform are the gamification and the generic recommendations: it’s noise that I could do without (“you read something in philosophy, maybe you’ll like this book by Plato”). There are also lots of trackers, and it is powered by a faceless multi-billion dollar enterprise that threatens the livelihood of friendly, local bookshops.

Some features

Various people’s online bookshelves inspired me to create one on this site, including Melanie Richard’s highlights, focused on highlights, Dave Rupert’s Bookshelf, which features many short reviews and half stars, Tom McWright’s, Maggie Appleton’s, Mandy Brown’s, Alex Chan’s, Sawyer Hollenshead (also with highlights) and Amanda Pinkster (includes where she read them).

I like the processes of other people: Katy Decorah uses GitHub actions, Nienke uses her own What.pm and Jeremy Keith tags notes with ISBN numbers. My process is still different from each of them though, for no particular reason.

For me, a personal book repository does not require a lot, but these are some features I wanted to have:

Separate views for Dutch and English
I mostly read in these two languages, some viewers may only be interested in either section.
Hand-picked book covers
‘Never judge a book by its cover’, they say. Well, I like book covers as expectation setters and did not automate the cover art collection process.
Links to author’s personal sites
Personal sites deliver on the promise of the web, said Matthias Ott in Make it personal. I haven’t enriched a lot of the data with this piece of information, but will be.
Dark mode
Because CSS is fun. I went for a midnightblue background with khaki text.
No tracking
This site does not track users. Minimum Viable Data Collection (zero, in this case) ftw.

What I could automate

CSV entries to front matter in Markdown

I decided to use Eleventy to turn my data into a web page, as I like its flexibility, its focus on simplicity and its firm hesitation to make decisions for developers using it.

Goodreads provides reading data in CSV files, which are reasonably well structured. For the Eleventy site, I needed a folder full of Markdown files, one for each book, with basically the metadata from the Goodreads export as Yaml front matter:

---
title: "Uncanny Valley"
author: "Anna Wiener"
isbn: "0374278016"
isbn13: "9780374278014"
rating: "5"
publisher: "MCD"
pages: "281"
publishYear: "2020"
read: "2020"
goodreads_id: "45186565"
---

I did this in Node using a slightly modified version of CSV to Markdown. The project is archived and I could not get the Noderize wrapper to work, but the provided script in index.js did the job for me.

It seems like Hay Kranen’s dataknead may be a great alternative to do this work (in Python).

Image processing

This site has a lot of images, and resizing or optimising would not be my definition of fun. I used the official Image plugin for Eleventy to generate correctly sized images from my source images, and the documented Nunjucks shortcode to output a picture element with webp and jpg versions in various sizes.

I used the native lazyloading attribute, loading="lazy" , which I learned only in this project, is not added to the picture-element, but to the fallback <img> .

The grid

I knew how I wanted my content to be layed out, but I didn’t know what my content would be. Grid Layout is fantastic if that’s your situation. I used grid’s autoplacement feature: I defined a grid, added the content in HTML and each book magically appeared in its right place.

books with grid browser tools overlayed

On small screens, I used the non-default autoflow value column, to make new items appear horizontally.

What I didn’t automate

In web projects, we often balance between spending time to automate versus doing it manually. Sure, automation can be a fun thing to work on. But if I’m honest, I only want to do it if it saves more time than it costs.

Book covers

Cover art is among the highest forms of graphic design. Covers of music and books can be incredibly creative. Film posters can be a prone to cliche overuse, but have you seen Saul Bass’s movie posters?

Books often get different covers when they are reprinted or distributed in different countries. This project was the perfect excuse to handpick my favourite for each book.

CSS authoring

There was not enough complexity to warrant any form of CSS processing, so I just created a single CSS file and started adding styles. I used no methodology or framework. I did mostly avoid classes, because in my day to day work I overuse them and it seemed like a fun challenge.

Extra data

I’ve also added some data manually that I didn’t have in Goodreads, like the language I read a book in. And I want to slowly add more data to some books, like the URI for the author’s personal website, and, in case I wrote a review, a link to that review.

Future features

There are some things that I would like to improve when there’s more time or less lockdown. A website is never finished!

Some interface to add data
Adding a new book now involves me manually creating a Markdown file with the right front matter and a JPG file with the same name for the book cover. I could automate at least part of this.
Filters
Books can currently display by language. If I started adding tags to books, I could create sub lists, “Show books about topic X”. That would be fairly trivial to do.
Better sorting
I messed up transforming the date field in the Goodreads export, so now I only have a year and no way to sort by reading date. I plan to add this for new books.
RSS
I doubt anyone would subscribe to something like this, but wide availability of reading list RSS feeds would allow us all to create a decentralised Goodreads in feed reader software of our choice.
Better lazyloading
Currently, all images on the book site have the loading="lazy" attribute. The recommended way is to only add this attribute for images that are not in the viewport. I’m not sure how to solve that on this site, because my grid grows with the viewport. Which images are in your viewport, depends on how wide it is.
Better markup
Maybe I can use more standard markup for the books, like microformats. The indieweb personal library page has some pointers, including Paul Munday’s example of microformats for books.

Woops, that’s quite the list. Let me just postpone it to the next sprint.

Wrapping up

So, my book site is available on books.hiddedevries.nl, the source is on GitHub. This has been a fun weekend project, and to be honest, I am very much looking forward to continue expanding the existing data and add new stuff.

If you have one of these digital bookshelves yourself, please do share them in the comments or reply on Twitter! If you have any thoughts or opinions on what I’ve done, feel free to let me know.

Comments, likes & shares (95)

Gonçalo Morais 🏡 wrote on 7 January 2021:
This is great! I did the same a while back (bookshelf.gnclmorais.com) but it definitely doesn’t look as elegant as yours! 👏🏻
Piotr Gaczkowski wrote on 7 January 2021:
Nice taste! How to find you there?
Accessabilly wrote on 7 January 2021:
Supercool! Thanks for sharing!
Hidde wrote on 7 January 2021:
ooohh yours is automated 🧐 nice!
Ana Rodrigues wrote on 7 January 2021:
I immediately thought of you when I saw this! I remember that I added yours to my bookmarks a while back - but took me ages to find it.
Gonçalo Morais 🏡 wrote on 7 January 2021:
For now… until GoodReads APi access gets shut down. 😔 debugger.medium.com/goodreads-is-r…
matt northam ᴹᴺ wrote on 7 January 2021:
Love this 👏 I've been meaning to do something similar (my Goodreads is up to date, my own site is horribly lagging books.mattnortham.com) this is a great bit of inspiration! You're manually exporting the csv though, right(?) Is the GR api route no longer viable?
Baldur Bjarnason wrote on 7 January 2021:
“How I turned my Goodreads data into a self-hosted website with Eleventy” hiddedevries.nl/en/blog/2021-0…
Beatriz Gonzalez wrote on 7 January 2021:
Sounds like a great project to take on this year :)
Accessabilly wrote on 7 January 2021:
Cool stuff!
Stephan ten Kate wrote on 7 January 2021:
Nice! Is it an idea to show a piece of the next book which is outside the viewport of the row? That makes ik more clear it's horizontally scrollable (at leas on my iPhone 8).
Mike Harley, Goblin Herder wrote on 7 January 2021:
Excellent write up!
Dave Rupert wrote on 7 January 2021:
Yay, Bookshelves!!
Hidde wrote on 7 January 2021:
this stopped me too until now 😅, was surprised how easy it was to obtain the data
JulieG wrote on 7 January 2021:
This looks great! I want to do something similar but have been putting it off for ages because I didn't realise you could export the data from Goodreads.
Ymar wrote on 7 January 2021:
Looks awesome, definitely giving this a try after I figured out a way to export and import my Spotify playlists.
Max Böck wrote on 7 January 2021:
Great example of how to own your data. And beautifully done as well! #IndieWeb
Sia Karamalegos wrote on 7 January 2021:
Cool! Do you plan to only use your site in the future or to import from Goodreads again periodically?
Hidde wrote on 7 January 2021:
I think I'll probably regularly add the data manually
Dan Denney wrote on 7 January 2021:
Awesome walkthrough: How I turned my Goodreads data into a self-hosted website with Eleventy hiddedevries.nl/en/blog/2021-0… * I've struggled a bit with the API and am choosing my own images, so I may swap to skipping the API as well
Marty McGuire wrote on 7 January 2021:
Nick Lewis wrote on 12 January 2021:
Very neat!
Beko Pharm wrote on 16 January 2021:

Hm… exporting Goodreads data to display on the own website. Sounds like a good idea. I mean I never did use Goodreads myself but I know many others did: https://hiddedevries.nl/en/blog/2021-01-04-how-i-turned-my-goodreads-data-into-a-self-hosted-website-with-eleventy

Tracy Durnell wrote on 18 February 2021:

This page inspired by Hidde de Vries and Dave Rupert.

Alis wrote on 6 March 2021:
Tracy Durnell wrote on 11 May 2021:

Books Read in 2021

Running total as of 5/10/2021: 47
See my 2021 TBR on Goodreads.
Presented in reverse order. Links go to my review / notes. * indicates re-reads
👍 = liked a lot 👍👍 = loved (not equivalent to a star rating – an enjoyment / value, not quality, assessment)

Currently Reading

I like to have lots of books going at once, and will sometimes take months to read through books that may benefit from spacing out the reading.

Read in May

Read in April (12)

Read in March (11)

Read in February (10)

Read in January (9)

Did Not Finish

I quit a lot of books. This is nothing against these books, they just weren’t working for me at the time I tried to read them. I usually try to give them to about 20% to grab me, but I’ll sometimes quit books earlier or later. I’m just going to include books that I don’t think I’ll come back to here, others will just return to my TBR list.

  • Wild Rain by Beverly Jenkins – just didn’t get into it
  • This One Wild and Precious Life by Sarah Wilson – kind of judgy
  • The Art of Taking It Easy by Dr. Brian King – nothing new in the first 20%, humor didn’t work for me
  • Creative Quest by Questlove – some interesting thoughts but too name-droppy for me
  • Wildwood by Colin Meloy – too young for my taste
  • Phoenix Extravagant by Yoon Ha Lee – couldn’t get into it
  • Finna by Nino Cipri – the characters’ disagreement was frustrating
  • Spacer’s Cinderella by Adria Rose – didn’t like the meet-cute
  • Breath by James Nestor – I’m skeptical of the causation here and that there aren’t other causes like exercise and diet
  • The Midnight Bargain by C.L. Polk – too YA for my taste
  • Welcome to the Goddamn Ice Cube by Blair Braverman – upsetting story at start
  • Let’s Explore Diabetes with Owls by David Sedaris – not feeling it
  • The Idiot Girl’s Action Adventure Club by Laurie Notaro – not my humor
  • Underland by Robert Macfarlane – realized I am more claustrophobic than I thought
  • Made to Kill by Adam Christopher – didn’t like the writing style
  • Dear Girls by Ali Wong – not my humor
  • The Bedwetter by Sarah Silverman – not my humor
  • Pleasure Activism by adrienne maree brown – didn’t like approach to book
  • Lord Despair by Jane Sydney Bailey – pacing felt off
  • He’s No Prince Charming by Elle Daniels – didn’t like the premise
  • Scoundrel by Zoe Archer – consent issues

This page inspired by Hidde de Vries and Dave Rupert.

Tracy Durnell wrote on 14 May 2021:

Books Read in 2021

Running total as of 5/13/2021: 48
See my 2021 TBR on Goodreads.
Presented in reverse order. Links go to my review / notes. * indicates re-reads
👍 = liked a lot 👍👍 = loved (not equivalent to a star rating – an enjoyment / value, not quality, assessment)

Currently Reading

I like to have lots of books going at once, and will sometimes take months to read through books that may benefit from spacing out the reading.

Read in May

Read in April (12)

Read in March (11)

Read in February (10)

Read in January (9)

Did Not Finish

I quit a lot of books. This is nothing against these books, they just weren’t working for me at the time I tried to read them. I usually try to give them to about 20% to grab me, but I’ll sometimes quit books earlier or later. I’m just going to include books that I don’t think I’ll come back to here, others will just return to my TBR list.

  • Cemetery Boys by Aiden Thomas – too YA for me
  • The 99% Invisible City by Roman Mars – interesting but not well-served by a Kindle format – might revisit in paper format
  • The Ultimate Pi Day Party by Jackie Lau – writing didn’t grab me
  • Practical Permaculture by Jessi Bloom – I’m less interested in this than I thought i would be
  • Wintering by Katherine May – too stressful for me right now, I was worried the husband was going to die of an infection and I couldn’t go there
  • Wild Rain by Beverly Jenkins – just didn’t get into it
  • This One Wild and Precious Life by Sarah Wilson – kind of judgy
  • The Art of Taking It Easy by Dr. Brian King – nothing new in the first 20%, humor didn’t work for me
  • Creative Quest by Questlove – some interesting thoughts but too name-droppy for me
  • Wildwood by Colin Meloy – too young for my taste
  • Phoenix Extravagant by Yoon Ha Lee – couldn’t get into it
  • Finna by Nino Cipri – the characters’ disagreement was frustrating
  • Spacer’s Cinderella by Adria Rose – didn’t like the meet-cute
  • Breath by James Nestor – I’m skeptical of the causation here and that there aren’t other causes like exercise and diet
  • The Midnight Bargain by C.L. Polk – too YA for my taste
  • Welcome to the Goddamn Ice Cube by Blair Braverman – upsetting story at start
  • Let’s Explore Diabetes with Owls by David Sedaris – not feeling it
  • The Idiot Girl’s Action Adventure Club by Laurie Notaro – not my humor
  • Underland by Robert Macfarlane – realized I am more claustrophobic than I thought
  • Made to Kill by Adam Christopher – didn’t like the writing style
  • Dear Girls by Ali Wong – not my humor
  • The Bedwetter by Sarah Silverman – not my humor
  • Pleasure Activism by adrienne maree brown – didn’t like approach to book
  • Lord Despair by Jane Sydney Bailey – pacing felt off
  • He’s No Prince Charming by Elle Daniels – didn’t like the premise
  • Scoundrel by Zoe Archer – consent issues

This page inspired by Hidde de Vries and Dave Rupert.