Automated item sniper for Project Diablo 2 market. Scans saved market filters for cheap items, ranks deals, captures screenshots + direct links, and waits for the user to choose offer amounts before submitting through the website. Use when the user asks to scan the PD2 market, snipe items, check filters, make offers, or monitor the marketplace. Targets softcore ladder. Triggers on phrases like "check market", "snipe items", "scan filters", "PD2 market", "make offers", "any cheap items".
Resources
9Install
npx skillscat add dinglestein/pd2-market-sniper Install via the SkillsCat registry.
PD2 Market Sniper
Automated trading assistant for Project Diablo 2 marketplace (softcore ladder).
Account: d1ngl3 on projectdiablo2.com
Prerequisites
Chrome must be running with remote debugging and logged into the d1ngl3 PD2 account:
Stop-Process -Name chrome -Force -ErrorAction SilentlyContinue
Start-Process "C:\Program Files\Google\Chrome\Application\chrome.exe" -ArgumentList "--remote-debugging-port=9222","--user-data-dir=C:\Users\jding\AppData\Local\Google\Chrome\User Data"Main Workflows
1) Safe Scan Cycle
python scripts/sniper.py scan --max-price 0.5 --filters-per-cycle 12 --daily-limit 200 --max-pages 1What it does:
- Rotates through only part of the saved filter list each cycle (default 12 filters)
- Enforces conservative pacing with 2.0-3.5s randomized delays between filters
- Supports bounded pagination with
--max-pages(default 1 page) - Adds randomized delay between page turns during multi-page scans
- Caps daily checks (default 200) via
sniper_state.json - Intercepts market XHR/fetch JSON when available, with DOM fallback if the API shape changes
- Expires old seen items after 36h so relists can surface again
- Auto-refreshes pd2.tools economy data daily
- Produces structured
scan_results.json - Writes
assets/dashboard.html
2) Scan a Specific Filter
python scripts/sniper.py scan --filter-id 69e0c58f9fc33c4bc7fe0483 --max-price 0.5 --max-pages 33) Alert-Then-Offer Flow (PRIMARY WORKFLOW FOR CHAT)
CRITICAL: The agent IS the notification layer. The CLI only prints to stdout — it does NOT message the user. The agent must read the JSON output, format deals for the chat platform, and send them to the user.
Step-by-step:
- Run operator-scan — captures JSON with ranked deals to
scan_results.json. - Parse the JSON output — read the structured result from the CLI.
- Format deals for chat — for each deal, send a concise card with:
- Item name, price (HR), seller, score
- Key stats/corruptions (if any)
- Direct link
- Screenshot image (attach via
MEDIA:<path>if available) - Economy value comparison (if available)
- Message the user — send each deal as a separate message to the chat channel (WhatsApp/Discord/etc).
- Ask what they want to offer — explicitly prompt: "Reply with an HR amount (e.g.
0.3) to make an offer, or skip." - Wait for user reply — when the user sends a number, run
reply-offer <amount>. - Confirm the result — tell the user if the offer went through or failed.
WhatsApp formatting (no markdown tables, no headers):
🎯 DEAL #1 (Score: 12.4)
⭐ Griffon's Eye
💰 Asking: 0.4 HR | 💎 Econ: 1.2 HR (66% off)
👤 Seller: someguy
🔗 https://www.projectdiablo2.com/market/listing/abc123
Stats:
- +1 Lightning Skills
- 20% FCR
- +15% Light Damage
Reply with an HR amount (e.g. 0.3) to offer, or skip.Operator scan:
python scripts/sniper.py operator-scan --max-price 0.5 --filters-per-cycle 12 --daily-limit 200 --max-pages 1 --top 5This stores the top result as the current pending confirmation target and writes structured JSON to scan_results.json.
Show the pending deal again:
python scripts/sniper.py pendingSubmit a user reply amount against the pending deal:
python scripts/sniper.py reply-offer 0.3Direct offer by URL:
python scripts/sniper.py offer --listing-url "https://www.projectdiablo2.com/market/listing/abc123..." --amount 0.3One-click confirm using the last scan result:
python scripts/sniper.py confirm --deal-index 0 --amount 0.3The sniper does not auto-price. It alerts, ranks, screenshots, and waits for the user to choose the number. The agent is responsible for delivering these alerts to the user via the active chat channel.
Other Commands
List saved filters:
python scripts/sniper.py filtersShow offer history stats:
python scripts/sniper.py historyShow the current pending confirmation deal as JSON:
python scripts/sniper.py pending --jsonRefresh economy cache:
python scripts/sniper.py economy --forceRegenerate dashboard from saved data:
python scripts/sniper.py dashboardFiles and Data
scripts/sniper.py- CLI entry pointscripts/scanner.py- scan orchestration, pacing, API interception, deal collectionscripts/offers.py- offer submission flowscripts/alerts.py- scoring and alert formattingscripts/economy.py- pd2.tools refresh and lookupscripts/history.py- seen item expiry, offer history, scan state, filter healthscripts/dashboard.py- HTML dashboard generationscripts/parsers.py- API/DOM listing parsersscripts/config.py- shared config and filter listseen_items.json- dedup tracker with timestampsoffer_history.json- offer log and status historysniper_state.json- cadence counters, rotation state, filter health, recent scansscan_results.json- latest structured scan outputassets/all_economy.json- cached economy valuesassets/dashboard.html- scan dashboardscreenshots/- deal and offer screenshots
Scan Result Shape
Each scan returns structured JSON with:
summary: timing, filter count, daily count, deal countfilters: per-filter results, API endpoints hit, errors if anydeals: ranked deals with score, direct link, screenshot path, seller, price, and economy contextreview: listings that need manual review because no HR price was parsedstate: recent scan history and filter-health data
Filter Health
The sniper tracks whether filters return listings over time:
- Filters with no hits for 7+ days are marked
slow - Slow filters are still kept in rotation
- Nothing is auto-removed
Safe Usage Notes
- Conservative cadence is deliberate to reduce ban risk
- Keep cycles limited instead of hammering all 59 filters at once
- Use
--max-pages 1for normal sniper behavior, increase pages only for deliberate deep scans - Avoid spamming the same listing, use
offer_history.jsonas a sanity check - Season 13 ladder resets April 24, 2026
Saved Filters
All existing saved filter IDs are preserved in scripts/config.py.