Slop Block is a Chrome extension that uses a hybrid classification system (local heuristics + AI) to filter LinkedIn posts. It automatically hides job announcements, grindset posts, engagement bait, and other noise while keeping genuine recruiter hiring posts visible.
Key Philosophy: Slop Block uses deterministic heuristics as the primary filter and only invokes Chrome's built-in LLM as a fallback for ambiguous posts, preserving performance, privacy, and control.
- Heuristics First: Fast keyword and phrase matching runs first for instant results
- AI Fallback: Chrome's built-in LanguageModel API (Gemini Nano) only processes uncertain cases
- Privacy First: All processing happens locally. No data sent to external servers
- Customizable: Toggle 13+ post categories on/off via the popup interface
- Real-time Updates: Automatically processes new posts as they appear using MutationObserver
- Performance Optimized: Batched processing with requestIdleCallback, no layout shifts, no scroll jank
- SPA Navigation Support: Automatically re-initializes on LinkedIn's single-page app navigation
- Chrome Canary or Beta version 127+ (required for LanguageModel API support)
- Google Chrome browser
Slop Block requires Chrome's built-in LanguageModel API powered by Google Gemini Nano for AI classification. To enable this feature:
- Ensure you're using Chrome Canary or Beta version 127+
- Navigate to
chrome://flagsin your address bar - Enable these flags:
#prompt-api-for-gemini-nano#optimization-guide-on-device-model
- Restart Chrome
For detailed setup instructions and system requirements, see the official Google Chrome AI documentation.
Note: The first post you load may take longer to process as Chrome needs to initialize and download the Gemini Nano model. Subsequent posts will process much faster once the model is loaded.
- Go to the Slop Block repository
- Click the green "Code" button
- Select "Download ZIP"
- Extract the downloaded ZIP file to a location you can easily access
- Open Google Chrome
- Navigate to
chrome://extensions/in the address bar- Alternatively: Go to Menu (⋮) → Extensions → Manage Extensions
- Toggle the "Developer mode" switch in the top-right corner
- Click the "Load unpacked" button
- Navigate to and select the
chrome extensionfolder inside the extracted directory- Important: Select the
chrome extensionfolder, not the rootSlop-Blockfolder
- Important: Select the
That's it! Visit your LinkedIn feed and Slop Block will automatically start filtering posts. You can customize which post categories to show/hide by clicking the extension icon in your Chrome toolbar.
The extension follows a clean separation of concerns with clear boundaries between components:
Manifest.json - Entry point that registers:
- Background service worker
- Content scripts injected into LinkedIn
- Popup UI for user controls
Content Scripts (LinkedIn page) - Handle the heavy lifting:
content_script.js- Orchestrator that observes DOM mutations, identifies posts via URNs, and coordinates classification and blockingfilter.js- Pure heuristics engine (fast, local, deterministic) with precedence-ordered classification rulesui.js- Handles blur overlays, labels, and user reveal actions
Background Service Worker - Only place where AI runs:
service_worker.js- Routes messages from content scriptsgeminiClient.js- Wraps Chrome's built-in LanguageModel API, caching a single session
Popup + Storage - Manage user preferences:
popup.js- Saves settings tochrome.storage.sync- Content scripts re-evaluate visible posts when settings change
- Fast by default: Heuristics run first, AI is only a fallback
- Expensive AI calls minimized: Most posts never touch AI
- Clear isolation: Separation between DOM access, AI access, and user controls
- Scales well: Works efficiently with LinkedIn's virtualized feed
The extension processes posts in a heuristics-first approach:
-
Page Load
- LinkedIn renders its virtualized feed
content_script.jsinitializes MutationObserver and SPA navigation hooks
-
New Posts Appear
- DOM mutations trigger a scheduled scan (batched with
requestIdleCallback) - Each post is assigned a stable URN (Uniform Resource Name)
- Post text is extracted and normalized
- DOM mutations trigger a scheduled scan (batched with
-
Heuristics Classification (Fast Path)
filter.jsclassifies the post using precedence-ordered rules- If the category is blocked by settings → blur immediately
- If allowed → leave unblurred
- No AI involved for the majority of posts
-
LLM Fallback (Slow Path, Only If Needed)
- If heuristics return "Other / Unsure":
- UI shows "Processing…"
- Content script sends a message to the background worker
- The Gemini client reuses a cached LanguageModel session
- Returns a short label/category
- UI updates the overlay label
- If not unsure → LLM is never called
- If heuristics return "Other / Unsure":
-
User Reveal
- Clicking "Reveal Post" unblurs the post
- The URN is added to
userRevealedso it won't be re-blocked
-
Settings Change
- User toggles a filter in the popup
- Settings are saved to sync storage
- Content script re-classifies all visible posts and updates blur state
- Critical path is local and synchronous: Heuristics provide instant results
- AI calls are asynchronous, rare, and clearly isolated: Only for ambiguous cases
- Feed stays smooth: Even under heavy scrolling, processing is batched and non-blocking
- User intent always wins: Manual reveals are respected and persisted
Slop-Block/
├── architecture.jpg # Architecture diagram
├── sequence.jpg # Runtime flow diagram
├── chrome extension/ # Chrome extension source code
│ ├── background/ # Background service worker
│ │ ├── service_worker.js # Message routing
│ │ └── geminiClient.js # LanguageModel API wrapper
│ ├── content/ # Content scripts
│ │ ├── content_script.js # Main orchestrator
│ │ ├── filter.js # Heuristics classification
│ │ ├── ui.js # UI overlay management
│ │ └── styles.css # Overlay styles
│ ├── popup/ # Extension popup UI
│ │ ├── popup.html
│ │ ├── popup.js
│ │ └── popup.css
│ ├── icons/ # Extension icons
│ └── manifest.json # Extension manifest
└── docs/ # Website documentation
├── index.html
├── styles.css
└── script.js
Slop Block identifies and filters 13+ categories of LinkedIn posts:
- Hiring Posts (default: shown) - Recruiter posts actively seeking candidates
- Job Announcements (default: hidden) - Posts announcing new positions
- LinkedIn Grindset Final Boss (default: hidden) - Extreme hustle culture posts
- AI Doomer (default: hidden) - Posts claiming AI will replace all developers
- Child Prodigy Flex (default: hidden) - Posts emphasizing extreme youth + achievement
- Sponsored/Ads (default: hidden) - Promoted and sponsored posts
- Sales Pitch (default: hidden) - Sales and lead generation posts
- Job Seeking (default: hidden) - Open-to-work and layoff posts
- Events/Webinars (default: hidden) - Event and webinar announcements
- Engagement Bait (default: hidden) - Comment traps and engagement farming
- Educational/Tips (default: hidden) - Educational content and tips
- Project Launch (default: hidden) - Project launches and shipping posts
- Congrats/Certs (default: hidden) - Congratulations and certification posts
- Other (default: hidden) - Posts that don't match other categories (AI-classified)
The heuristics engine uses:
- Phrase matching: Extensive lists of keywords and phrases for each category
- Regex patterns: High-signal patterns for structured variants
- Precedence ordering: Categories are checked in a specific order (e.g., hired announcements before hiring posts)
- Text normalization: Handles curly quotes, dashes, and punctuation variations
When heuristics can't confidently classify a post:
- Post is marked as "Other / Unsure"
- Background worker is notified via message passing
- Chrome's built-in LanguageModel API (Gemini Nano) processes the post text
- Returns a 1-3 word category label
- UI updates to show the AI-determined category
- URN-based deduplication: Posts are tracked by stable URNs to prevent re-processing
- Batched processing: Multiple posts are processed together using
requestIdleCallback - Subtree-only scanning: Only newly added DOM nodes are scanned, not the entire feed
- Virtualization-safe: Works correctly with LinkedIn's virtualized feed implementation
- Session caching: LanguageModel session is cached and reused across requests
MIT License
Copyright (c) 2024 Slop Block
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Contributions are welcome! Please feel free to submit a Pull Request.


