Listing Radar
Reads the LinkedIn or Indeed job posting you have open right now and tells you which lines match the phrasing scammers actually use.
Listing Radar
Reads the LinkedIn or Indeed job posting you have open right now and tells you which lines match the phrasing scammers actually use.
Date: 2026-09-04 Form factor: Browser extension (Manifest V3) Browser surface: content script (LinkedIn and Indeed job pages), toolbar popup, side panel, background service worker Status: Prototype
What it is
Listing Radar sits quietly on job postings on LinkedIn and Indeed. When you open one, it reads the description, checks it against a set of phrasing patterns tied to known scam tactics, and shows a score in the toolbar the moment it's done. Open the popup and you get the score plus the exact lines that tripped it, quoted back at you so you're not just told "risky" and left to guess why.
Why it has to be an extension
The scoring has to happen against the actual page you're looking at, not a URL you paste somewhere else. A content script can read the rendered job description straight out of the DOM, including LinkedIn's client-side routing that swaps in a new posting without a page reload — a plain website has no way to see any of that. The side panel adds the other half: it keeps a running list of every listing scanned this session so you can compare five postings side by side while you're deep in a job search, instead of losing the read on each one the moment you switch tabs.
Who it serves
Anyone running a high-volume remote job search, which is exactly the setup a scam recruiter counts on: enough listings passing by that no one gets a close read. A PasswordManager.com survey of 1,254 U.S. job seekers found that 6 in 10 encountered a fake posting in 2025, and 1 in 4 fell for a hiring scam outright, with half of those losing money or personal data (PasswordManager.com).
Why it could be profitable
Free tier: unlimited scans on LinkedIn and Indeed, a 10-listing session history. Paid tier (roughly $3-5/month): unlimited history with CSV export, plus a live-updated pattern list instead of the fixed one shipped in this build — scam phrasing shifts, and a subscription is the honest way to keep paying for someone to track that. There's a clearer B2B case too: university career centers and coding bootcamps place large cohorts into remote-heavy job searches every semester, and a seat-based license protecting a few hundred students at once is a more sellable pitch than one recruiter subscription at a time.
The demand side has real numbers behind it — BBB's 2026 employment scam update reports employment scam complaints roughly doubled in 2025, with task-based scams alone carrying a $2,300 median loss (BBB) — but the honest caveat is that Listing Radar only covers one entry point. The FTC's April 2026 alert on job scams describes fraud that starts over text message or WhatsApp before a listing is ever posted anywhere (FTC), and that path never touches a browser tab this extension can read.
How to load it in Chrome
- Open
chrome://extensionsand turn on Developer mode. - Click Load unpacked and select this folder's
extension/directory. - Visit a job posting on
linkedin.com/jobsorindeed.com, then click the toolbar icon to see the score. Click the clock-style icon next to it to open the side panel and see everything scanned so far.
How to try the demo
- Open
index.htmlin any modern browser. It falls back to an inline data snapshot iffetchis blocked by the browser'sfile://restrictions. - Use the three buttons above the mock job posting to switch between a clean listing, one with a couple of soft flags, and an obvious scam. Each switch re-scans the posting and updates the badge, the popup, and the side panel.
The badge and text above the mock posting simulate what content.js would inject into a real page; the scoring logic itself (script.js) is the same pattern list content.js runs, applied to whichever mock listing is on screen instead of a live DOM.
Permissions, and why each one
| Permission | Why it's needed |
|---|---|
storage |
Stores the per-tab scan results and the session history shared between the content script, popup, and side panel. |
sidePanel |
Opens and populates the side panel view of scan history. |
content_scripts match pattern (linkedin.com/jobs/*, *.indeed.com/*) |
Limits the content script to the two sites it actually scores, instead of every page you visit. |
What's in this prototype
- Content script that extracts posting text from LinkedIn and Indeed and re-scans automatically when the site swaps in a new listing without a page reload
- A fixed set of ten scam-phrasing patterns pulled from FTC and BBB reporting on real tactics: off-platform handoffs, upfront fees, crypto payouts, task-unlock language, skipped interviews, urgency, personal-inbox contacts, early bank-detail requests, and pay-to-experience mismatches
- Toolbar popup showing the current listing's score, band, and the specific matched lines
- Side panel with the full session history, sorted riskiest-first
- Toolbar badge that colors by risk band the moment a scan finishes
- Demo harness with three switchable mock listings spanning clean, borderline, and obvious-scam
Roadmap
- Replace the fixed pattern list with a server-synced one so new scam phrasing doesn't require a new extension release, gated behind the paid tier
- Add Glassdoor and ZipRecruiter as additional content-script targets
- Seat-based licensing flow for career-center and bootcamp customers
- Surface a one-click "report to BBB Scam Tracker" action from a high-risk result
Sources
- PasswordManager.com: 1 in 4 Job Seekers Fell for Hiring Scams in 2025 — survey of 1,254 U.S. job seekers on fake-posting exposure and scam victimization
- BBB: Employment Scams 2026 Update — 2025 report volume, task-scam losses, and delivery-method breakdown
- FTC Consumer Alert: That Job Offer Text Is Probably a Scam — April 2026 alert describing the specific red-flag phrasing this extension scores against
Requirements
Listing Radar — Requirements
Goals
- Score the job posting a user currently has open on LinkedIn or Indeed against a fixed set of scam-phrasing patterns.
- Show the score and the specific matched lines without requiring the user to leave the page or copy text anywhere.
- Keep a running, per-session history of every listing scanned so a user can compare multiple postings.
- Do all of this without sending posting text off the device.
Primary user
Someone actively job-searching across many postings a day, most often remote or entry-level roles, which is the segment scam recruiters target hardest. They don't have time to fact-check every listing by hand and want a signal that catches the obvious patterns without slowing down their search.
Functional requirements
- FR1: The content script extracts the visible job description text from the currently open LinkedIn or Indeed posting.
- FR2: The content script re-extracts and re-scans when the page's URL changes without a full reload, since both sites swap in new postings via client-side routing.
- FR3: The extracted text is scored against a fixed list of at least ten scam-phrasing patterns, each carrying its own weight.
- FR4: The total score is capped at 100 and mapped to a Low / Elevated / High band using fixed thresholds.
- FR5: Each matched pattern is reported with a human-readable label and a short quoted snippet of the matching text.
- FR6: Scan results are sent from the content script to the background service worker via
chrome.runtime.sendMessage. - FR7: The background service worker stores each result in
chrome.storage.local, keyed by tab, and appends it to a capped session history. - FR8: The background service worker sets the toolbar badge text and color to reflect the risk band of the most recent scan for the active tab.
- FR9: The toolbar popup shows the current tab's scan result: band, score, matched flags with snippets, and a running count of listings scanned this session.
- FR10: The side panel lists the full session history sorted by score, highest first.
- FR11: The side panel updates automatically when new scan results arrive, via
chrome.storage.onChanged. - FR12: The popup's "Open scan history" button opens the side panel for the current window.
- FR13: Free-tier history is capped at 10 entries; the cap is a single constant so a paid tier can raise it without other code changes.
- FR14: The extension declares no permission it does not use in
content.js,popup.js,sidepanel.js, orbackground.js. - FR15: The demo harness reproduces the popup and side panel UI without any
chrome.*API, using the same markup, CSS, and JS files as the real extension. - FR16: The demo runs from a direct
file://open with no local server, falling back to an inline JSON snapshot iffetchis blocked.
User stories
- As someone applying to a dozen remote listings a day, I want an automatic score on each one, so that I don't have to manually re-read every posting for red flags.
- As a user who sees a high-risk score, I want the exact matched phrases quoted back to me, so that I can judge for myself whether the flag makes sense instead of trusting a number blindly.
- As a user comparing several postings from the same job search session, I want a history view sorted by risk, so that the worst ones surface without me hunting through tabs.
- As a user who trusts a clean-scoring listing, I want zero flags to show plainly rather than a vague "looks fine," so that a null result reads as confirmation, not silence.
- As a user hitting the free tier's 10-scan history limit, I want that limit to be obvious in the popup, so that the upgrade pitch makes sense in context.
Extension surfaces
- Content script — extracts posting text on LinkedIn and Indeed job pages, runs the scan, and reports results
- Toolbar popup — current-tab score, matched flags, session stats, link to the side panel
- Side panel — full session history, sorted by risk
- Background service worker — stores scan results, updates the per-tab toolbar badge
chrome.storage— shared state between the content script, popup, and side panel
Non-functional requirements
- No posting text or scan result ever leaves the device; everything lives in
chrome.storage.local. - Pattern matching runs synchronously against a single string and completes in well under 50ms for a typical job description.
- Session history is capped to keep
chrome.storage.localreads bounded regardless of plan tier. - The content script does nothing on a page until it has extracted at least 40 characters of posting text, avoiding false scans on loading or error states.
- The side panel's live update via
chrome.storage.onChangedmust not require a manual refresh.
Out of scope (for the prototype)
- The server-synced, continuously updated pattern list described in the README roadmap — the prototype ships a fixed list only
- Support for job boards beyond LinkedIn and Indeed
- Any paid-tier functionality (unlimited history, CSV export, seat licensing) — the prototype is the free-tier feature set only
- A "report to BBB Scam Tracker" action
Open questions
- LinkedIn and Indeed's DOM structure changes periodically; how much selector maintenance is realistic to commit to before this needs a more resilient extraction approach (e.g. matching on ARIA roles or semantic structure instead of class names)?
- Should the risk thresholds (25 / 55) be user-adjustable, or is a fixed scale better for keeping results comparable across listings?
- Is per-tab storage the right model, or should a scan persist by URL instead, so revisiting the same listing later doesn't require a re-scan?