Chrome Extension

UX Case Study

UX Case Study

Bookmark Previewer: Finding Saved Links Again

Bookmark Previewer: Finding Saved Links Again

Bookmark Previewer: Finding Saved Links Again

Bookmark Previewer: Finding Saved Links Again

A Chrome extension that keeps your real bookmark folders exactly as you built them, adds meaning-based search on top, and lets you see a site before you click it — designed, and shipped solo.

A Chrome extension that keeps your real bookmark folders exactly as you built them, adds meaning-based search on top, and lets you see a site before you click it — designed, and shipped solo.

Built as my first-ever Figma plugin, crafted with the precision of a senior UX designer, it’s made to solve real bilingual workflow pain points: broken alignment, lost styles, incorrect RTL flow, messy overrides, and manual fixes.

1. Problem

1. Problem

Folders didn't fail from a lack of effort. They failed because memory doesn't hold still.

Folders didn't fail from a lack of effort. They failed because memory doesn't hold still.

Folders didn't fail from a lack of effort. They failed because memory doesn't hold still.

I had a few hundred bookmarks and a folder structure I'd built myself — and I still couldn't find things in it. Not because I hadn't organized. Because organizing once isn't enough:

1
Taxonomy Drift

The category that made sense the day I saved something stops matching how I think about it weeks later.

1

Taxonomy Drift

The category that made sense the day I saved something stops matching how I think about it weeks later.

2
Keywords Search Fail

Chrome's bookmark search only matches the saved title or URL — useless when I can't recall the exact wording.

2

Keywords Search Fail

Chrome's bookmark search only matches the saved title or URL — useless when I can't recall the exact wording.

3
No Visual Memory Cue

A bookmark is a line of text. Recognition — the fastest way people actually recall things — never gets a chance to kick in.

3

No Visual Memory Cue

A bookmark is a line of text. Recognition — the fastest way people actually recall things — never gets a chance to kick in.

The goal wasn't a better filing system. It was closing the gap between saving something and being able to find it again — without asking me to maintain more structure than I already wasn't maintaining.

2. Benchmarking the Field

2. Benchmarking the Field

Before designing anything, I looked at how bookmark and read-later tools actually handle this today:

Before designing anything, I looked at how bookmark and read-later tools actually handle this today:

Before designing anything, I looked at how bookmark and read-later tools actually handle this today:

competitve benchmarking table

The gap: Nothing combines zero added organizing effort, meaning-based search, real visual recall, and keeps your data on your own machine. Tools are either fully manual, or "smart" in exchange for sending your browsing history to a server.

3. The Solution

3. The Solution

Trust the folders you already built. Add the parts folders can't do.

Trust the folders you already built. Add the parts folders can't do.

Trust the folders you already built. Add the parts folders can't do.

Groups mirror your real Chrome folders — exactly.

No new taxonomy to learn or maintain. Rename, drag a bookmark into another group, or delete one, and it happens through Chrome's own bookmarks API, so the tool can never drift from what's actually in your browser.

Groups mirror your real Chrome folders — exactly.

No new taxonomy to learn or maintain. Rename, drag a bookmark into another group, or delete one, and it happens through Chrome's own bookmarks API, so the tool can never drift from what's actually in your browser.

Search by meaning, not exact words.

A local embedding model runs on-device, so typing "inspiration site" surfaces the right bookmarks even if none of them contain that phrase.

Search by meaning, not exact words.

A local embedding model runs on-device, so typing "inspiration site" surfaces the right bookmarks even if none of them contain that phrase.

Search by meaning, not exact words.

A local embedding model runs on-device, so typing "inspiration site" surfaces the right bookmarks even if none of them contain that phrase.

See it before you click it.

Hovering a bookmark shows the live site in preview — with a fallback chain for the many sites that refuse to be framed (more on that below).

See it before you click it.

Hovering a bookmark shows the live site in preview — with a fallback chain for the many sites that refuse to be framed (more on that below).

See it before you click it.

Hovering a bookmark shows the live site in preview — with a fallback chain for the many sites that refuse to be framed (more on that below).

Fully Local

No account, no server, no per-query cost. Everything — metadata fetching, embedding, search — runs on-device.

Fully Local

No account, no server, no per-query cost. Everything — metadata fetching, embedding, search — runs on-device.

Fully Local

No account, no server, no per-query cost. Everything — metadata fetching, embedding, search — runs on-device.

4. The Design Process

4. The Design Process

The first idea was AI clustering. It was also wrong.

The first idea was AI clustering. It was also wrong.

The first idea was AI clustering. It was also wrong.

This is the part of the process worth showing in full, because the direction actually changed twice — once on the information architecture, once on the interaction design.

-> PIVOT 1 - INFORMATION ARCHITECTURE

-> PIVOT 1 - INFORMATION ARCHITECTURE

-> PIVOT 1 - INFORMATION ARCHITECTURE

AI-clustered groups → your real folders

