Skip to content

About

local web app for tracing where a photo appears on the internet. It uses Google Cloud Vision Web Detection to find exact-file matches, then enriches those matches with scraped page metadata, EXIF when available, and oldest-known archive dates from the Wayback Machine.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Reserve Image Search

A local web app for tracing where a photo appears on the internet.

Upload an image or paste a URL. The app calls Google Cloud Vision Web Detection to find exact-file matches, then enriches those matches with scraped page metadata, EXIF data, and oldest-known archive dates from the Wayback Machine.

The frontend shows the full pipeline step-by-step -- raw JSON, normalized candidates, ranking decisions, and errors -- so you can inspect every part of the trace, not just the final answer.


Architecture

                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                              β”‚               Reserve Image Search                 β”‚
                              β”‚                                                    β”‚
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                β”‚
  β”‚   Browser   β”‚             β”‚  β”‚ FastAPI  β”‚      β”‚   SQLite     β”‚                β”‚
  β”‚  React +    │──HTTP──────>β”‚  β”‚ Backend  β”‚<────>β”‚ backend/     β”‚                β”‚
  β”‚  Vite UI    β”‚<──JSON──────│  β”‚          β”‚      β”‚ photos.db    β”‚                β”‚
  β”‚  (port      β”‚             β”‚  β”‚ (port    β”‚      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β”‚
  β”‚   5173)     β”‚             β”‚  β”‚  8000)   β”‚                                      β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                β”‚
                              β”‚       β”‚            β”‚  uploads/    β”‚                β”‚
                              β”‚       β”‚            β”‚  (local      β”‚                β”‚
                              └───────┼────────────│   files)     β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           
                                      β”‚            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            
                                      β”‚                                          
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                       
                    β”‚                 β”‚                  β”‚                       
                    v                 v                  v                       
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                   
         β”‚ Google Cloud β”‚ β”‚  Metadata    β”‚ β”‚   Wayback    β”‚                   
         β”‚ Vision API   β”‚ β”‚  Scraper     β”‚ β”‚ Machine CDX  β”‚                   
         β”‚              β”‚ β”‚              β”‚ β”‚              β”‚                   
         β”‚ - full match β”‚ β”‚ - Open Graph β”‚ β”‚ - oldest     β”‚                   
         β”‚ - page match β”‚ β”‚ - Twitter    β”‚ β”‚   archive    β”‚                   
         β”‚ - web entity β”‚ β”‚ - JSON-LD    β”‚ β”‚   timestamp  β”‚                   
         β”‚ - labels     β”‚ β”‚ - EXIF       β”‚ β”‚              β”‚                   
         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜                   
                β”‚                β”‚                β”‚                            
                v                v                v                            
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                      
         β”‚              Ranking Engine                  β”‚                      
         β”‚                                              β”‚                      
         β”‚  Sorts by: Wayback > Publish > Modified >    β”‚                      
         β”‚  EXIF.  Prefers exact over partial matches.  β”‚                      
         β”‚  Selects best_source with metadata.          β”‚                      
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                      
                                                                          

Pipeline Stages

Each trace job runs through five stages. The frontend polls for status and shows each stage as it completes.

 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚                        Trace Pipeline                                       β”‚
 β”‚                                                                             β”‚
 β”‚  1. IMAGE SEARCH                                                            β”‚
 β”‚     β”‚  Send image to Google Cloud Vision Web Detection                      β”‚
 β”‚     β”‚  Optional: also query SerpAPI Google Lens                             β”‚
 β”‚     β”‚  Returns: exact matches, page candidates, web entities, labels        β”‚
 β”‚     v                                                                       β”‚
 β”‚  2. CANDIDATE SELECTION                                                     β”‚
 β”‚     β”‚  Filter and prioritize results                                        β”‚
 β”‚     β”‚  Keep fullMatchingImages as exact-file evidence                       β”‚
 β”‚     β”‚  Select up to 20 pages for scraping                                   β”‚
 β”‚     v                                                                       β”‚
 β”‚  3. METADATA SCRAPING                                                       β”‚
 β”‚     β”‚  Fetch candidate pages and extract metadata                           β”‚
 β”‚     β”‚  Sources: Open Graph, Twitter Card, JSON-LD,                          β”‚
 β”‚     β”‚           Dublin Core, HTML meta tags, EXIF, HTTP headers             β”‚
 β”‚     β”‚  Runs up to 6 concurrent workers                                      β”‚
 β”‚     v                                                                       β”‚
 β”‚  4. WAYBACK ENRICHMENT                                                      β”‚
 β”‚     β”‚  Query Wayback Machine CDX API for each result                        β”‚
 β”‚     β”‚  Find the oldest known archived snapshot                              β”‚
 β”‚     v                                                                       β”‚
 β”‚  5. RANKING                                                                 β”‚
 β”‚     β”‚  Sort results by oldest evidence                                      β”‚
 β”‚     β”‚  Prefer: Wayback > Publish Date > Modified Date > EXIF                β”‚
 β”‚     β”‚  Select best_source with full metadata                                β”‚
 β”‚     v                                                                       β”‚
 β”‚  DONE                                                                       β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Job Status Flow

 PENDING
   β”‚
   v
 PROCESSING_VISION
   β”‚
   v
 SELECTING_EXACT_MATCHES
   β”‚
   v
 SCRAPING_METADATA
   β”‚
   v
 CHECKING_WAYBACK
   β”‚
   v
 RANKING_RESULTS
   β”‚
   v
 COMPLETED          ERROR

