Add Books to Your Vault with Google Books and Claude
The Problem
Adding a book to my Obsidian vault meant opening Goodreads or Google Books in a browser, copying the title, author, ISBN, and cover URL, then pasting them into a template and fixing the formatting. I used the Obsidian Web Clipper for a while, which helped, but it still required switching contexts — open browser, find the right page, clip it, go back to Obsidian, clean up the result.
For something I do a few times a week, the friction was enough that I’d skip it. Books I was reading wouldn’t get notes until weeks later, if at all.
The Solution
A Claude Code skill that does the lookup and note creation in one step. Say /add-book Talking to Strangers by Malcolm Gladwell, and it searches Google Books, shows you the matches, asks a couple of questions (reading status, any context), and writes the note.
The architecture splits the work: a dumb script handles the API call, Claude handles the reasoning.
google-books-search.sh— a bash script that calls the Google Books API and pipes the response throughjqto extract only the fields that matter: title, authors, year, ISBN, cover URL, publisher, page count- Claude skill — parses the user’s natural language input, calls the script, presents results, and creates a properly formatted book note with wikilinked authors and frontmatter
How To
The search script
The script lives alongside the skill definition. It takes a query string, hits the Google Books API (no API key needed for basic searches), and returns clean JSON:
#!/usr/bin/env bash
set -euo pipefail
QUERY="${1:?Usage: google-books-search.sh \"query string\"}"
API_URL="https://www.googleapis.com/books/v1/volumes"
curl -s "${API_URL}?q=$(printf '%s' "$QUERY" | jq -sRr @uri)&maxResults=5" | jq '[
.items[]? | .volumeInfo | {
title: (.title + if .subtitle then ": " + .subtitle else "" end),
authors: (.authors // []),
year: (.publishedDate // "" | split("-")[0]),
isbn13: ([(.industryIdentifiers // [])[] | select(.type == "ISBN_13") | .identifier][0] // ""),
isbn10: ([(.industryIdentifiers // [])[] | select(.type == "ISBN_10") | .identifier][0] // ""),
cover: ((.imageLinks.thumbnail // "") | gsub("http:"; "https:") | gsub("zoom=1"; "zoom=3")),
publisher: (.publisher // ""),
pageCount: (.pageCount // 0)
}
]'The raw Google Books response is massive — descriptions, access info, sale info, preview links, maturity ratings. The jq filter reduces each result to about 8 fields. That’s the difference between sending thousands of tokens through Claude for parsing versus a few dozen.
The skill prompt
The skill prompt tells Claude how to handle the interaction:
- Parse the user’s input — split “by” to separate title from author, detect ISBNs
- Build the Google Books query (
intitle:,inauthor:,isbn:) - Run the script and show a numbered list of results
- Ask for reading status (To Read / Reading / Read) and optional context
- Create the note using the vault’s book template
The book template
The note frontmatter captures the metadata that matters for filtering and display:
---
Title: "Full Title Including Subtitle"
Author: "[Author Name](/obsidian/author-name/)"
year: 2025
Cover: "https://..."
isbn: "9781234567890"
date-created: 2026-03-12
Status: To Read
Rating:
tags:
- Type/book
read:
---Authors get wikilinked so they accumulate backlinks as you add more books. Rating is a bare number (not a string) so Obsidian’s Dataview can sort by it. The cover URL points to Google Books’ higher-resolution thumbnail.
What I Learned
jq as a token-saving layer. The Google Books API returns 15-20KB of JSON per query. After jq, it’s under 1KB. That’s not just faster — it means Claude doesn’t waste reasoning tokens parsing fields it’ll never use. Anytime a skill calls an external API, piping through jq first is worth considering.
Google Books API doesn’t require a key for reads. Basic volume searches work unauthenticated. You’ll hit rate limits eventually, but for adding a few books a day it’s a non-issue. The QuickAdd script I originally looked at required an API key in the plugin settings — unnecessary complexity for this use case.
Keep the script with the skill. I considered putting the script in my global ~/bin directory, but it’s single-purpose. Bundling it in the skill directory (.claude/skills/add-book/) keeps the skill self-contained and portable.
Caveats
- Google Books metadata isn’t always complete — some editions lack ISBNs or cover images. The skill falls back to OpenLibrary’s default cover when there’s no thumbnail.
- Multiple editions of the same book show up as separate results. You pick the one you want.
- No API key means you’re subject to anonymous rate limits — fine for personal use, not for batch-importing a library.