The Problem

Users must copy an image URL or download a file, open a search engine, paste the link, and click “search”. That workflow is slow and error‑prone, especially for journalists or investigators who need to verify many images quickly.

What This Does

search-by-image is a browser extension (Chrome, Edge, Safari, Opera, Firefox, Samsung, Apple stores) that adds a context‑menu command “Search by Image”. When invoked, the extension captures the target image, selects one or more of the 30+ configured reverse‑image services, and opens the corresponding search pages in new tabs.

The UI lives in several Vue entry points: src/action/App.vue, src/browse/App.vue, src/options/App.vue, and the background logic in src/background/main.js. Core utilities such as src/utils/app.js and src/utils/common.js provide helpers for storage, messaging, and script injection. The manifest files in src/assets/manifest/ define the permissions and context‑menu registration for each browser.

How It Is Wired

Startup – The extension boots from src/action/main.js (entry point init). It registers the context‑menu item, loads user settings from src/storage/storage.js, and prepares the UI (src/action/App.vue). init reaches 135 functions and is called from a single place, making it the primary bootstrap hub.

User action – Selecting “Search by Image” triggers onContextMenuItemClick in src/background/main.js. This function calls hasModule, executeScript, and sendMessage (the latter is the most widely used internal call, invoked from 22 locations). The background script injects src/content/main.js into the target page, which uses addViewFrame and showView to display a small overlay with engine toggles.

Engine dispatch – When the user clicks an engine button, src/utils/engines.js runs searchApi → engine‑specific module (e.g., src/engines/yandex.js). Each engine module defines search, showResults, and engineAccess. The call chain is typically:

onContextMenuItemClick → sendMessage → getEnabledEngines → setFileInputData → engine.search

sendMessage is the highest‑fan‑out function (22 callers), so changes here affect most workflows.

External effects – The only outbound interactions are:

  • Network: calls to the selected search engine URLs (via engine.search which opens a new tab).
  • Filesystem / cache: self.caches.open and browser.storage.session.get used in the startup path init → setup → getStartupState.

No other system commands or binaries are invoked.

Data flow – Persistent settings live in src/storage/storage.js, accessed through helpers in src/utils/app.js (getEnabledEngines, getSupportedEngines). src/utils/common.js provides executeScript and insertCSS, which are used throughout the background and content scripts.

Module hot spots

  • src/utils/app.js – 112 functions, called from 12 files, makes the network call and reads/writes storage.
  • src/utils/common.js – 59 functions, called from 10 files, handles script injection.
  • src/background/main.js – 66 functions, central to context‑menu handling.

There are no circular dependencies; the import graph contains a single edge from src/storage/init to src/storage/storage.

How To Use It

# Clone the repo
git clone https://github.com/moses-y/search-by-image
cd search-by-image

# Install dependencies
npm ci

# Build the extension (produces bundled assets in dist/)
npm run build   # defined in package.json scripts

# Load into a browser
# Chrome/Edge: chrome://extensions → Enable Developer Mode → Load unpacked → dist/
# Firefox: about:debugging → This Firefox → Load Temporary Add‑on → dist/manifest.json
# Safari: use Xcode project generated by the build (see README for details)

No additional environment variables or secret keys are required; the extension runs entirely client‑side.

Real‑World Use

A newsroom analyst right‑clicks an image on a social‑media post, selects “Search by Image”, and instantly opens tabs on Google Lens, TinEye, and Yandex. The analyst can compare results without leaving the article, saving minutes per image and reducing the risk of manual URL errors.

Code Health & Issues

  • High – Pin GitHub Actions.github/workflows/*.yml uses dessant/label-actions@v5. Replace the tag with a fixed SHA to prevent supply‑chain drift.
  • High – No test suite – 147 source files, zero test files. Add unit/integration tests for public entry points (src/action/main.js, src/background/main.js, etc.) and run them in CI.
  • Medium – Enable Dependabot – No dependency‑update bot configured; add .github/dependabot.yml.
  • Medium – Add dependency‑vulnerability scan – CI workflow lacks a scan step; integrate dependency-review-action or osv-scanner.
  • Medium – Checkout without persisting credentials.github/workflows/ci.yml should set persist-credentials: false.
  • Low – Job timeouts – CI jobs have no timeout-minutes; add reasonable limits.

Additional observations: the codebase contains several oversized files (src/background/main.js, src/utils/app.js, src/action/App.vue) and duplicated 6‑line blocks across many Vue components, which increase maintenance cost.

The Bottom Line

search-by-image delivers a functional, cross‑browser reverse‑image workflow with a clear modular split between UI, background, and engine adapters. The extension is usable out‑of‑the‑box but suffers from a lack of automated testing, oversized modules, and some CI hardening gaps. Teams that need quick image verification can adopt it, but should invest in refactoring the large files and adding a test suite before extensive customization.