My bookmarks were a disaster. I don't mean "a little disorganized." I mean full-blown digital hoarding across four browsers, three devices, a Raindrop.io account with 800 unsorted items, a Notion database I stopped updating in 2024, a Telegram chat with myself called "Links," and approximately two hundred Chrome tabs I was too afraid to close because one of them was definitely important. I just couldn't remember which one.
I'd tried every bookmark manager on the planet. Raindrop, Pocket, Instapaper, browser bookmarks, shared Apple Notes, a Slack channel with myself. They all worked for about a week before I stopped categorizing things and started dumping everything into a folder called "Unsorted" that I would absolutely never sort. The problem was never the tool. The problem was me. I will never manually tag a link. It's boring, I'll skip it, and in three months I'll have 500 items in digital purgatory.
The best system is the one that works without you. If it requires discipline to maintain, it's already failed.
The Problem, Actually Defined
Once I stopped blaming the tools and started looking at my actual behavior, the problem became obvious. I had three friction points:
- Saving was easy, organizing was not. Every app makes it trivial to save a link. None of them make categorization effortless. So I'd save and skip the organizing step every single time.
- Everything lived in different places. Work links in one app, design inspiration in another, articles to read in a third. No single place to search everything.
- Finding things later was impossible. I'd remember reading something about "that CSS grid trick" but have no idea which of my six bookmark graveyards it was buried in.
What I wanted was dead simple: I send a URL somewhere, and it handles everything else. Fetch the page title, figure out what category it belongs in, and file it in Raindrop.io where I can actually find it later. No tagging. No folders to choose. No decisions on my end. Just throw a URL at it and walk away.
The Architecture
The solution has three moving parts, each one simple on its own:
- A Cloudflare Worker — receives the URL and orchestrates everything
- Metadata extraction — pulls the title, description, and Open Graph data from the page
- Raindrop.io API — saves the bookmark to the right collection with auto-generated tags
The categorization logic doesn't use AI. I initially planned to use Claude to classify each link, but it turned out that simple pattern matching on URLs and meta tags was more than good enough — and way faster. A link from github.com is Development. A link with "figma" or "design" in the title is Design. A YouTube URL is Video. It's not glamorous, but it's right about 90% of the time, and the remaining 10% I genuinely don't care about.
You don't need AI for everything. Sometimes a dozen if-statements will outperform a language model — they're faster, cheaper, and you can debug them by reading the code. Save the AI for problems that actually need it.
Building It With Claude Code
I didn't write this Worker by hand. I described what I wanted to Claude Code and we built it through conversation. The first version took about twenty minutes. It received a URL, fetched the HTML, pulled the <title> tag, and saved it to Raindrop. Bare minimum, but it worked.
Then we iterated. "What if the page doesn't have a title tag?" "What about paywalled sites that return a login page?" "Can you add Open Graph image support?" Each question became a small improvement. After about two hours of back-and-forth, I had something I actually wanted to use every day.
Here's the core of the Worker:
export default {
async fetch(request, env) {
const { url } = await request.json();
// 1. Fetch the page and extract metadata
const meta = await extractMetadata(url);
// 2. Categorize based on URL patterns + meta
const collection = categorize(url, meta);
// 3. Save to Raindrop.io
const bookmark = await saveToRaindrop({
link: url,
title: meta.title,
excerpt: meta.description,
collection: collection,
tags: generateTags(url, meta),
}, env.RAINDROP_TOKEN);
return Response.json({
status: "saved",
title: meta.title,
collection: collection.name,
});
},
};
The Categorization Logic
The categorize function is the heart of the system. It looks at three things: the URL domain, the URL path, and keywords in the page title. Here's a simplified version:
function categorize(url, meta) {
const domain = new URL(url).hostname;
const title = (meta.title || "").toLowerCase();
// Domain-based rules
const domainMap = {
"github.com": "Development",
"stackoverflow.com": "Development",
"dribbble.com": "Design",
"figma.com": "Design",
"youtube.com": "Video",
"arxiv.org": "Research",
"news.ycombinator.com": "Tech News",
};
if (domainMap[domain]) {
return collections[domainMap[domain]];
}
// Keyword-based fallback
const keywords = {
Design: ["design", "figma", "ui", "ux", "css"],
Development: ["api", "code", "deploy", "git"],
AI: ["ai", "llm", "gpt", "claude", "model"],
Writing: ["writing", "blog", "essay", "prose"],
Tools: ["app", "tool", "software", "saas"],
};
for (const [cat, words] of Object.entries(keywords)) {
if (words.some(w => title.includes(w))) {
return collections[cat];
}
}
return collections["Inbox"];
}
Is it sophisticated? No. Does it work? Remarkably well. The domain matching alone covers about 60% of my bookmarks. The keyword fallback catches another 30%. The remaining 10% land in "Inbox" where I can glance at them once a week and drag them somewhere — but honestly, I rarely bother. If the system got it wrong, it's usually close enough that I'd find it through search anyway.
Talking to Raindrop's API
Raindrop.io has a clean, well-documented REST API. You authenticate with an OAuth token, and creating a bookmark is a single POST request. The API also supports collections (their word for folders) and tags, which made the automatic categorization straightforward.
async function saveToRaindrop(bookmark, token) {
const response = await fetch(
"https://api.raindrop.io/rest/v1/raindrop", {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
link: bookmark.link,
title: bookmark.title,
excerpt: bookmark.excerpt,
collection: { "$id": bookmark.collection.id },
tags: bookmark.tags,
}),
});
return response.json();
}
The best APIs are the ones that do exactly what the documentation says they'll do. Raindrop's API is one of those rare, delightful ones.
The Aha Moment
The moment this went from "cool side project" to "I can't live without this" was about a week in. I was reading an article about Cloudflare's new Workers AI features. Without thinking, I hit Share, tapped my shortcut, and saw the notification: "Saved to AI." Two seconds, no decisions, correctly categorized.
Then I realized I'd been doing this unconsciously all week. I'd saved maybe 40 links without once thinking about where they should go. When I opened Raindrop later that evening, everything was neatly organized across my collections. Design links with design links. Dev articles with dev articles. YouTube videos in their own section. It felt like having a personal librarian who silently files everything while you browse.
That's when I knew the system worked. Not because the code was clever — it's barely 200 lines — but because I'd stopped thinking about it entirely. The best tools are the ones you forget you're using.
The Numbers
Four months in, here's where things stand:
- 1,247 bookmarks saved and categorized automatically
- 92% accuracy on categorization (I spot-checked 100 random entries)
- Zero maintenance since the initial deploy
- ~1.8 seconds average response time from tap to confirmation
- $0 hosting cost — Cloudflare Workers free tier handles everything
I've actually gone back and found things I saved. That's never happened before with any bookmark system. The trick wasn't building a better bookmark manager. It was removing every single point of friction that made me not use the last dozen bookmark managers I tried.
What I'd Add Next
If I rebuild this tomorrow, I'd add two things. First, automatic summarization — not just the meta description, but a two-sentence summary of what the page is actually about, so I can search by concept instead of just title keywords. Second, a weekly digest that emails me the five most interesting links I saved that week, because I save far more than I revisit.
But honestly, even without those additions, this is the most useful thing I've built. Two hundred lines of JavaScript, a free Cloudflare Worker, and an API token solved a problem I'd been fighting for years. Sometimes the best project isn't the ambitious one. It's the small, boring one that quietly changes your daily life.