Yuvaraj Vodiboina
All work
(11)Case studyChrome extension

Notilo

A web highlighter I built and published: notes in six colours, anchored to the exact words and kept on your device. It’s no longer live.

Platform
Chrome extension
When
May to Aug 2025
Role
Sole developer
Last version
3.2.5, 20 Mar 2026
Status
No longer live
(01)

How it works

4 steps
  1. 01

    Select any text

    On almost any website.

    Open larger: Highlight. Note. Remember.
  2. 02

    Tap the floating plus

    Make a highlight, and attach a note right next to the text.

    Open larger: Notes and highlights side by side
  3. 03

    Colour and categorise

    Six colours and six categories, changeable any time.

  4. 04

    Search and export

    Filter every note on the page, or download them as a text file.

    Open larger: Search your notes on any page
(02)

The problem

I spent two hours annotating a research paper, the browser cleared the session, and all of it was gone. The highlighter extensions I tried were heavy, needed an account, or sent my data somewhere.

(03)

What I built

Highlights anchored to text ranges with the Selection and Range APIs, so they survive re-renders and come back when you revisit the page. It had notes in six colours and six categories, in-page search, and export to a text file. Everything stayed in local storage, with no account and no sync.

Hard partRe-attaching a highlight that spans several DOM nodes after the page re-renders, or when you come back days later.

(04)

Under the hood

  1. 01Selection APIWhat you picked
  2. 02Range APIAnchored to the exact words
  3. 03chrome.storagePer page, on your device
  4. 04MutationObserverPuts highlights back as the page changes
(05)

Decisions

  1. 01

    One storage key per URL

    A simple key-value lookup, scoped to the exact page, that works offline.

    Trade-offQuery strings and hashes create separate sets of highlights, which can be confusing on single-page apps.

  2. 02

    MutationObserver instead of polling

    It catches late-loading text as it appears and costs nothing while the page is idle.

    Trade-offIt has to be disconnected carefully to avoid memory leaks.

(06)

A bug I remember

Highlights on the wrong word

What it did
Restored highlights landed on the wrong occurrence of a word, one or two along.
Why
Restoring matched by the text itself, and “important” appears six times in most articles. It reliably found the wrong one.
The fix
Save the selection’s character offset within the page’s text, and restore it from the text node that owns that exact range. Text is ambiguous; position isn’t.
(07)

What I tried first

  • The CSS Custom Highlight API

    ::highlight is the right long-term answer and was the first thing I tried, but Safari and older versions of Chrome didn’t support it. Wrapping ranges in the DOM runs everywhere.

  • Cloud sync with accounts

    It was planned for version 2, until I wrote the privacy policy: every URL you visit, and your notes, uploaded. Local-only was the product decision.

(08)

What I learned

  • A selection can span dozens of elements. Re-wrapping it without breaking the layout takes careful node splitting.
  • chrome.storage.local has limits. Pages with heavy annotation needed LRU eviction of old highlight sets.
(09)

Timeline

  1. Built and published

    Highlights in six colours, notes, in-page search and export.

  2. 3.2.5

    Highlights read better in all six colours, search on a page is faster, and exports are cleaner.

  3. No longer live

    It stays here, and on codehorizon.in, as a record of what I built.

(10)

Built with

JavaScriptManifest V3Selection APIRange APIMutationObserver

Notilo is no longer on the Chrome Web Store.

Next12 of 16Research project CourseRecommendationEngine A machine-learning system that recommends online courses from what learners like you went on to take, served through a Flask API.Read the case study