PropertyRoom Scraper - Police Auction Lots & Consignors
Pricing
$0.90 / 1,000 per lot returneds
PropertyRoom Scraper - Police Auction Lots & Consignors
From $0.90 per 1,000 rows, no start fee. Every open lot on PropertyRoom, the auctioneer for US police and municipal seized property: live bid, bid count, close time, condition, photos, and the consignor's name, street, city, state, ZIP and phone. 16,092 lots counted; 6,618 unreachable by category.
Pricing
$0.90 / 1,000 per lot returneds
Rating
0.0
(0)
Developer
Scrapers Delight
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
🚔 PropertyRoom Scraper — Police Auction Lots, Live Bids & Consignors
Scrape every open auction lot on PropertyRoom.com, the contracted auctioneer that US police departments and municipalities use to dispose of unclaimed, seized and surplus property. One row per lot: the live bid, the bid count, the exact close time, the condition the consignor stated, the full photo set — and the consignor's published name, street, city, state, ZIP and phone.
$0.90 per 1,000 lots. No run-start fee. You are charged once per row delivered and for nothing else. A run that matches nothing costs nothing.
Every number on this page was measured on 2026-09-18 by running this Actor through an Apify residential exit. None of them is an estimate.
📊 What does PropertyRoom Scraper do?
- 🔎 Reads the whole catalogue. 16,092 open lots in PropertyRoom's sitemap; 9,568 reachable through its browse pages. Both paths are supported and the difference is explained below.
- 💰 Gets the current bid — the number PropertyRoom does not put in the listing HTML at all. 1,000 of 1,000 rows on a live run carried a price, a bid count and a bid increment.
- 🏢 Gets the consignor's contact block. Display name, street, city, state and ZIP on 1,000 of 1,000 rows; phone on 598. That is a pawn shop, coin dealer or jewellery wholesaler with a real address on two thirds of lots — a lead list hiding inside an auction site.
- 🚔 Flags law-enforcement consignment using PropertyRoom's own sentence, not a guess. 240 of 1,000 rows on a live run.
- ⏱️ Sorts by closing-soonest, cheapest, or most-contested before spending anything, so your row cap lands on the lots you actually want.
- 🧾 Filters are free. Status, auction format, price band, bid count, closing window and title keyword all run against PropertyRoom's batched bid feed before the per-lot fetch. A lot your filter rejects is never delivered and never charged.
- 🖼️ Every photo, as a direct CDN URL. 1,000 of 1,000 rows.
- 🏛️ PropertyRoom's own client roster — the 45 law-enforcement and municipal agencies it names
publicly, written to a separate
CLIENT_AGENCIESrecord. Site-wide reference, never faked onto a row. - 📋 A RUN_SUMMARY that reconciles what was walked against what was delivered and charged.
👤 Who uses a PropertyRoom scraper?
- Jewellery, watch and coin dealers — the site's largest department is jewellery (3,762 lots), then collectibles and coins. Filter to no-bids-yet lots closing in the next hour.
- Electronics and tool resellers on eBay or Amazon — 877 electronics lots, 729 tools, with stated condition and the model number in the description.
- Pawnbrokers — scan bulk lots for inventory instead of clicking through 383 pages.
- Asset-recovery and insurance-salvage desks — track recovered property as it moves through the law-enforcement disposal channel.
- Price researchers — closed lots carry the realised price, so you can compare what things actually sell for against what is currently being asked.
- B2B lead builders — 27 distinct consignor accounts across a 1,000-lot run, each with a physical address; 325 of those rows shipped from Florida, 195 from California.
⚙️ How it works
PropertyRoom is an ASP.NET site whose listing pages do not contain the current bid. The bid lives in the page's own XHR. This Actor uses that endpoint directly, which is both more complete and about three times smaller than the rendered page:
- Enumerate. Either the browse catalogue (
/c/<category>/<page>, 25 lot cards a page, in the site's own closing-soonest order) or the sitemap (every lot URL in one request). - Hydrate the live state in batches. PropertyRoom's
GetClientListingsendpoint accepts an array of lot IDs and answers them all in one request — verified to 1,000 IDs in 2.4 seconds. Live bid state for the entire 16,092-lot catalogue costs 33 requests, not 16,092. - Filter and sort here, on data that cost about 480 bytes a lot.
- Fetch the full record only for the lots that survived and are about to be delivered.
That ordering is why the price is what it is. We charge per row delivered but pay per lot examined, so any filter applied after the expensive step would put the cost of your rejected lots inside the price of your kept ones.
The two enumeration paths, measured
| Browse catalogue (default) | Full sitemap census | |
|---|---|---|
| Lots reachable | 9,568 (383 pages, walked exhaustively) | 16,092 |
| Lots only this path reaches | — | 6,524 |
| Ordered by the site? | Yes, closing soonest | No |
| Platform usage, 25-row run | $0.0012 | $0.0389 |
| Fixed cost before the first row | ~$0.0000 | ~$0.047 |
| Pays for itself from | any size | about 100 rows |
| Best for | everyday runs, one department, capped runs | completeness, big pulls, site-wide price/bid sorts |
The union of every browsable category page is 9,550 lots — so this is not a quirk of the
all-items page. A third of PropertyRoom's open inventory simply is not linked from any category.
Set source to sitemap when you need it. The extra cost is one 4.6 MB read plus a live-state
sweep of all 16,092 lots — about $0.047 of Apify usage before the first row, regardless of how many
rows you keep — so it amortises away on a large pull and not on a small one. A sitemap run under
100 rows says so in RUN_SUMMARY.warnings.
💵 Pricing
| Model | Pay per event — one event, lot-scraped |
| Price | $0.0009 per lot delivered ($0.90 per 1,000) |
| Run-start fee | None |
| Charged for filtered-out lots | No — they are dropped before any per-lot request |
| Charged for IDs that do not exist | No |
| Charged for lots we could not reach | No |
| Charged for a run that matches nothing | No |
Apify platform usage is separate and billed by Apify. Measured on this Actor at 1024 MB through Apify Proxy (residential, US), across three runs of 25 / 250 / 1,000 rows: $0.00021 per row, on a fixed base of about $0.0015 per run. The slope was within 3% across all three run sizes. 83% of that is residential proxy traffic — note that Apify meters residential transfer on the decompressed payload, so the gzip this Actor requests on every call buys speed, not proxy dollars.
📥 Input
{"source": "catalogue","categories": ["coins"],"listingStatus": "open","bidState": "noBidsYet","maxCurrentPrice": 50,"closingWithinHours": 6,"sortBy": "endingSoonest","maxLots": 25,"fetchDetails": true,"proxyConfiguration": {"useApifyProxy": true,"apifyProxyGroups": ["RESIDENTIAL"],"apifyProxyCountry": "US"}}
| Field | Type | Default | What it does |
|---|---|---|---|
source | string | catalogue | catalogue walks browse pages (9,568 lots, cheap, pre-ordered). sitemap reads the full census (16,092 lots). |
categories | array | all items | Category slugs, OR-ed. Measured lot counts: jewelry 3,762 · everything-else 1,245 · collectibles 1,222 · electronics 877 · coins 746 · tools-and-equipment 729 · fashion 635 · watches 532 · fine-art 213 · sunglasses-and-eyewear 161 · musical-instruments 149 · computers 120 · vehicles 73 · bikes 18 · steal-of-the-day 11. Sub-category slugs work too. Ignored in sitemap mode. |
lotIds | array | — | Re-check known lots and skip enumeration entirely. Overrides categories. |
listingStatus | string | any | open · scheduled · closed. Measured on 1,000 random lots: 580 open, 418 scheduled, 2 closed. |
auctionFormats | array | all | Auction (753 of 1,000) · Fixed Price (233) · Reserve Auction (11) · Bid to be Approved Auction (3). |
bidState | string | any | noBidsYet · hasBids. 58 of 1,000 random lots had a bid. |
minCurrentPrice / maxCurrentPrice | integer | — | Price band. Median price across 1,000 lots was $32; the highest was $3,999. |
maxBidCount | integer | — | Skip lots that already have a bidding war. |
closingWithinHours | integer | — | The "what can I still win today" filter. |
titleContains | array | — | Keywords, OR-ed, case-insensitive. |
sortBy | string | endingSoonest | endingSoonest · endingLatest · priceLowest · priceHighest · mostBids · newestListed · asListed. |
maxLots | integer | 50 | Hard cap on rows delivered and charged. |
fetchDetails | boolean | true | Off skips the per-lot record: about five times faster, but 33 fields come back null at the same price. |
includeClientAgencies | boolean | true | Writes the CLIENT_AGENCIES record (45 named agencies, the site's 4,300+ client claim, and 5 clients that publish their own auction page). Two extra page reads. |
concurrency | integer | 8 | 200 detail calls at 8 took 25.6 s with zero errors. |
proxyConfiguration | object | Apify RESIDENTIAL, US | See Proxy below. This one matters. |
📤 Output — a real row from a live run
Not an example. This is row 1 of a 1,000-row run on 2026-09-18, trimmed only where marked.
{"lotId": "18940685","lotUrl": "https://www.propertyroom.com/l/nikon-coolpix-l830-digital-camera/18940685","title": "Nikon CoolPix L830 Digital Camera","category": "Digital & SLR Cameras","categoryId": 1057,"auctionFormat": "Auction","listingStatus": "open","isOpen": true,"currentPriceUsd": 32,"soldPriceUsd": null,"startingBidUsd": 1,"minimumBidUsd": 35,"bidIncrementUsd": 3,"reservePriceUsd": 0,"buyersPremiumUsd": 0,"bidCount": 13,"hasBids": true,"activeBidders": 7,"watchCount": 10,"highBidderLocation": "Walker, LA","highBidderMemberSince": "August 2026","closesAt": "2026-09-18T22:12:00.000Z","closesAtLocalEastern": "Sep 18, 2026 at 06:12 PM","secondsRemaining": 140,"description": "Get a great deal with this online auction presented by PropertyRoom.com on behalf of a law enforcement or public agency client.\nModel: L830 Memory Card: Not included Battery: \"AA\", not included Accessories: Carry bag only ...","condition": "Fair, scuffed and scratched","itemNumber": "1320-002549","itemLocation": "CA,917611547","quantityOffered": 1,"quantityRemaining": 1,"weight": 4,"weightUnit": "pounds","shippingEstimateUsd": 16.95,"shippingService": "Standard","shippingCarrier": "FlatRate","freeShipping": false,"allowedCountries": "US","sellerId": 1,"sellerName": "Ontario, California","sellerStreet": "3959 E. Guasti Road Unit D","sellerCity": "Ontario","sellerState": "CA","sellerZip": "91761","sellerPhone": null,"sellerIsPropertyRoom": true,"isLawEnforcementConsignment": true,"consignorAccountCode": "1320","photoCount": 3,"titlePhotoUrl": "https://content.propertyroom.com/listings/sellers/seller1/images/origimgs/nikon-coolpix-l830-digital-camera-1_10920261944283282256.jpg","photoUrls": ["... 3 direct CDN URLs ..."],"scrapedAt": "2026-09-18T22:10:34.817Z"}
Measured field fill — 1,000 rows, one live run, 2026-09-18
100% filled (1,000 / 1,000): lotId · lotUrl · title · category · categoryId ·
auctionFormat · listingStatus · isOpen · currentPriceUsd · startingBidUsd ·
minimumBidUsd · bidIncrementUsd · reservePriceUsd · buyersPremiumUsd · bidCount ·
hasBids · activeBidders · watchCount · closesAt · closesAtLocalEastern ·
secondsRemaining · description · quantityOffered · quantityRemaining ·
shippingEstimateUsd · shippingService · shippingCarrier · freeShipping ·
allowedCountries · sellerId · sellerName · sellerStreet · sellerCity · sellerState ·
sellerZip · sellerIsPropertyRoom · isLawEnforcementConsignment · photoCount ·
titlePhotoUrl · photoUrls · scrapedAt
| Field | Fill | Why it is not 100% |
|---|---|---|
itemNumber | 999 / 1,000 | One lot had none. |
consignorAccountCode | 859 / 1,000 | Not every SKU starts with PropertyRoom's four-digit account prefix. |
sellerPhone | 598 / 1,000 | Some consignors publish no phone. Blank, never invented. |
weight / weightUnit | 593 / 1,000 | PropertyRoom writes 0 for "not recorded"; a 0 lb parcel is not a fact, so it is null and the unit goes with it. |
condition | 464 / 1,000 | Condition is free text inside the description, not a field. Parsed where stated, null where not. |
itemLocation | 407 / 1,000 | Published mainly on PropertyRoom's own lots. |
highBidderLocation / highBidderMemberSince | 232 / 1,000 | Only exists once a lot has a bid: 232 of the 236 rows that had bids carried it. |
soldPriceUsd | 0 / 1,000 | This run was filtered to live lots. It fills on a closed lot that actually received a bid — verified separately against closed lots 18939117, 18947386 and 18955837. |
On a 200-lot random sample the picture is the same, with two extra findings: sellerState and
sellerZip were 197/200 rather than 1,000/1,000, because PropertyRoom's "In-Place Auctions" lots
publish City: "See Auction Listing" and a whitespace state; and condition parsed on 101/200.
🚔 What this Actor does not claim
This is the part other listings get wrong, so it is stated plainly.
- The contracting police department or agency is NOT published on a PropertyRoom listing.
Not in the HTML, not in the JSON, not in the images. We went looking properly before saying so:
all 16
/ajax/ajax.svc/methods were enumerated out of the site's own script bundles and there is noGetSeller,GetMerchantorGetAgency;/seller/<id>answers an error page and/m/<id>is empty, because the/m/route is keyed on a merchant display name rather than the numeric ID; 0 of 60 lots pulled from Vehicles and Police & Fire Surplus — where a municipal consignment is most likely to be named — mentioned an agency; and 3 of 1,000 rows on a live run contained an agency-shaped token, all three incidental product copy. What you get instead is:isLawEnforcementConsignment— PropertyRoom's own sentence, printed verbatim at the top of the description: "presented by PropertyRoom.com on behalf of a law enforcement or public agency client." 240 of 1,000 rows on a live run; 37 of 200 on a random sample.sellerIsPropertyRoom— the lot is sold from PropertyRoom's own account (sellerId1), which is the channel its public-agency clients are disposed through. The two agree on 197 of 200 random lots, and thesellerNameon these is the PropertyRoom warehouse handling the lot ("Ontario, California", "Frederick, MD", "Ronkonkoma, New York"), not the agency.consignorAccountCode— the four-digit prefix ofitemNumber. It behaves exactly like a consignor account: 18 of the 19 third-party merchants in a 200-lot sample used one code for all their lots, while PropertyRoom's own account used 32 distinct codes across 40 lots — one per client batch. It groups lots from the same agency consignment. It is a code, not a name.
- The agency names PropertyRoom does publish are site-wide, and we keep them separate. Its
/about-us/partnerspage names 45 law-enforcement and municipal clients — Atlanta PD, NYPD, Chicago PD, Cook County Sheriff's Office, Washington State Patrol and so on — against the 4,300+ clients it claims in total, and/client/linkingnames five more that publish their own auction page. This Actor writes that roster to aCLIENT_AGENCIESkey-value record, and deliberately does not join it onto any row: nothing links a lot to one of those names, so a per-row agency column would be an invention. Turn it off withincludeClientAgencies: false. - PropertyRoom's own "police items" view does not filter.
cat.aspx?policeitems=truereturns the same 383-page result set as the unfiltered catalogue, lot for lot, measured 2026-09-18. Any police flag built on it marks the entire site. Ours is built on the site's own sentence instead. - There is no site search.
robots.txtdisallows/searchresult.aspx, sotitleContainsfilters the catalogue rather than querying PropertyRoom's search. - No sub-category column. PropertyRoom's listing record exposes the leaf category only. We checked whether the browse path could supply a parent: on 99 category pages, the first lot's own category disagreed with the page's breadcrumb 55 times, because category pages mix in descendant categories. A derived "subcategory" column would have been wrong more often than right, so it is not shipped.
- A handful of scheduled lots carry placeholder close dates — 9 of 1,000 sat in 2050, 2201 or 3025. That is PropertyRoom's own value and it is passed through unchanged rather than nulled.
listingStatusandsecondsRemainingcan disagree for under a minute at the moment a lot closes: the countdown goes negative before PropertyRoom flips the status code. Both are the site's own values;isOpenrequires both to agree.shippingEstimateUsdof 0 means free shipping or local pickup, not missing data — 26 of the 29 zero-shipping lots in a 200-lot sample were flagged free shipping.- Closed lots are not browsable at all. PropertyRoom drops a lot from its category pages the
second it closes.
listingStatus: "closed"therefore switches to the sitemap by itself and says so inRUN_SUMMARY.warnings. Because the sitemap only carries a closed lot for a short while, this is a recent-results view rather than a sold-price archive. - A narrow filter stops the walk, on purpose, and says so. Browse pages carry 25 lots each and
PropertyRoom has no page-size parameter (seven variants probed, all returned 25), so a filter
that rejects most of the catalogue makes the walk read a lot of pages to find a few rows. Two
bounds apply, and both are reported in
RUN_SUMMARY.warningswhen they fire: the walk abandons a category after 40 consecutive pages (1,000 lot cards) that match nothing, and it stops altogether at 0.8 browse pages per row you asked for — the point where page traffic would cost more than the rows it finds are worth. An unfiltered run never comes close: it stops aftermaxLots / 25pages. If you want a wide filter over the whole site, setsourcetositemap, which reads every lot ID in one request instead of 25 at a time.
🌐 Proxy — read this one
PropertyRoom sits behind CloudFront, and it rejects Apify's shared datacenter exits.
| Pool | Result |
|---|---|
| Apify RESIDENTIAL, country US | HTTP 200 on 20 of 20, and on 1,000+ requests across every run since. Zero blocks. |
| Apify shared datacenter | HTTP 403 with a CloudFront block page on 3 of 9 requests. A full run on this pool aborted on its first page. |
Residential + US is the schema default, so you get it automatically. If you clear it, the run fails fast with a message naming the cause and the fix rather than returning an empty dataset. The Actor also treats a 200 that carries a CloudFront block page as a transport failure, not an empty category — that distinction is what stops a blocked run from looking like a small marketplace.
❓ FAQ
Does it get the current bid?
Yes, on every row. PropertyRoom's listing HTML does not contain it — the bid comes from the page's
own GetClientListings endpoint, which also supplies the bid count, bid increment, close time and
status. 1,000 of 1,000 rows on a live run.
Can I get the realised price on lots that have finished?
Yes, for recently closed lots. Set listingStatus to closed and the run switches to the sitemap
automatically, because PropertyRoom removes a lot from its browse pages the moment it closes — a
catalogue walk would read all 384 pages and find nothing (measured: 587 seconds, 0 rows, before
this was fixed). Closed lots linger in the sitemap for a while afterwards, so this is a
recent-results view, not a historical archive. soldPriceUsd fills when the lot actually received
a bid; a closed lot with zero bids reports its opening ask as currentPriceUsd and
soldPriceUsd: null, because nobody bought it.
Does it tell me which police department the item came from?
No, and no scraper can: PropertyRoom does not publish it on a listing. See What this Actor does
not claim above for what was probed and the three fields you get instead. What you do get is
CLIENT_AGENCIES — the 45 agencies PropertyRoom names on its own partners page — as a separate
reference record, never joined onto a row.
A competing listing advertises a "seller agency" field. What is that?
It is the consignor's pickup-facility name, which that Actor's own README defines as exactly that
and whose own example value is "GC Pawn" — a pawn shop. It is the same field this Actor ships as
sellerName, filled on 1,000 of 1,000 rows. Its companion "seller state" is derived from the
facility's ZIP; we read the state straight from the source record instead.
How many lots are on the site? 16,092 open lot URLs in the sitemap on 2026-09-18, of which 99.8% of a random 1,000 were still live. The browsable catalogue reaches 9,568 of them.
Why is the default only the browse catalogue if the sitemap has more?
Because the browse pages are already in closing-soonest order, so a capped run stops after a few
pages: a 25-row run costs $0.0012 of platform usage there against $0.0389 through the sitemap.
Switch source to sitemap the moment you need the 6,524 lots the catalogue omits.
Am I charged for lots my filters reject? No. Filters run against a batched feed costing about 480 bytes a lot, before any per-lot request.
Is there a run-start fee? No. If nothing matches, the run costs you nothing.
What happens if a lot ID does not exist?
It is recorded in RUN_SUMMARY.notFound and charged nothing. IDs that answer but publish no record
go in noRecordPublished; lots we could not reach after retries go in unreachable. The three are
kept apart on purpose — they mean different things to a buyer working a list.
How fresh is the bid?
It is read at run time, seconds before the row is written. scrapedAt records the moment, and
secondsRemaining is the countdown at that moment.
Can I monitor a watchlist cheaply?
Yes — pass lotIds. That skips enumeration entirely and costs one batched request plus one detail
call per lot.
Can I turn the detail fetch off?
Yes, fetchDetails: false. It is about five times faster, but 33 fields come back null and the
price per row is the same, so it only makes sense for a pure price sweep over lots you have already
profiled.
Does it work without a proxy? No. CloudFront blocks the platform IP and the shared datacenter pool. Use Apify Proxy on RESIDENTIAL with country US — which is what the input schema already fills in.
What is consignorAccountCode for?
Grouping. On PropertyRoom's own lots it separates one agency consignment from another, so you can
tell a 40-lot police batch apart from the rest of the day's inventory even though neither is named.
⚖️ Source and legal
- Source: public listing pages on
propertyroom.com, its public XML sitemap, and the public JSON endpoints those pages call (/ajax/ajax.svc/GetClientListings,/ajax/ajax.svc/GetListing). No login, no account, no credentials. Only data PropertyRoom serves to any visitor. robots.txt, quoted verbatim as of 2026-09-18:
This Actor reads the sitemap,User-agent: *Disallow: /my-items.aspx?*Disallow: /error.aspx?*Disallow: /watchlist.aspx?*Disallow: /catalognew.aspx?*Disallow: /userlogin.aspx?*Disallow: /bidhistory.aspx?*Disallow: /searchresult.aspx?*Disallow: /account/Disallow: /watchlist/Disallow: /activity//c/category pages and/ajax/ajax.svc/endpoints. None of those paths appears in that list, and there is noCrawl-delaydirective.- Why this data is public in the first place: police and municipal unclaimed or seized property must generally be disposed of by public auction under state statute — for example New York Personal Property Law §253, California Civil Code §2080.6 and Florida Statutes §705.103. PropertyRoom is the contracted auctioneer for many of those agencies. The listing, its price and its consignor block are the public face of a statutory sale.
- Contact data: the consignor block is business contact information a seller publishes on its
own listings.
highBidderLocationis the city and state PropertyRoom itself displays next to a bid, with no name attached. No personal identifiers are collected. - You are responsible for how you use the output, including any applicable terms of service and data-protection law in your jurisdiction.
Built and measured on 2026-09-18. Every count, fill percentage and cost figure on this page came from running this Actor, not from an estimate.