AI-clustered groups → your real folders

V1 embedded every bookmark and grouped them with incremental nearest-centroid clustering — the "smart" part of the pitch. Run against my real, few-hundred-bookmark library, the clusters were technically coherent but felt arbitrary: sites I'd have filed together stayed apart, and the labels read as fragmented keyword soup rather than categories I'd trust. The AI's idea of "similar" didn't match my own mental model, and a tool that reorganizes your bookmarks in a way you don't trust is worse than one that does nothing. I dropped automatic clustering entirely and mirrored the real Chrome folder tree instead — moving the "smart" layer to where it could add value without asking me to trust a new structure: search.

before and after cluster methodology

-> PIVOT 2 - VISUAL DIRECTION:

-> PIVOT 2 - VISUAL DIRECTION:

-> PIVOT 2 - VISUAL DIRECTION:

Five directions explored before "liquid glass"

Five directions explored before "liquid glass"

Before committing to a UI, I sketched five distinct directions to compare structurally different ways to browse the same data:

Visual directions

Folder Explorer won for matching the new "mirror real folders" architecture, then converged toward a soft, translucent "liquid glass" aesthetic (frosted panels, a gradient canvas, pill-shaped nav). The folder icon itself went through several passes before landing on a version legible at both card and sidebar-row size:

folder icon direction

-> PIVOT 3 - THE PREVIEW IN 5 ROUNDS:

-> PIVOT 3 - THE PREVIEW IN 5 ROUNDS:

-> PIVOT 3 - THE PREVIEW IN 5 ROUNDS:

Hovering a bookmark is easy. Getting a real preview to render is not.

Hovering a bookmark is easy. Getting a real preview to render is not.

This ended up being the most technically resilient feature in the tool, purely because the naive version failed on contact with real sites:

  1. A plain <iframe> — blocked immediately by X-Frame-Options / CSP on most real "inspiration" sites (Dribbble, Behance, Awwwards — exactly the sites this tool is meant to help with).

<iframe src="https://dribbble.com"></iframe>
✕ Refused to display 'dribbble.com' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'

<iframe src="https://dribbble.com"></iframe>
✕ Refused to display 'dribbble.com' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'

<iframe src="https://dribbble.com"></iframe>
✕ Refused to display 'dribbble.com' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'

<iframe src="https://dribbble.com"></iframe>
✕ Refused to display 'dribbble.com' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'

  1. Scoped response-header stripping via declarativeNetRequest, restricted to sub-frame requests initiated by the extension's own dashboard — enables the preview without weakening framing protection anywhere else in normal browsing.

responseHeaders: [
  { header: "x-frame-options", operation: "remove" },
  { header: "content-security-policy", operation: "remove" }
],
condition: { resourceTypes: ["sub_frame"],
  initiatorDomains: [chrome.runtime.id] }
responseHeaders: [
  { header: "x-frame-options", operation: "remove" },
  { header: "content-security-policy", operation: "remove" }
],
condition: { resourceTypes: ["sub_frame"],
  initiatorDomains: [chrome.runtime.id] }
responseHeaders: [
  { header: "x-frame-options", operation: "remove" },
  { header: "content-security-policy", operation: "remove" }
],
condition: { resourceTypes: ["sub_frame"],
  initiatorDomains: [chrome.runtime.id] }
responseHeaders: [
  { header: "x-frame-options", operation: "remove" },
  { header: "content-security-policy", operation: "remove" }
],
condition: { resourceTypes: ["sub_frame"],
  initiatorDomains: [chrome.runtime.id] }
  1. Broadened iframe sandbox permissions — the first pass was so restrictive that modern JS-heavy sites threw during initialization and rendered nothing, even once the headers were fixed.

<iframe sandbox="allow-same-origin allow-scripts allow-forms
  allow-popups allow-popups-to-escape-sandbox allow-modals">
<iframe sandbox="allow-same-origin allow-scripts allow-forms
  allow-popups allow-popups-to-escape-sandbox allow-modals">
<iframe sandbox="allow-same-origin allow-scripts allow-forms
  allow-popups allow-popups-to-escape-sandbox allow-modals">
<iframe sandbox="allow-same-origin allow-scripts allow-forms
  allow-popups allow-popups-to-escape-sandbox allow-modals">
  1. Spoofed Sec-Fetch-* request headers — some sites don't block via a header at all; they detect framing server-side and quietly serve different content instead.

<iframe sandbox="allow-same-origin allow-scripts allow-forms
  allow-popups allow-popups-to-escape-sandbox allow-modals">
<iframe sandbox="allow-same-origin allow-scripts allow-forms
  allow-popups allow-popups-to-escape-sandbox allow-modals">
<iframe sandbox="allow-same-origin allow-scripts allow-forms
  allow-popups allow-popups-to-escape-sandbox allow-modals">
