County and court
portal scraping,
delivered daily.
The records are public. Getting them out, every day, without a person clicking through a clerk’s site, is the hard part. We build the scraper, skip trace it if you want, check it before it reaches you, and fix it when the portal changes. Judgments, probate, mortgage and divorce records, plus foreclosure and UCC wherever a portal publishes them.
We reply within 24 hours. Free pilots go to businesses we select, based on the data you need and your business needs, and the sheet arrives within 7 days. No call required, no contract, you keep the data either way. One pilot per company.
One portal in. A checked file out.
Portal
One form-gated public portal. Usually a platform we already know.
- Identify the vendor platform behind it
- Session, disclaimer and login flow
- Decide scrapeable, hard, or no, and say which
Extraction
The hard part. Caps, captchas and session state, handled per portal.
- Date-range chunking under result caps
- Captcha and bot-protection handling
- Polite throttling, resumable runs
Filter & dedupe
Record type, date window, entity filtering, and dedupe against what you already have.
- Drop corporate and government parties
- Plaintiff / defendant split
- Dedupe by case id and party
Skip trace, enrich, validate
Optional. A raw name becomes a validated phone, or it gets dropped.
- Address, phone and age lookup
- Line type, activity score, output ready for your DNC scrub
- Property-owner match where it applies
Delivery
Into the thing you already use. Checked before it lands, not after.
- Google Sheets, CSV, XLSX
- Job API, or a search app
- Validation gate blocks a bad month
On the biggest pipeline, every month runs ten named checks before anything uploads: every record has its full party list, every name got looked up, every match row has an address. A month that fails its checks is not delivered. It is fixed, then delivered.
Examples of the work.
Each entry names the county, the portal, the thing that made it hard, and what came out. Open one for the full record to see the counts, how they are known, and the field names actually captured.
9 filed records.
Broward County, Florida
Recorded certified final judgments, joined to property ownership
55,661Judgment rowsA 124-day search cap, and an export that silently drops every co-defendant.
124-day capCloudflareProperty match10 QA checksOpen the recordClose the record- Portal
- Clerk of Courts Official Records (AcclaimWeb) → County Property Appraiser
- Delivered as
- Google Sheets, one county tab rebuilt per validated month, plus CSV on disk
What made it hardThe portal caps every search at 124 days, pages the grid at 1,000 rows, and its own CSV export carries only the first name on each side of a document, so co-defendants silently disappear from the file you get.
How it was beatenRanges chunked into month windows under the 124-day cap, then one extra call per judgment to the document-details endpoint to pull the complete party list. Cloudflare passed with Chrome TLS impersonation, no browser, with the per-document call throttled to 1.0s (0.4s drew 403s on long runs). After a block it cools down 60s, then 180s, and reopens a fresh session. Every defendant is then searched against the property appraiser under two name forms and the hits merged by folio.
- Judgment rows
- 55,661
- Validated months
- 104
- Debtor-with-property rows
- 22,914
- QA checks per month
- 10
file-verifiedFields captured- DirectName
- IndirectName
- RecordDate
- DocTypeDescription
- InstrumentNumber
- BookType
- BookPage
- DocLegalDescription
- Consideration
- CaseNumber
- AllDirectNames
- AllIndirectNames
- bcpa_match_type
- bcpa_folios
- bcpa_owners
- bcpa_addresses
Jan 2017 – Aug 2025, contiguous. Property matches are name-based, so multi-match rows are candidate properties, not confirmed ownership.
Cook County IL · Kent County MI · DeKalb County GA
Recorded mortgages and mortgage-related deeds
57,501Raw rows, single runsA silent 1,000-result cap, so a month-long query quietly returns a third of the month.
1,000-result cap7-day chunking3 countiesOpen the recordClose the record- Portal
- Three county recorder platforms: Clerk CRS, Tyler self-service deeds, LandmarkWeb
- Delivered as
- CSV, filtered and delivered in batches
What made it hardCook's recorder silently caps each search at 1,000 results. A month-long query looks like it worked and quietly returns a third of the month.
How it was beatenEvery month split into 7-day windows to stay under the cap, with an anti-forgery token pulled per session. DeKalb needs a disclaimer-acceptance POST and session continuity before it will answer; Kent needs a form submit then paged results. One shared scraper base class carries the range helpers, the corporate-entity filter and resumable runs across all three.
- Raw rows, single runs
- 57,501
- Cook County IL
- 33,696
- Kent County MI
- 16,117
- DeKalb County GA
- 7,688
file-verifiedFields captured- county
- state
- doc_number
- recording_date
- amount
- grantor_1
- grantor_2
- grantor_3
- grantee_1
- grantee_2
- property_address
- legal
Raw rows from single runs. Filtering to individual grantors inside an amount band cuts these substantially before anything is enriched.
Shelby County, Tennessee
Tax sales with excess proceeds and redemption deadlines
10,494Parcel rowsA decade of sale books as PDFs, with the layout changed four times across them.
PDF parsing5 parsersExcess proceedsOpen the recordClose the record- Portal
- County tax-sale Sale Book PDFs
- Delivered as
- Styled XLSX workbook
What made it hardA decade of sale books published only as PDFs, and the county changed the page layout four times across them. One parser reads 2015 and returns nothing for 2020.
How it was beatenFive separate layout parsers, auto-detected per document, over 38 hard-coded sale-book URLs spanning sale numbers TS 1301 to TS 2201. Header dates parsed per book and redemption deadlines resolved from them.
- Parcel rows
- 10,494
- Sale books parsed
- 37
- Rows with excess proceeds
- 2,259
- Layout parsers
- 5
file-verifiedFields captured- Parcel ID
- Taxpayer Name
- Property Address
- Sale Amount
- County Tax Owed
- City Tax Owed
- Total Tax Owed
- Excess Proceeds
- Redemption Period
- Redemption Deadline
- Sale Dates
- Order Confirming Date
- Tax Year
- Sale Number
- Purchaser
Tax years 2015–2024. The optional Chancery Court status cross-check did not run on this export, so that column is empty.
Georgia, statewide probate portal
Probate estate filings with their court-document PDF links
625Input casesA grid that only moves by postback, and estates needing 227 document-link columns.
ViewStateTelerik gridParallel runsOpen the recordClose the record- Portal
- ASP.NET WebForms with Telerik RadGrid, with viewstate and postbacks
- Delivered as
- CSV with PDF URLs
What made it hardA grid that only moves by postback, a case match that has to be verified rather than trusted, and estates carrying so many documents the output needed 227 separate link columns.
How it was beatenBrowser-driven form search with grid pagination, each result verified against the case id before its detail page is scraped for PDF links. Several browsers run in parallel and append to one CSV safely using file locks, with resumable runs and a not-found extractor.
- Input cases
- 625
- Result rows
- 608
- Columns per row
- 257
- Rows with a document link
- 595
file-verifiedFields captured- the client's own input columns, preserved
- filing detail columns
- 227 court-document PDF link columns
The number of distinct Georgia counties in that run was not computed.
27 states + DC
Judgment and case-search modules, one per jurisdiction
125Modules builtEvery county is a different portal, and the ones that matter are gated.
125 modules53 shared helpers49 solversOpen the recordClose the record- Portal
- Tyler SmartSearch, CaseLook, CivilPublic, BenchmarkWeb, CountySuite, CTrack and others
- Delivered as
- Async job API returning one unified record schema across every jurisdiction
What made it hardEvery county is a different portal, and the ones that matter are gated: BotDetect image captchas, Cloudflare Turnstile, hCaptcha with a second captcha fired mid-flow, AWS WAF, JSF, Apache Wicket, an arithmetic captcha behind a real login.
How it was beatenA module per jurisdiction over one shared async session pool, all request-based with no browser anywhere in the tree. 53 modules share a vendor helper, so a new county on a known platform inherits a working client instead of starting over.
- Modules built
- 125
- States + DC
- 27 + DC
- Sharing a vendor helper
- 53
- With a solver wired in
- 49
code-verifiedFields captured- party_name
- case_name
- case_number
- case_type
- party_type
- date_filed
- case_detail_id
- case_detail_link
Code-verified only. These are modules built, not counties running today, and no record counts are claimed for any of them without a fresh run.
National
Skip trace, then validation. A raw name becomes a reachable phone or it is dropped
11Enrichment sources wiredA phone number that dials is not the same as a phone number that exists.
Line typeActivity scoreAddress matchOpen the recordClose the record- Portal
- Licensed identity APIs and people-search sources, plus phone validation
- Delivered as
- Merged and deduped CSV, normalized against the client's existing list
What made it hardA phone number that dials is not the same as a phone number that exists. Raw skip-trace output is full of voicemail boxes, non-fixed VoIP, and addresses that do not match the property the record came from.
How it was beatenLookup for current address, phone and age, then a validation gate: line type and activity score per number, voicemail and non-fixed VoIP marked invalid, phone numbers put in one standard format, a second validator as a cross-check, ZIP and area-code allow-lists, an age filter, and a yes/no flag on whether the found address matches the recorded property address. Runs resume by skipping leads already enriched, and failed lookups are refunded rather than billed.
- Enrichment sources wired
- 11
- Cook County: raw → filtered
- 33,696 → 14,800
- → delivered batches
- 2,160
- → final deduped
- 616
code-verifiedFields captured- current address
- phone
- age
- line_type
- activity_score
- phone_verified
- address_match_flag
- identity_score
- last_reported_date
That funnel is one county's absolute counts, not a published pass rate. Yours depends on the record type and how clean the names are.
Franklin County, Ohio
Civil court party records, searched by business name
360,650Data rowsVolume, until the delivery destination becomes the constraint, not the scraper.
360k rowsSheets delivery10M-cell guardOpen the recordClose the record- Portal
- County Common Pleas clerk portal
- Delivered as
- Google Sheets, one tab per court per month, with a 10,000,000-cell guard
What made it hardVolume. A run across roughly 1,870 search terms against one county produces a file large enough that the delivery destination, not the scraper, becomes the constraint.
How it was beatenUnattended resumable runs with failed-term retry files, then a cleaning stage that splits plaintiff from defendant and drops corporate and government parties to leave individuals. Delivery checks the destination workbook's total cell count before writing and stops cleanly rather than failing mid-upload.
- Data rows
- 360,650
- Unique case numbers
- 218,348
file-verifiedFields captured- search_term
- case_number
- case_type_category
- party_name
- party_type
- case_title
- filing_date
- status
Party-per-case rows, not deduplicated unique cases. The unique-case-number figure is the one to compare against.
Missouri, statewide judgment index
Recorded judgments by party name, and a lesson about trusting row counts
682Delivered after dedupeA 2.2 GB file with 9.8 million rows in it, and every row looked legitimate.
DedupeQA catchPagination loopOpen the recordClose the record- Portal
- State case-management judgment index
- Delivered as
- Deduped CSV: the 682, not the 9.8 million
What made it hardThe run produced a 2.2 GB file with 9,797,294 rows in it. It was not 9.8 million judgments. It was a pagination loop returning the same records over and over, and every row looked completely legitimate.
How it was beatenAn audit that counts distinct case ids rather than rows. 9,797,294 rows held 739 distinct case ids and two distinct search terms. Deduped properly, the real deliverable was 682 rows. This is why the delivered number and the scraped number are never the same number, and why a file that looks big is not evidence of anything.
- Raw rows produced
- 9,797,294
- Distinct case ids in them
- 739
- Delivered after dedupe
- 682
file-verifiedFields captured- search_term
- party_name
- first_name
- middle_name
- last_name
- case_id
- filing_date
- judgment_date
- judgment_desc
- judgment_amount
- style_of_case
- case_type
- county
- circuit
- scraped_at
Included because it is the failure that teaches the most. The raw figure is never quoted as volume.
Shelby County, Tennessee
A delivered search tool, not a file drop
2Search modesA portal that repeats its last page forever, so a naive pager never stops.
Next.js appPassword gateCSV + XLSXOpen the recordClose the record- Portal
- Sheriff's warrants portal, productized
- Delivered as
- Deployed password-gated web app with CSV and XLSX export
What made it hardThe portal repeats its last page forever instead of returning an empty one, so a naive pager never stops. And the client did not want a CSV. They wanted to search it.
How it was beatenPagination terminates when a page's warrant-number set matches the previous page. Desktop view first, mobile view as fallback, with a session warm-up to collect cookies before the POST. The scrape was then reimplemented in TypeScript inside a Next.js route so it runs serverless, behind a shared-password cookie gate, with CSV and Excel export in the browser.
- Search modes
- 2
- Parallel implementations
- 2
- Export formats in-browser
- 2
code-verifiedFields captured- warrant_number
- issue_date
- name
- age
- sex
- address
- city
- state
- zip
- charge
- bond
Live query volumes are not claimed. Only a small sample export exists on disk.
No client is named anywhere on this page, and no screenshot of real output exists on it. The datasets behind this work contain real people’s names and addresses, and those stay out of marketing material, including yours, when you become one of them.
What the hard portals need.
These are not features. They are the specific things that stand between a public record and a file on your desk, and each one has cost us time before.
- Captcha handling
- reCAPTCHA v2 and v3, hCaptcha, Cloudflare Turnstile, BotDetect distorted-text images, and audio challenges. Solved through commercial solver APIs with retry and fallback routing, and in one case through the protection vendor's own public challenge endpoint with no paid solver at all.
- Bot protection on public portals
- Cloudflare, Akamai, Imperva, DataDome, PerimeterX, AWS WAF and Dynatrace have all come up. Passed with Chrome TLS and HTTP fingerprint impersonation rather than a browser, with the exact header set and header ordering a real client sends. Some targets accept solved cookies replayed locally; others only answer through the solver's own forward path, so the replay route gets tested per site.
- Proxies and session shaping
- A rotating pool plus residential proxies with sticky sessions, rotated on a request count, with balance monitoring so a run does not die silently when credit runs out. Session expiry follows IP mismatch, and a blocked run cools down, reopens a fresh session and retries rather than hammering.
- ViewState and session state
- ASP.NET WebForms ViewState and EventValidation round-tripping across dozens of county sites, plus anti-forgery tokens, disclaimer-acceptance steps, Telerik RadGrid postbacks, JSF, Apache Wicket enumeration, ASP.NET AJAX envelope unwrapping, and scripted guest sessions on public portals that ask for one.
- PDF parsing
- Text extraction from published document sets, including multi-layout parsing where a county changed its format across years, and bulk collection of per-case document links. We do not do OCR. Scanned-image documents are outside what we have built, and we will tell you that before you pay for it.
- Date-range chunking
- The single most common reason a portal lies to you. A 124-day search cap chunked into months; a silent 1,000-result cap split into 7-day windows; 3-day chunks recursively halved when a chunk still hits the ceiling. A grid-versus-export row-count check catches the difference.
- Scheduling and monitoring
- Scheduled daily runs with a duplicate-send guard, timestamped run logs per month, progress files that let a half-finished run resume where it stopped, failed-term retry files, and per-source circuit breakers so one dead dependency does not take the whole pipeline with it.
- QA before delivery
- Why it matters over time. On the judgment pipeline every month runs 10 named checks before anything uploads: every record has its full party list, every name got looked up, every match row has an address. A month that fails its checks is not delivered. It is fixed.
The shape of a delivered file, with placeholder values. Real columns depend on what the portal exposes. The field list comes with the pilot, before you commit to anything.
| recording_date | instrument_no | party_name | amount | phone | line_type | addr_match |
|---|---|---|---|---|---|---|
| 2026-03-04 | A-0000001 | SAMPLE, ALEX Q | $184,000 | 555-0100 | mobile | Yes |
| 2026-03-04 | A-0000002 | EXAMPLE, BRETT | $96,500 | 555-0101 | landline | No |
| 2026-03-05 | A-0000003 | PLACEHOLDER, C | $241,750 | n/a | n/a | n/a |
| 2026-03-05 | A-0000004 | TESTCASE, DANA | $133,200 | 555-0103 | mobile | Yes |
Every value above is made up. We do not put real records in marketing material, and we will not put yours in ours either.
One free pilot. Then pricing starts at $1,500.
The price depends on how often you need the data, how complex it is to get, how many portals are included, and how much support you will need. You should not have to book a call to find out where pricing starts.
Free pilot
One portal, one record type, covering the most recent 7 days of records. We reply within 24 hours. If we select you, the sheet arrives within 7 days. Pilots go to businesses we want to work with, based on the data you need and your business needs. No call, no contract, you keep the data either way.
- The sheet, and the field list
- A one-page note on what the portal does and does not expose
- What it would cost to run daily
- One pilot per company
Ongoing feed
Portals built and run on a schedule, with maintenance included, so a portal change gets fixed instead of silently breaking your data.
- How often you need the data
- How complex it is to get
- How many portals are included
- How much support you will need
- Scheduled runs, delivered to Sheets, CSV, API or your CRM
- Validation gate before delivery
- Fixes when a portal changes
Skip tracing and phone validation can be added to any feed and are quoted with it.
The questions worth asking first.
Including the ones most vendors would rather you asked after signing.
Can you do my county?
Send the link. We will look at what it is built on and reply within 24 hours with whether it is doable: yes and it is straightforward, yes but it is hard, or no and why. It costs nothing to ask.
Most county portals run on one of a handful of vendor platforms, and we have already built against Tyler Odyssey and SmartSearch, AcclaimWeb, LandmarkWeb, Fidlar Ava, BenchmarkWeb, CaseLook, CountySuite, CTrack, OSCN, CaseNet, MiCOURT and more. If yours is one of those, a build usually takes days. Our judgment and case-search work alone spans 27 states and DC.
Is this legal?
The records are public records from public portals. You are paying for collection and delivery, not for access to anything restricted.
We rate-limit politely and we do not create fake accounts. We do not break into anything that is meant to restrict access. Some public portals put a captcha or a bot check in front of public records, and getting past those is part of the build. Each portal has its own terms. If one forbids automated collection, we tell you that instead of quietly doing it, and we price a manual or licensed alternative.
What can the contact data be used for?
Your own marketing and business-development outreach. That is the line, and it goes in writing in every proposal.
It cannot be used for credit, insurance, employment, tenant-screening or any other FCRA-regulated decision. We are not a consumer reporting agency and this is not a consumer report. We do not collect motor-vehicle records, which is where the DPPA applies.
On phones: we deliver numbers with line type and an activity score so you can drop the dead ones. Checking numbers against the national and state do-not-call lists, honoring revocations, and consent for any automated dialing stay on your side. That is TCPA, and it is your call to make, not ours.
What types of documents and records can you collect?
UCC filings, probate, mortgage, divorce, foreclosure and judgment records, among others. It comes down to two things: whether a portal for that record type exists, and whether the data you want is actually published there.
We have built against judgments, probate, recorded mortgages and divorce (domestic-relations) cases. UCC and foreclosure portals we would scope as new work and tell you so before you commit. If a portal does not publish it, we cannot collect it.
Will you work with everyone?
No, and we may not work together. We are looking to work with specific businesses: ones that already know which counties and record types they need and would put a daily feed to work.
Free pilots go to the businesses we select, based on the data you need and your business needs. If we are not the right fit, we will tell you so instead of taking on work we would not do well.
Who owns the data?
You do. The output is yours, including from a free pilot, whether or not we work together afterward.
If we stop working together, you keep every record we have already delivered.
What happens when the portal changes?
It will. Keeping a feed working through those changes is what maintenance covers, and it is the real reason in-house setups fail. The scrape is not the hard part. The hard part is noticing when it quietly stops being complete.
Every delivery goes through a validation step that runs named checks and blocks a month that fails them. A broken month arrives as a fix, not as a clean-looking file missing half its records.
What can't you do?
If the data is not in the portal, we cannot collect it. We only extract what a portal actually publishes. A court judgment search shows the case number, the parties, the filing date and the amount. It will not show the debtor's bank balance. We cannot collect it, and no skip trace will find it either. A phone number is different: the court does not publish it, but a skip trace can often find it from other sources.
No OCR. If the documents you need are scanned images rather than text, that is not a capability we have built, and we will say so before you pay for it.
No guaranteed uptime and no claim that any specific portal is live today without a fresh run. For record types we have not built against yet, such as UCC and foreclosure portals, the first build is new work and we say so up front.
No data on anyone for a decision about their credit, housing, insurance or job. If that is the use case, we are the wrong vendor and we will say so in our first reply.
How fast?
A pilot county within 7 days of being selected. We say that only because single-county runs genuinely are that size. A single run of one recorder portal in this portfolio produced between 7,688 and 33,696 raw rows, and that is a day or two of work.
A full build with history backfilled is longer, and the portal decides how much longer. A JSON API is hours. A captcha-gated WebForms site with result caps is days.
Tell us the county that
wastes the most of your week.
We reply within 24 hours. If we are a fit, we’ll pull the most recent 7 days of records from it and send you the sheet, free, within 7 days, based on the data you need and your business needs. No call, no contract. If it is useful we talk. If it is not, you keep the data.
You get the people who wrote the code, with nobody between you and a fix.