First signed XPI via web-ext unlisted channel. Firefox will now auto-update installed copies by polling dist/updates.json in this repo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AutoTrader Marker
Firefox extension to mark AutoTrader (autotrader.co.uk) listings as "not wanted" so the ones you haven't reviewed yet stand out.
What it does
- Search results: adds a
✗ Not wantedbutton to the top-left of every listing card. Click and the card fades to ~30 % opacity with a red dashed outline. - Detail page (
/car-details/{id}): adds a floating✗ Not wantedbutton in the bottom-right corner. If you land on a page you've already dismissed, a red banner appears at the top with an Undo action. - Browser-action popup shows the count, lets you toggle Hide dismissed listings (fully collapse them on search results instead of fade), export/import the list as JSON, or clear everything.
- State persists in
browser.storage.localand syncs across open tabs viastorage.onChanged.
Temporary install (for development)
about:debugging#/runtime/this-firefox→ Load Temporary Add-on…- Select
manifest.json. Changes require clicking Reload on that page. - Temporary add-ons vanish on Firefox restart.
Persistent install via unlisted signing (auto-updates)
Once signed and installed this way, Firefox auto-updates installed copies by
polling dist/updates.json in the Gitea repo roughly once a day.
One-time setup
- Create the Gitea repo at https://git.nocker.cloud/tony/autotrader-marker
(must be pullable over HTTPS without auth so Firefox can fetch
dist/updates.jsonand the XPIs). - Initial commit and push:
cd autotrader-marker git init && git branch -m main git remote add origin https://git.nocker.cloud/tony/autotrader-marker.git npm install git add . git commit -m "Initial commit" git push -u origin main - Get AMO JWT credentials at
https://addons.mozilla.org/en-US/developers/addon/api/key/. Save them
somewhere safe (macOS Keychain or Infisical
/autotrader-marker). - Export the creds before running any release:
export WEB_EXT_API_KEY='user:12345:67' export WEB_EXT_API_SECRET='abcdef0123456789...' - Cut the first signed release (from the repo root, on your Mac):
bin/release.sh 0.1.0 # or: bin/release.sh patch git add manifest.json package.json dist/ git commit -m "Release v0.1.0" git push origin main - Install the signed XPI once on your host Firefox:
- Open
about:addons→ ⚙ (gear) → Install Add-on From File… - Select
dist/autotrader-marker-0.1.0.xpi - Firefox keeps it installed and checks for updates automatically.
- Open
Subsequent releases
# Edit code, then:
bin/release.sh patch # 0.1.0 → 0.1.1
# (or 'minor' / 'major' / an explicit version like '1.2.3')
git add manifest.json package.json dist/
git commit -m "Release v$(node -p "require('./manifest.json').version")"
git push origin main
Firefox polls for updates on its own schedule (~daily). To trigger immediately:
about:addons → ⚙ → Check for Updates.
What bin/release.sh does
- Bumps the version in
manifest.jsonandpackage.json. - Runs
web-ext sign --channel=unlistedagainst AMO. Mozilla validates and signs the XPI (usually seconds for an unlisted submission). - Copies the signed XPI to
dist/autotrader-marker-<version>.xpi. - Appends the new version to
dist/updates.jsonso Firefox can discover it. - Prints next-step git commands — it does not push automatically.
If web-ext sign prints a lint ERROR about MANIFEST_UPDATE_URL, that's
expected and doesn't block signing: the rule only applies to AMO-listed
add-ons, and --channel=unlisted proceeds past it.
Package a static zip (for about:debugging without signing)
python3 -c "
import zipfile
with zipfile.ZipFile('../autotrader-marker.zip', 'w', zipfile.ZIP_DEFLATED) as z:
for f in ['manifest.json','content.js','content.css','popup.html','popup.css','popup.js','icon.svg']:
z.write(f)
"
DOM contract (verified 2026-04)
The content script relies on these AutoTrader selectors. If they change, update
content.js:
| What | Selector |
|---|---|
| Listing card | li[data-testid^="id-"] (id is id-{listingId}) |
| Search result title | [data-testid="search-listing-title"] |
| Detail page id | URL path /car-details/{digits} |
| Detail page title | h1 (falls back to document.title) |
The primary id sources are the data-testid on the <li> for search results
and the URL path for detail pages — no href parsing needed in the happy path.
The detail-page UI uses a fixed-position FAB, so it doesn't depend on the
page's layout at all.
Files
| File | Purpose |
|---|---|
manifest.json |
MV3 manifest, Firefox-specific settings, update_url → Gitea |
content.js |
Injects buttons, manages dismissal state, MutationObserver for infinite scroll, SPA-nav aware |
content.css |
Button styling + dismissed-card fade/hide rules |
popup.html / popup.css / popup.js |
Toolbar popup UI |
icon.svg |
Single SVG used for toolbar + addon listing |
bin/release.sh |
Version bump + sign + updates.json refresh |
dist/updates.json |
Served to Firefox for update polling |
dist/*.xpi |
Signed extension bundles referenced by updates.json |