<iframe sandbox="allow-same-origin allow-scripts allow-forms
  allow-popups allow-popups-to-escape-sandbox allow-modals">
  1. A graceful floor: for the sites that still can't be framed, the fallback card leads with the site's own Open Graph social-preview image instead of a bare favicon — so even a "blocked" result still looks like the real site.

preview = ogImage ?? faviconUrl ?? null
// card leads with ogImage first — never a bare favicon alone
preview = ogImage ?? faviconUrl ?? null
// card leads with ogImage first — never a bare favicon alone
preview = ogImage ?? faviconUrl ?? null
// card leads with ogImage first — never a bare favicon alone
preview = ogImage ?? faviconUrl ?? null
// card leads with ogImage first — never a bare favicon alone
  1. Under the Hood

  1. Under the Hood

  1. Under the Hood

  1. Under the Hood

The technical decisions that made the UX possible.

The technical decisions that made the UX possible.

The technical decisions that made the UX possible.

Local embeddings, off the main worker

A small on-device model (transformers.js) runs in a Chrome "offscreen document," not the background service worker — keeps the always-on worker light and avoids WASM/service-worker lifecycle conflicts.

Local embeddings, off the main worker

A small on-device model (transformers.js) runs in a Chrome "offscreen document," not the background service worker — keeps the always-on worker light and avoids WASM/service-worker lifecycle conflicts.

Local embeddings, off the main worker

A small on-device model (transformers.js) runs in a Chrome "offscreen document," not the background service worker — keeps the always-on worker light and avoids WASM/service-worker lifecycle conflicts.

Full-tree resync over event patching

Every bookmark or folder change triggers a debounced re-walk of the whole Chrome bookmark tree, reconciled against storage — correct by construction for renames, moves and even a whole folder being deleted, instead of hand-rolled logic per event type.

Full-tree resync over event patching

Every bookmark or folder change triggers a debounced re-walk of the whole Chrome bookmark tree, reconciled against storage — correct by construction for renames, moves and even a whole folder being deleted, instead of hand-rolled logic per event type.

A resumable, durable task queue

The fetch → embed pipeline is backed by an IndexedDB queue that survives a mid-item service-worker restart, so nothing is silently dropped or duplicated.

A resumable, durable task queue

The fetch → embed pipeline is backed by an IndexedDB queue that survives a mid-item service-worker restart, so nothing is silently dropped or duplicated.

A resumable, durable task queue

The fetch → embed pipeline is backed by an IndexedDB queue that survives a mid-item service-worker restart, so nothing is silently dropped or duplicated.

Scoped network rules, not global ones

declarativeNetRequest rules are scoped to requests initiated by the extension's own pages — the preview works without touching security headers anywhere else the user browses.

Scoped network rules, not global ones

declarativeNetRequest rules are scoped to requests initiated by the extension's own pages — the preview works without touching security headers anywhere else the user browses.

Scoped network rules, not global ones

declarativeNetRequest rules are scoped to requests initiated by the extension's own pages — the preview works without touching security headers anywhere else the user browses.

The browser stays the source of truth

IndexedDB stores only derived data — metadata, embeddings, per-folder color/emoji. Every structural change (rename, move, delete) goes through Chrome's real bookmarks API first, so the extension can't drift from what's actually in the browser.

The browser stays the source of truth

IndexedDB stores only derived data — metadata, embeddings, per-folder color/emoji. Every structural change (rename, move, delete) goes through Chrome's real bookmarks API first, so the extension can't drift from what's actually in the browser.

Zero external dependency

No account, no backend, no per-query API cost — the entire pipeline (fetch, embed, search) runs locally, once the embedding model is cached after first use.

Zero external dependency

No account, no backend, no per-query API cost — the entire pipeline (fetch, embed, search) runs locally, once the embedding model is cached after first use.

Zero external dependency

No account, no backend, no per-query API cost — the entire pipeline (fetch, embed, search) runs locally, once the embedding model is cached after first use.

6- Outcome & Reflection

6- Outcome & Reflection

6- Outcome & Reflection

The biggest UX win wasn't the AI feature. It was knowing where to not use one.

The biggest UX win wasn't the AI feature. It was knowing where to not use one.

The tool solves the problem it set out to solve: bookmarks stay organized the way I already think about them, and a meaning-based search catches what a keyword search never could. But the most transferable lesson came from the pivot, not the ship: an "AI-powered" feature isn't automatically better UX. The first version replaced the user's own structure with the model's guess at one, and it was worse — not because the clustering was technically bad, but because trust in your own organization is the actual product being protected. The fix wasn't a better model. It was moving intelligence to where the user has no existing mental model to compete with: search.

What's Next:

What's Next:

What's Next:

A real screenshot-capture fallback for the small remaining set of sites no header trick can unblock, and a nested-folder view in the dashboard for structures deeper than one level (currently flattened for simplicity).

Want

More Projects?

Want

More Projects?

Create a free website with Framer, the website builder loved by startups, designers and agencies.