<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andreas</title>
    <description>The latest articles on DEV Community by Andreas (@pulsekatt).</description>
    <link>https://dev.to/pulsekatt</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3973781%2F7011fca0-346c-4dec-8968-1fd7537966fd.jpg</url>
      <title>DEV Community: Andreas</title>
      <link>https://dev.to/pulsekatt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pulsekatt"/>
    <language>en</language>
    <item>
      <title>I built a free AI book-recommendation app — and the hardest part was staying under a 1,000/day API limit</title>
      <dc:creator>Andreas</dc:creator>
      <pubDate>Mon, 08 Jun 2026 09:09:13 +0000</pubDate>
      <link>https://dev.to/pulsekatt/i-built-a-free-ai-book-recommendation-app-and-the-hardest-part-was-staying-under-a-1000day-api-i7</link>
      <guid>https://dev.to/pulsekatt/i-built-a-free-ai-book-recommendation-app-and-the-hardest-part-was-staying-under-a-1000day-api-i7</guid>
      <description>&lt;p&gt;I kept finishing a book I loved and then having no idea what to read next. Goodreads-style recommendations always felt generic, so I built My Next Book: you add a few books you've loved, and it returns five tailored picks, each with a one-line reason for the match plus cover, genre and a real description.&lt;/p&gt;

&lt;p&gt;Live (no login, free): &lt;a href="https://mynextbook.io" rel="noopener noreferrer"&gt;https://mynextbook.io&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;React + Vite, deployed on Vercel&lt;/li&gt;
&lt;li&gt;Recommendations from Claude (Haiku) via a small serverless proxy, so the API key never touches the browser&lt;/li&gt;
&lt;li&gt;Book metadata (covers, genre, page count, publisher blurb) from the Google Books API — real data, not model guesses&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The actual hard part: the Google Books free tier
&lt;/h2&gt;

&lt;p&gt;Google Books gives you ~1,000 calls/day on the free tier. With search-as-you-type plus enriching every recommendation with a cover and metadata, I blew through that almost instantly in testing.&lt;/p&gt;

&lt;p&gt;What fixed it was layering caches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build-time bundled cache.&lt;/strong&gt; A curated list of ~440 popular titles, with cover URLs fetched once at build time by a script and baked straight into the bundle. These show up instantly on load with zero API calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Threshold-based search.&lt;/strong&gt; When a query has enough strong matches in that bundled cache, the app skips the Google API entirely and serves from the cache. The live API is only hit for searches the cache can't answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;localStorage caching.&lt;/strong&gt; Both search results and recommendation enrichment (covers/genre/description) are cached client-side with a TTL, so repeat lookups of the same book are free.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Net effect: most common searches now resolve with zero network calls, and the daily quota goes a very long way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd love feedback on
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Recommendation quality (does it actually "get" your taste?)&lt;/li&gt;
&lt;li&gt;Anything in the UX that feels off&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>showdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