Exact Match Rules

This app is intentionally conservative about what counts as a match:

 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚                                                                β”‚
 β”‚  fullMatchingImages         ->  EXACT image file evidence      β”‚
 β”‚  (same file hash)                                              β”‚
 β”‚                                                                β”‚
 β”‚  pagesWithMatchingImages    ->  CANDIDATE page evidence        β”‚
 β”‚  (may be context/embed)                                        β”‚
 β”‚     β”‚                                                          β”‚
 β”‚     β”œβ”€β”€ scraper confirms the exact image URL is on the page    β”‚
 β”‚     β”‚   -> upgraded to EXACT page                              β”‚
 β”‚     β”‚                                                          β”‚
 β”‚     └── cannot confirm                                         β”‚
 β”‚         -> stays as fallback candidate                         β”‚
 β”‚                                                                β”‚
 β”‚  visuallySimilarImages     ->  stored in raw JSON only         β”‚
 β”‚  (not used for ranking)                                        β”‚
 β”‚                                                                β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Repository Layout

photo-detector/
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ api/
β”‚   β”‚   β”‚   └── routes.py            # REST API endpoints
β”‚   β”‚   β”œβ”€β”€ db/
β”‚   β”‚   β”‚   β”œβ”€β”€ database.py          # SQLite connection setup
β”‚   β”‚   β”‚   └── models.py            # SQLAlchemy models (photo_jobs, bulk_jobs)
β”‚   β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”‚   β”œβ”€β”€ pipeline.py          # Main pipeline orchestrator
β”‚   β”‚   β”‚   β”œβ”€β”€ bulk_pipeline.py     # Bulk processing orchestrator
β”‚   β”‚   β”‚   β”œβ”€β”€ scraper.py           # Page metadata extraction
β”‚   β”‚   β”‚   β”œβ”€β”€ vision_client.py     # Google Vision API client
β”‚   β”‚   β”‚   β”œβ”€β”€ serpapi_client.py    # SerpAPI Google Lens client
β”‚   β”‚   β”‚   └── utils.py             # Helpers
β”‚   β”‚   └── main.py                  # FastAPI app entry point
β”‚   β”œβ”€β”€ uploads/                     # Uploaded image files (local)
β”‚   β”œβ”€β”€ photos.db                    # SQLite database
β”‚   β”œβ”€β”€ .env                         # Environment variables (API keys)
β”‚   └── requirements.txt             # Python dependencies
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   β”œβ”€β”€ UploadBox.tsx        # Single image upload / URL input
β”‚   β”‚   β”‚   β”œβ”€β”€ ResultsView.tsx      # Trace results with step timeline
β”‚   β”‚   β”‚   β”œβ”€β”€ BulkView.tsx         # Bulk job management
β”‚   β”‚   β”‚   └── BulkInput.tsx        # Bulk URL input form
β”‚   β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”‚   └── api.ts              # Frontend HTTP client (Axios)
β”‚   β”‚   β”œβ”€β”€ hooks/                   # Custom React hooks
β”‚   β”‚   β”œβ”€β”€ App.tsx                  # Main app component
β”‚   β”‚   └── main.tsx                 # React entry point
β”‚   β”œβ”€β”€ package.json                 # Node.js dependencies
β”‚   └── vite.config.ts              # Vite build config
β”œβ”€β”€ launcher.bat                     # One-click Windows launcher
└── README.md

What You Need To Run

Prerequisites

 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚  Required                                       β”‚
 β”‚                                                 β”‚
 β”‚  Python  3.12+     https://python.org           β”‚
 β”‚  Node.js 20+       https://nodejs.org           β”‚
 β”‚  Google Cloud project with Vision API enabled   β”‚
 β”‚    -> Get a service account key or API key      β”‚
 β”‚                                                 β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚  Optional                                       β”‚
 β”‚                                                 β”‚
 β”‚  SerpAPI account                                β”‚
 β”‚    -> Enables Google Lens as an additional      β”‚
 β”‚       search mode (serpapi / combined)          β”‚
 β”‚    -> https://serpapi.com                       β”‚
 β”‚                                                 β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Install

# Backend
cd backend
python -m venv .venv
.venv\Scripts\activate          # Windows
pip install -r requirements.txt

# Frontend
cd frontend
npm install

Configure

Create backend/.env:

# Required: Google Cloud Vision
GOOGLE_APPLICATION_CREDENTIALS=C:\path\to\service-account.json
# -- or --
GOOGLE_VISION_API_KEY=your_api_key_here

# Optional: SerpAPI (enables additional search mode)
SERPAPI_API_KEY=your_serpapi_key_here

