A Chrome Manifest V3 extension that turns your Amazon order history into a personal sustainability tracker. It scrapes your past orders, builds an eco + preference profile with Gemini AI, grades your active cart on environmental impact, and flags return-risk items before you check out.
Navigate to your Amazon orders page and use the popup scraper. You can:
- Scan all order pages — walks full-year filters from 2025 through the current year (not Amazon’s default three-month window) in a background tab.
- Scan this view — from whatever orders view is open in the active tab (year filter, etc.), paginates through all pages in that view without closing your tab.
After a crawl finishes, the service worker merges rows into chrome.storage.local, optionally syncs orders to the backend when it is running, and builds your eco + preference profile automatically so work is not lost if the popup closes.
The profile is built from scraped orders via a two-stage pipeline (also triggered automatically after a successful crawl). You can still use Build eco profile manually if you only scraped a page or need to rebuild:
- Rule-based parser (
order-profile.js) extracts top categories, brands, colors, sizes (shoes, shirts, pants, outerwear), flavors, and scents from product titles. - Gemini Flash (
/api/ai-preference-profile) re-analyzes the same orders and merges results, with the AI layer taking precedence where it has higher-confidence extractions. - The merged profile is stored in
chrome.storage.localand backed up to SQLite.
You can also fill in sizing gaps manually via a preference hints form in the popup; hints are pre-filled from any order-history data already extracted.
eco-engine.js computes aggregate sustainability metrics over your full order history:
| Metric | How it's computed |
|---|---|
| Lifetime CO₂e | Per-item kg CO₂ by category × quantity, summed across all orders |
| Return waste (lbs) | Estimated landfill weight per returned item by category |
| Return shipping CO₂ | 0.5 kg CO₂e per returned item |
| Return rate by category | Used to flag cart items with historically high return rates |
Category CO₂ weights are based on lifecycle assessment averages (e.g. electronics 65 kg, shoes 10 kg, apparel 9 kg).
When you open the popup on amazon.com/cart, the extension reads your cart items and scores the order:
- Carbon estimate — CO₂e for each item based on inferred category
- Return-risk warning — flags categories where your personal return rate exceeds 30%
- Shipment consolidation — penalises carts spanning many categories (likely multiple shipments)
- Letter grade A–F with a tailored tip (e.g. "Select No-Rush Shipping", "Verify sizes before buying")
return-risk-engine.js calls Gemini (or the backend /api/return-risk-reasoning endpoint) to reason about each cart item against your preference profile. It returns:
- Risk level —
low | moderate | high - Primary reason —
size_mismatch | fit_guidance_conflict | duplicate_order | unfamiliar_brand | unusual_variant | price_outlier | quality_risk | none - Recommended action —
keep | review_size | compare_with_past_purchase | confirm_order | remove_duplicate | switch_variant - Tags — used to surface inline warnings on each cart item card
For footwear with a clear size mismatch, the engine can override the model’s short summary with a numeric US size gap (e.g. usual 4 vs selected 10 → six full sizes), so the copy matches the numbers instead of vague phrases like “two sizes.”
On any Amazon product detail page, product-widget.js injects a small IntentCart panel that:
- Parses fit guidance text from Amazon's own review summary ("runs small", "size down", etc.)
- Runs the return risk engine against your profile for the specific product
- Shows a risk badge, confidence line, profile anchors (usual sizes/colors when relevant), and an expandable Why this matters line
- Review logic scans all visible fit snippets (not just the first line), labels mixed or conflicting sizing when appropriate, and avoids showing a “true to size” quote under a summary that already says the shoe runs large / wide (or duplicating the same line twice)
content.js watches the cart page for shoe items. If a shoe's size variant doesn't match your stored preferred shoe size, a warning modal appears before you proceed to checkout.
amazon-cartreader/
├── frontend/ ← Chrome extension (load this folder in Chrome)
│ ├── manifest.json
│ ├── popup.html / popup.css / popup.js (main UI + state machine)
│ ├── eco-engine.js (CO₂ + waste stats, cart scoring, Gemini eco tips)
│ ├── return-risk-engine.js (per-item return risk via Gemini or backend)
│ ├── product-widget.js (injected widget on Amazon product pages)
│ ├── order-profile.js (fetch, parse, and preference profile pipeline)
│ ├── orders-scraper.js (Amazon order history page scraper)
│ ├── content.js (cart parser + shoe-size warning modal)
│ └── background.js (service worker: order crawl + persist + profile build via importScripts)
├── backend/ ← Local Node.js server
│ ├── server.js (SQLite persistence + Gemini API proxy)
│ └── imported-orders.example.json
├── package.json
└── .gitignore
- Node.js ≥ 18
- A Gemini API key (free tier is sufficient)
- Chrome or any Chromium browser
- Open
chrome://extensions. - Enable Developer mode (top-right toggle).
- Click Load unpacked.
- Select the
frontend/folder.
GEMINI_API_KEY=your-key npm startThe server starts at http://localhost:3000. The extension also tries 127.0.0.1:3000 and ports 3001 as fallbacks.
- Start the backend with your Gemini key (optional but recommended for SQLite backup and proxied AI).
- Go to
amazon.com/your-orders/ordersin Chrome. - Open the IntentCart popup — the scraper panel appears.
- Click Scan all order pages (year-by-year crawl) or open a filtered view (e.g. a single year) and use Scan all pages in this view.
- Wait for the crawl to finish — your profile and eco stats update automatically in the background (you can still tap Build eco profile to rebuild manually).
- View your lifetime CO₂e, return waste stats, and Gemini-powered sustainability tips.
- Open your Amazon cart to see the eco grade and per-item return risk.
- Copy
backend/imported-orders.example.json→backend/imported-orders.jsonand populate with real records. - Start the backend.
- The backend serves these orders through
/api/imported-orders.
| Endpoint | Method | Description |
|---|---|---|
/api/health |
GET | Server status + SQLite stats |
/api/imported-orders |
GET | Serve orders (SQLite → file fallback) |
/api/imported-orders |
POST | Save scraped orders to SQLite |
/api/order-preference-profile |
GET | Retrieve latest profile snapshot |
/api/order-preference-profile |
POST | Save profile snapshot |
/api/ai-preference-profile |
GET | Run Gemini on file/SQLite orders |
/api/ai-preference-profile |
POST | Run Gemini on provided order records |
/api/return-risk-reasoning |
POST | Run Gemini return-risk analysis on cart items |
If GEMINI_API_KEY is missing, AI endpoints return 503; the extension falls back to rule-based parsing and local Gemini calls (using a key stored in chrome.storage.local).
type ImportedOrderItem = {
orderId: string;
orderDate: string;
productTitle: string;
asin?: string;
category?: string;
brand?: string;
variantText?: string;
quantity: number;
unitPrice?: number;
currency?: string;
returned?: boolean;
returnReason?: string | null;
};type PreferenceProfile = {
orderCount: number;
topCategories: Array<{ value: string; count: number }>;
topBrands: Array<{ value: string; count: number }>;
topColors: Array<{ value: string; count: number }>;
topFlavors: Array<{ value: string; count: number }>;
topScents: Array<{ value: string; count: number }>;
sizes: {
shoes: string | null;
shirts: string | null;
pants: string | null;
outerwear: string | null;
};
manualHints?: { ... }; // user-supplied overrides
updatedAt: string; // ISO timestamp
};- The SQLite database is written to
backend/amazon-cart-reader.sqlite(git-ignored). backend/imported-orders.jsonis git-ignored; useimported-orders.example.jsonas a template.- No sample data is returned unless the server is started with
USE_SAMPLE_DATA=true. - Gemini API key can be supplied via the
GEMINI_API_KEYenv var (backend proxy) or stored directly inchrome.storage.local(used by the extension for direct Gemini calls).