Save things you want to learn later.
Keeper is a small Chrome extension built with Manifest V3, plain HTML, plain CSS, and plain JavaScript. It is designed to help you quickly save terms, concepts, tools, and topics while browsing, then come back to them later in a simple popup list.
The project is intentionally beginner-friendly:
- no frameworks
- no backend
- no database
- no build tools
- no external APIs
- local-only storage with
chrome.storage.local
Keeper currently supports:
- save selected text from the popup
- save manual text when nothing is selected
- save selected text from the right-click context menu
- save selected text with a keyboard shortcut
- save the current page title
- save the current page URL
- save an optional note
- save one optional tag
- store data locally in the browser
- show saved items in the popup
- filter items by status
- sort items in different ways
- mark items as learned
- delete items
- open the original saved page
- jump close to the selected text when a text-fragment URL is available
- copy the original source URL
- export saved items to JSON
- import saved items from JSON
Keeper has two main parts:
- a popup UI
- a background service worker
The popup handles:
- manual saving
- selected text capture when the popup opens
- rendering saved items
- filtering
- sorting
- export and import
- item actions like learned, delete, open, and copy URL
The background service worker handles:
- creating the right-click context menu
- saving directly from the context menu
- handling the keyboard shortcut
This split is important because the popup is only open when the user clicks the extension, but the context menu and keyboard shortcut must work even when the popup is closed.
Keeper/
├─ background.js
├─ manifest.json
├─ popup.html
├─ popup.css
├─ popup.js
└─ README.md
This is the main Chrome extension configuration file.
It tells Chrome:
- this extension uses Manifest V3
- the extension name and description
- which permissions are needed
- which popup opens from the toolbar icon
- which background service worker runs
- which keyboard shortcut command exists
This is the service worker.
It handles background-only tasks:
- creating the
Save to Keepercontext menu - clearing and recreating the menu during reloads to avoid duplicate development issues
- handling right-click saves from selected text
- handling the quick-save keyboard shortcut
- writing saved items to
chrome.storage.local
This is the popup layout.
It includes:
- the term/topic input
- the note field
- the tag field
- the current page info
- the save button
- the filter tabs
- the sort control
- the export button
- the import button
- the saved items list
This file styles the popup.
It keeps the UI:
- compact
- readable
- simple
- lightweight
This is the main popup logic file.
It handles:
- reading the active tab
- reading selected text from the page
- creating new items
- normalizing older stored items
- rendering cards
- showing hostnames
- filtering
- sorting
- marking items as learned
- deleting items
- opening source pages
- opening jump-to-text links
- copying URLs
- exporting JSON
- importing JSON safely
Keeper keeps each item in local storage using this shape:
{
id: "unique-id",
text: "Saved text",
note: "Optional note",
tag: "Optional tag",
pageTitle: "Page title",
pageUrl: "Original page URL",
sourceUrl: "Original page URL",
jumpUrl: "Optional text-fragment URL",
status: "saved",
createdAt: "ISO timestamp"
}-
idUnique identifier for the item. -
textThe main term, topic, or selected text the user saved. -
noteOptional note written by the user. Defaults to an empty string. -
tagOne optional simple tag string. Defaults to an empty string. -
pageTitleThe title of the page where the item was saved from. -
pageUrlThe original page URL. -
sourceUrlThe original source page URL used for opening the page again. -
jumpUrlA text-fragment URL used to jump near the originally selected text when possible. -
statusEithersavedorlearned. -
createdAtThe timestamp when the item was created.
Keeper keeps permissions minimal for the features it supports.
-
storageRequired to save and read items fromchrome.storage.local. -
contextMenusRequired to add theSave to Keeperright-click menu item. -
tabsRequired so the background service worker can read the active tab title and URL for quick save. -
activeTabRequired for temporary access to the current active page after a user action. -
scriptingRequired to read selected text from the active page.
When the popup opens:
- Keeper reads the active tab
- Keeper gets the page title and URL
- Keeper tries to read the currently selected text
- If text is selected, it auto-fills the text input
- If no text is selected, the user can type manually
When the user clicks Save item:
- Keeper validates that the main text field is not empty
- It creates an item object
- It stores that item in
chrome.storage.local - It re-renders the list in the popup
Keeper adds a context menu item named:
Save to Keeper
This menu item appears when:
- the user selects text on a normal webpage
- the user right-clicks the selection
When clicked, Keeper saves immediately:
- selected text
- empty note
- empty tag
- page title
- page URL
- default status of
saved - timestamp
If no text is selected, Keeper does not save a blank item.
The popup cannot handle right-click saves reliably because it is usually closed.
In Manifest V3, context menu creation and click handling belong in the background service worker. That is why background.js exists.
Keeper registers a quick-save command through Chrome commands.
Default shortcut:
- Windows/Linux:
Ctrl+Shift+K - macOS:
Command+Shift+K
You can change it here:
chrome://extensions/shortcuts
When triggered:
- Keeper finds the active tab
- Keeper reads the current selection from the page
- If selected text exists, it saves it immediately
- If nothing is selected, it skips saving
- Chrome shortcuts can conflict with browser shortcuts
- Chrome shortcuts can conflict with operating system shortcuts
- The shortcut may not work on
chrome://pages - The shortcut may not work on some restricted pages
- If Chrome blocks page scripting, Keeper cannot read the selection
- No selection means no save
Keeper supports one simple optional tag per item.
How it works:
- the popup includes a
Tagfield - the tag is stored as a plain string
- the saved card shows the tag only if it exists
- right-click save and keyboard quick save use an empty string as the default tag
This stays intentionally simple. There is no multi-tag support yet.
Keeper supports these popup filters:
AllTo LearnLearned
How they work:
Allshows every itemTo Learnshows items with statussavedLearnedshows items with statuslearned
The popup updates the list immediately when a filter is clicked. It does not reload the extension.
Keeper supports these sort options:
Newest firstOldest firstA-ZLearned last
-
Newest firstNewercreatedAtvalues come first. -
Oldest firstOldercreatedAtvalues come first. -
A-ZSorts by the savedtextfield alphabetically. -
Learned lastKeepssaveditems first and placeslearneditems after them. Inside each group, newer items stay first.
In the saved items list, Keeper shows a clean hostname instead of the full raw URL.
Example:
- shown in popup:
developer.chrome.com - stored in data: full source URL remains unchanged
This keeps the popup compact while still preserving the full URL for:
Open PageJump to TextCopy URL
Each saved item can support the following actions:
-
Open PageOpens the original page URL. -
Jump to TextOpens the text-fragment URL when available. -
Copy URLCopies the original source URL. -
Mark learnedChanges the status fromsavedtolearned. -
DeleteRemoves the item from storage.
Keeper tries to save a text-fragment URL when selected text exists on an http or https page.
That means Keeper stores:
- the original source page URL
- an optional jump URL that points near the selected text
Open Pagealways opens the normal pageJump to Textopens the text-fragment link- if there was no valid selected text, no jump link is saved
- works best on normal
httpandhttpspages - some sites may ignore text fragments
- some pages may re-render in ways that break text matching
chrome://pages, extension pages, PDFs, and some apps may not support this behavior
Keeper can export all saved data as a JSON file.
How export works:
- Click
Export - Keeper serializes all saved items
- The browser downloads a
.jsonfile
The export uses only native browser APIs:
BlobURL.createObjectURL- a temporary download link
Keeper can import saved data from a JSON file.
How import works:
- Click
Import - Choose a
.jsonfile - Keeper reads the file
- Keeper parses the JSON
- Keeper validates each item enough to avoid crashing
- Keeper merges valid items into storage
Keeper accepts:
- a JSON array of items
- an object with an
itemsarray
Keeper keeps validation intentionally simple:
- the imported value must contain an array of items
- each item must be an object
- each item must have a non-empty
textfield - invalid dates are replaced with the current time
- invalid status values fall back to
saved - missing note/tag/page title values fall back to simple defaults
- invalid items are skipped instead of crashing the popup
Keeper avoids duplicates using this practical rule:
- skip the item if its
idalready exists - also skip the item if
text,sourceUrl, andcreatedAtall match an existing item
This is simple, easy to understand, and helps avoid duplicate imports when the same file is imported again.
Keeper includes a light normalization step for older saved items.
This helps when the stored shape changed slightly over time, for example:
- older items using
pageUrlwithoutsourceUrl - older items with a text-fragment URL stored in
pageUrl - older items with no
tag
The popup normalizes those items before rendering so older data still works.
- Open Chrome
- Go to
chrome://extensions - Turn on
Developer mode - Click
Load unpacked - Select the
Keeperproject folder - Pin the extension if you want quick access
If the extension is already loaded and you changed the code:
- Go to
chrome://extensions - Find
Keeper - Click
Reload
- Open a web page
- Optionally select text
- Open the Keeper popup
- Review or edit the text field
- Add an optional note
- Add an optional tag
- Click
Save item
- Select text on a page
- Right-click
- Click
Save to Keeper
- Select text on a page
- Press the Keeper shortcut
In the popup you can:
- filter by
All,To Learn, andLearned - sort items
- open the saved page
- jump to the saved text when available
- copy the original URL
- mark an item as learned
- delete an item
- export your data
- import your data
During development reloads, context menu items can become stale or conflict with old IDs.
Keeper clears old menu items before recreating them so:
- duplicate IDs are avoided
- the menu is recreated cleanly after reload
- the right-click feature stays more reliable
The popup re-renders when storage changes so that saves coming from:
- the popup
- the context menu
- the keyboard shortcut
- imports
all appear consistently.
If a feature does not seem to work, check these first:
- make sure text is actually selected
- make sure the page is a normal webpage
- reload the extension in
chrome://extensions - try again on a regular
httpssite
- check
chrome://extensions/shortcuts - make sure the shortcut is not conflicting with another shortcut
- make sure text is selected
- avoid testing on restricted Chrome pages
- some sites ignore text fragments
- some pages change after load and the selected text cannot be found again
- try on a static normal webpage first
- make sure the file is valid JSON
- make sure it is either an array of items or an object with an
itemsarray - make sure the items contain non-empty
textfields
- search saved items
- stronger duplicate detection
- multi-tag support
- edit saved items
- pin or favorite items
- confirm before delete
- optional backup reminders