Hides viewed job cards on LinkedIn Jobs pages, adds a compact draggable badge, and lets you reveal hidden items anytime.
Hide or highlight viewed job postings on LinkedIn Jobs with a privacy-first userscript built for Tampermonkey and Violentmonkey — or install as a standalone browser extension for Chrome and Firefox.
This project focuses on three things: stable LinkedIn SPA behavior, high-confidence multilingual viewed/applied detection, and safer scrolling with guard and cooldown protections.

ON/OFF status toggle.Guard (ON/OFF): Scroll protection to prevent LinkedIn rate-limits. This is especially important when hiding jobs, as rapid scrolling through hundreds of hidden items can trigger bot-detection filters.Hide Mode: Automatically vanishes viewed jobs.Highlight Mode: Keeps jobs visible but adds separate low-opacity full-card color filters for viewed and applied cards.jobs and jobs/search views, the currently open job card gets its own configurable highlight filter color so the selected row stays easy to spot.Hide and Highlight modes, tune viewed, applied, active, and keyword card colors, adjust filter opacity, and open the GitHub repository.N hidden/N marked) — which includes both viewed/applied detections and custom-keyword matches, counted once per card — with a +N keyword breakdown showing how many of those are keyword matches, all updated in real-time.ON/OFF, Scroll Guard, Detection Mode, Navigation Reload, Viewed/Applied/Active/Keyword Colors, Filter Opacity, Custom Keywords, and Badge Position.https://www.linkedin.com/jobs/*https://www.linkedin.com/jobs/search/*https://www.linkedin.com/jobs/collections/*linkedin-hide-viewed-jobs.user.js into the extension.Alternative:
The browser extension provides the same functionality as the userscript in a standalone package — no Tampermonkey/Violentmonkey needed.
Chrome:
linkedin-hide-viewed-jobs-chrome.zip from the latest release.chrome://extensions in Chrome.Firefox:
linkedin-hide-viewed-jobs-firefox.zip from the latest release.about:debugging in Firefox.manifest.json file from the unzipped folder.Note: Firefox temporary add-ons are removed when the browser closes. For persistent installation, the extension needs to be signed by Mozilla.
This repository includes a GitHub Pages setup that renders this README through Jekyll with a polished dark editorial layout, a branded hero section, and responsive documentation styling.
Included site assets:
manifest via icons/site.webmanifestrobots.txtsitemap.xmlicons/Publish flow:
Pages.Build and deployment to Deploy from a branch.master branch and /(root) folder.Published site URL:
The script supports detection for the following languages:
OFF, viewed jobs are not hidden; they are only counted.ON, viewed jobs are hidden.Reload OFF is the default. SPA navigation stays on soft refresh unless you explicitly enable Reload ON.Highlight mode, Viewed and Applied cards use different colors so you can distinguish them at a glance.jobs and jobs/search pages, the currently selected card also gets its own full highlight filter color.Viewed, Applied, Active, and Keyword card colors, and use the opacity slider to make the highlight filter lighter or stronger.Enter to add it. Matching job cards are highlighted or hidden depending on the detection mode. Click the × on any chip to remove a keyword.GitHub Repo shortcut for the project source and issue tracker.5-15s) and slow scroll steps to reduce LinkedIn rate-limit risk.div.jobs-search-pagination are temporarily disabled (including collections/search pagination buttons).The script performs detection in multiple layers:
li[data-occludable-job-id] and related LinkedIn list item selectorsVIEWED_MARKER_SELECTORS)aria-label, and title checks inside each cardText matching uses normalize('NFD') plus diacritic removal for more stable multilingual matching.
Source-of-truth customization lives under src/** and the userscript bundle is generated from that source.
Common knobs:
VIEWED_KEYWORDS: Add more viewed-language phrasesAPPLIED_KEYWORDS: Add more applied-language phrasesJOB_CARD_SELECTORS: Card selection scopeVIEWED_MARKER_SELECTORS: Marker selection scopeSTORAGE_KEY: Preference storage keyUI_POSITION_KEY: Badge position storage keyHIDDEN_CLASS: CSS class used for hidingKEYWORD_HIGHLIGHT_COLOR: Highlight/overlay color for keyword-matched cardsmain.ts → LocalStorageService → App → Badge / DetectionService / RouterService / StyleManager
src/main.tswindow.localStorage via LocalStorageServicecontent.ts → ChromeStorageService → App → Badge / DetectionService / RouterService / StyleManager
popup.ts ← chrome.storage.local → background.ts → chrome.storage.onChanged → content.ts
src/extension/content.ts — injected into LinkedIn pagessrc/extension/background.ts — service worker relaying storage changessrc/popup/popup.html + popup.ts + popup.css — settings UI in browser toolbarchrome.storage.local via ChromeStorageServicechrome.storage.local → background relays → content script calls app.refreshSettings()Both modes share the same core business logic:
src/core/App.ts — orchestrator (accepts IStorageService via dependency injection)src/services/DetectionService.ts — viewed/applied/keyword detectionsrc/services/KeywordMatcher.ts — multilingual keyword matching and custom keyword matchingsrc/services/RouterService.ts — SPA route change detectionsrc/ui/Badge.ts — in-page badge UIsrc/ui/StyleManager.ts — CSS injectionThe storage adapter pattern (IStorageService) means App works identically whether backed by localStorage or chrome.storage.local.
bun run build # Build userscript only (.user.js)
bun run build:extension # Build browser extension (dist/extension-chrome/ and dist/extension-firefox/)
bun run build:all # Build both
bun run package:chrome # Create Chrome zip
bun run package:firefox # Create Firefox zip
bun run package:all # Create both zips
bun run lint # Check code quality
bun run check # Lint + format
bun run release # Create GitHub release (local)
VIEWED_KEYWORDS.Contributions are welcome.
feature/your-change) or fix branch (fix/your-change).src/** and update README.md if behavior changes.bun run check to verify lint and formatting.bun run build:all to verify both userscript and extension build.Guidelines:
LocalStorageService and ChromeStorageService are updated.Releases are created manually via GitHub Actions:
version in package.json.For local testing:
bun run build:all
bun run package:all
# Then sideload from dist/extension-chrome/ or dist/extension-firefox/