Auth modes explained:

 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚  GOOGLE_APPLICATION_CREDENTIALS      β”‚
 β”‚  (Recommended)                       β”‚
 β”‚                                      β”‚
 β”‚  Point to a service account JSON     β”‚
 β”‚  file.  Used by Google's client      β”‚
 β”‚  library via Application Default     β”‚
 β”‚  Credentials.                        β”‚
 β”‚                                      β”‚
 β”‚  Smallest permissions + protect      β”‚
 β”‚  the key file.                       β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚  GOOGLE_VISION_API_KEY               β”‚
 β”‚  (Fallback)                          β”‚
 β”‚                                      β”‚
 β”‚  Works but may hit 403 /             β”‚
 β”‚  API_KEY_SERVICE_BLOCKED if your     β”‚
 β”‚  API key has restrictions.           β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Run

Windows (one click):

launcher.bat

This opens two terminal windows -- backend on port 8000, frontend on port 5173.

Manual:

# Terminal 1: Backend
cd backend
.venv\Scripts\activate
uvicorn app.main:app --reload --host 127.0.0.1 --port 8000

# Terminal 2: Frontend
cd frontend
npm run dev

Then open http://localhost:5173.


API

Single Trace

POST /api/trace
  Body:  multipart file as "file"
      or form field "image_url"
  Query: search_mode=google_vision | serpapi | combined

Response:  { "job_id": "uuid", "status": "PENDING" }
GET /api/jobs/{job_id}

Response:  { status, error_message, results: { ... full pipeline JSON } }

Bulk Trace

POST /api/bulk/trace
  Body:  JSON { "urls": [...], "search_mode": "..." }

Response:  { "bulk_job_id": "uuid", "status": "PENDING" }
GET  /api/bulk/{bulk_job_id}           # status + per-job results
GET  /api/bulk/{bulk_job_id}/export     # CSV download

Recent Jobs

GET /api/jobs/recent                    # list recent trace jobs

Result Shape

{
  "query": "input image path or URL",
  "source_kind": "local_file",
  "pipeline_run_at": "2026-04-14T15:59:37Z",
  "steps": [],
  "vision": {
    "auth": {},
    "request": {},
    "rawResponse": {},
    "webDetection": {}
  },
  "candidates": {
    "exactImageUrls": [],
    "pageCandidates": [],
    "selectedPageUrls": [],
    "directExactImages": [],
    "confirmedExactPages": [],
    "fallbackCandidates": []
  },
  "scraped_pages": [],
  "exact_matches": [],
  "fallback_candidates": [],
  "best_source": {},
  "ranking": {},
  "errors": []
}

Metadata Sources

 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚  From pages                             β”‚
 β”‚                                         β”‚
 β”‚  Open Graph (og:image, og:title, ...)   β”‚
 β”‚  Twitter Card (twitter:card, ...)       β”‚
 β”‚  JSON-LD (ImageObject, Article, ...)    β”‚
 β”‚  Dublin Core (DC.title, DC.creator)     β”‚
 β”‚  HTML meta tags (author, date, ...)     β”‚
 β”‚  Platform-specific heuristics           β”‚
 β”‚                                         β”‚
 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
 β”‚  From images                            β”‚
 β”‚                                         β”‚
 β”‚  HTTP headers (Last-Modified, ...)      β”‚
 β”‚  EXIF data (DateTime, Artist, ...)      β”‚
 β”‚                                         β”‚
 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
 β”‚  From external archives                 β”‚
 β”‚                                         β”‚
 β”‚  Wayback Machine oldest snapshot        β”‚
 β”‚                                         β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Search Modes

 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚                                                               β”‚
 β”‚  google_vision (default)                                      β”‚
 β”‚    Uses Google Cloud Vision Web Detection only.               β”‚
 β”‚                                                               β”‚
 β”‚  serpapi                                                      β”‚
 β”‚    Uses SerpAPI Google Lens only.                             β”‚
 β”‚    Requires SERPAPI_API_KEY in .env.                          β”‚
 β”‚                                                               β”‚
 β”‚  combined                                                     β”‚
 β”‚    Runs both and merges results.                              β”‚
 β”‚    Requires both API keys.                                    β”‚
 β”‚                                                               β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Costs

Paid API:

Paid API (optional):

Everything else is local:

  • SQLite, React/Vite frontend, scraping, Wayback CDX queries all run on your machine with no separate billing.

Known Limits

  • Oldest Wayback snapshot is not the same as proven first upload.
  • Many platforms strip EXIF data from images.
  • Some pages block scraping, lazy-load content, or require JavaScript.
  • Google Vision may return context pages that don't expose enough HTML to prove they serve the same file.
  • Some sites remove Last-Modified headers or normalize images behind CDNs.
  • This app is useful for investigation -- it does not prove legal authorship by itself.

References

About

local web app for tracing where a photo appears on the internet. It uses Google Cloud Vision Web Detection to find exact-file matches, then enriches those matches with scraped page metadata, EXIF when available, and oldest-known archive dates from the Wayback Machine.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages