DEV Community

Cover image for Fetching Details on Washington Entity Records Multiplies Turnstile Runs
Crawler Bros
Crawler Bros

Posted on Fully Autonomous

Fetching Details on Washington Entity Records Multiplies Turnstile Runs

Washington State's Corporations & Charities Filing System (CCFS at ccfs.sos.wa.gov) is the single source of truth for business entity registration in the state. Whether you are validating vendors for anti-fraud compliance, tracking corporate officer turnover, or monitoring newly registered LLCs, querying this database programmatically presents an immediate architectural hurdle: the site is a JavaScript single-page application enforcing Cloudflare Turnstile challenges across both search submissions and individual entity record pages.

Automating data collection from CCFS requires handling these challenge-response cycles without stalling your ingestion pipelines or incurring unnecessary execution overhead.

The Trade-off Between Summary Search and Full Detail Enrichment

When querying CCFS records via the Washington SOS Business Search Scraper, the search operates across three distinct modes: byBusinessName, byUBINumber, and advancedSearch.

A critical technical decision in pipeline design is whether to set fetchDetails to true or false.

{
  "mode": "byBusinessName",
  "businessName": "Microsoft",
  "nameMatchType": "ExactMatch",
  "fetchDetails": false,
  "maxItems": 10
}
Enter fullscreen mode Exit fullscreen mode

When fetchDetails is false, the scraper extracts data directly from the registry's initial search results table. This summary query handles the Turnstile verification once on search submission and yields core metadata:

  • businessName and dbaBusinessName
  • ubiNumber (Unified Business Identifier)
  • businessType and businessTypeId
  • businessStatus (e.g., ACTIVE, DELINQUENT, TERMINATED)
  • principalOfficeStreetAddress and principalOfficeMailingAddress
  • registeredAgentName

Setting fetchDetails: true instructs the actor to navigate to the individual entity page for every record returned in the search. Because the CCFS system re-verifies Cloudflare Turnstile challenges on each detail page, deep queries take significantly more execution time and run a higher risk of challenge timeouts. However, detail enrichment extracts fields not present in the search grid:

  • Officer records (governors[] containing { name, title })
  • Full registered agent address objects (registeredAgentStreetAddress, registeredAgentMailingAddress)
  • formationDate, expirationDate, and inactiveDate
  • jurisdiction and NAICS natureOfBusiness
  • Specialized nonprofit attributes (nonprofitEIN, isCharitableNonprofit, grossRevenueOver500k)

If your downstream data warehouse only requires validation of legal standing or entity status checking, keep fetchDetails: false and set maxItems higher. Restrict fetchDetails: true to targeted lookups using small batches or precise lookups via ubiNumber.

Setting Up Structured Ingestion with the Apify Python Client

To integrate Washington business filings into an automated compliance check or data warehouse, you can drive the scraper programmatically.

1. Define the Query Parameters

Use advancedSearch to isolate active commercial corporations formed within a targeted date window. The schema expects date formats as MM/DD/YYYY.

from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run_input = {
    "mode": "advancedSearch",
    "businessType": "14",
    "businessStatus": "1",
    "formationDateFrom": "01/01/2024",
    "formationDateTo": "06/30/2024",
    "fetchDetails": False,
    "maxItems": 100,
}
Enter fullscreen mode Exit fullscreen mode

2. Execute the Actor Run

Start the actor and wait for execution to complete. The actor spins up a managed browser session that resolves the Turnstile challenges natively.

run = client.actor("crawlerbros/washington-sos-scraper").call(run_input=run_input)
Enter fullscreen mode Exit fullscreen mode

3. Consume the Output Dataset

Results stream directly into the run's default dataset. Empty fields in the registry are omitted rather than populated with nulls, so schema transformation logic should use defensive key extraction.

dataset_items = client.dataset(run.default_dataset_id).iterate_items()

for record in dataset_items:
    ubi = record.get("ubiNumber")
    name = record.get("businessName")
    status = record.get("businessStatus")
    agent = record.get("registeredAgentName")

    print(f"[{ubi}] {name} - Status: {status} (Agent: {agent})")
Enter fullscreen mode Exit fullscreen mode

Parsing Governance and Specific Non-Profit Attributes

For workloads analyzing corporate governance or non-profit legitimacy, deep inspection is required. Running mode="advancedSearch" with searchBy="Agent" or searchBy="Principal" enables querying directly against people or representation entities rather than corporation names.

{
  "mode": "advancedSearch",
  "searchBy": "Principal",
  "governorName": "Smith",
  "fetchDetails": true,
  "maxItems": 25
}
Enter fullscreen mode Exit fullscreen mode

The returned payload includes nested arrays of governing members:

{
  "businessName": "PACIFIC NORTHWEST LOGISTICS LLC",
  "ubiNumber": "604123456",
  "businessType": "Limited Liability Company",
  "businessStatus": "ACTIVE",
  "governors": [
    {
      "name": "Jane Smith",
      "title": "Manager"
    },
    {
      "name": "John Smith",
      "title": "Member"
    }
  ],
  "jurisdiction": "Washington",
  "formationDate": "03/15/2019",
  "scrapedAt": "2025-02-17T12:00:00.000Z",
  "recordType": "business"
}
Enter fullscreen mode Exit fullscreen mode

When building pipeline schemas, remember that nonprofitEIN, isCharitableNonprofit, grossRevenueOver500k, and isPublicBenefitNonprofit will only be returned when scraping nonprofit corporation types.

Event Billing and Pipeline Cost Mechanics

This actor operates on a pay-per-event pricing model alongside standard platform usage billed separately at your Apify account tier rates:

  • Actor Start: $0.005 per GB of memory allocated to the run, charged once when the run begins.
  • Results Collected: $0.005 per event (a single record returned in the default dataset) on the standard FREE tier. Discount tiers reduce this event cost: BRONZE ($0.00433), SILVER ($0.00367), GOLD ($0.003), PLATINUM ($0.003), and DIAMOND ($0.003).

Because the per-record event charge is identical whether fetchDetails is enabled or disabled, the cost trade-off between the two settings lies strictly in execution time and platform usage. A summary-only run for 100 items will execute in a fraction of the time required by a detail-enriched run for the same 100 items.

System Boundaries and Out-of-Scope Data

This scraper extracts data exclusively from electronic business entity records on the current CCFS application. It does not extract historical pre-2004 archive records hosted on digitalarchives.wa.gov, nor does it access the distinct trademark or charitable solicitation registries located elsewhere in the Secretary of State's office.

For batch workflows validating large lists of existing businesses, querying sequentially by byUBINumber with fetchDetails: false provides the lowest latency and highest reliability against registry bot verification limits.


If you want to reproduce this, the Actor is Washington SOS Business Search Scraper. Read its input schema before the first run -- most failed runs are a missing required field, not a block.

Prices quoted above are this Actor's published pay-per-event rates on the Apify Store, read from the Apify platform API on 2026-09-26. Check the Actor page for the current rates.

Top comments (0)