PropertyRoom Scraper - Police Auction Lots & Consignors avatar

PropertyRoom Scraper - Police Auction Lots & Consignors

Pricing

$0.90 / 1,000 per lot returneds

Go to Apify Store
PropertyRoom Scraper - Police Auction Lots & Consignors

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

Scrapers Delight

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

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_AGENCIES record. 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:

  1. 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).
  2. Hydrate the live state in batches. PropertyRoom's GetClientListings endpoint 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.
  3. Filter and sort here, on data that cost about 480 bytes a lot.
  4. 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 reachable9,568 (383 pages, walked exhaustively)16,092
Lots only this path reaches6,524
Ordered by the site?Yes, closing soonestNo
Platform usage, 25-row run$0.0012$0.0389
Fixed cost before the first row~$0.0000~$0.047
Pays for itself fromany sizeabout 100 rows
Best foreveryday runs, one department, capped runscompleteness, 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

ModelPay per event — one event, lot-scraped
Price$0.0009 per lot delivered ($0.90 per 1,000)
Run-start feeNone
Charged for filtered-out lotsNo — they are dropped before any per-lot request
Charged for IDs that do not existNo
Charged for lots we could not reachNo
Charged for a run that matches nothingNo

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"
}
}
FieldTypeDefaultWhat it does
sourcestringcataloguecatalogue walks browse pages (9,568 lots, cheap, pre-ordered). sitemap reads the full census (16,092 lots).
categoriesarrayall itemsCategory 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.
lotIdsarrayRe-check known lots and skip enumeration entirely. Overrides categories.
listingStatusstringanyopen · scheduled · closed. Measured on 1,000 random lots: 580 open, 418 scheduled, 2 closed.
auctionFormatsarrayallAuction (753 of 1,000) · Fixed Price (233) · Reserve Auction (11) · Bid to be Approved Auction (3).
bidStatestringanynoBidsYet · hasBids. 58 of 1,000 random lots had a bid.
minCurrentPrice / maxCurrentPriceintegerPrice band. Median price across 1,000 lots was $32; the highest was $3,999.
maxBidCountintegerSkip lots that already have a bidding war.
closingWithinHoursintegerThe "what can I still win today" filter.
titleContainsarrayKeywords, OR-ed, case-insensitive.
sortBystringendingSoonestendingSoonest · endingLatest · priceLowest · priceHighest · mostBids · newestListed · asListed.
maxLotsinteger50Hard cap on rows delivered and charged.
fetchDetailsbooleantrueOff skips the per-lot record: about five times faster, but 33 fields come back null at the same price.
includeClientAgenciesbooleantrueWrites 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.
concurrencyinteger8200 detail calls at 8 took 25.6 s with zero errors.
proxyConfigurationobjectApify RESIDENTIAL, USSee 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

FieldFillWhy it is not 100%
itemNumber999 / 1,000One lot had none.
consignorAccountCode859 / 1,000Not every SKU starts with PropertyRoom's four-digit account prefix.
sellerPhone598 / 1,000Some consignors publish no phone. Blank, never invented.
weight / weightUnit593 / 1,000PropertyRoom writes 0 for "not recorded"; a 0 lb parcel is not a fact, so it is null and the unit goes with it.
condition464 / 1,000Condition is free text inside the description, not a field. Parsed where stated, null where not.
itemLocation407 / 1,000Published mainly on PropertyRoom's own lots.
highBidderLocation / highBidderMemberSince232 / 1,000Only exists once a lot has a bid: 232 of the 236 rows that had bids carried it.
soldPriceUsd0 / 1,000This 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 no GetSeller, GetMerchant or GetAgency; /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 (sellerId 1), which is the channel its public-agency clients are disposed through. The two agree on 197 of 200 random lots, and the sellerName on these is the PropertyRoom warehouse handling the lot ("Ontario, California", "Frederick, MD", "Ronkonkoma, New York"), not the agency.
    • consignorAccountCode — the four-digit prefix of itemNumber. 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/partners page 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/linking names five more that publish their own auction page. This Actor writes that roster to a CLIENT_AGENCIES key-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 with includeClientAgencies: false.
  • PropertyRoom's own "police items" view does not filter. cat.aspx?policeitems=true returns 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.txt disallows /searchresult.aspx, so titleContains filters 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.
  • listingStatus and secondsRemaining can 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; isOpen requires both to agree.
  • shippingEstimateUsd of 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 in RUN_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.warnings when 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 after maxLots / 25 pages. If you want a wide filter over the whole site, set source to sitemap, 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.

PoolResult
Apify RESIDENTIAL, country USHTTP 200 on 20 of 20, and on 1,000+ requests across every run since. Zero blocks.
Apify shared datacenterHTTP 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: 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:
    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/
    This Actor reads the sitemap, /c/ category pages and /ajax/ajax.svc/ endpoints. None of those paths appears in that list, and there is no Crawl-delay directive.
  • 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. highBidderLocation is 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.