# Virginia Real Estate License Lookup (`automation-lab/virginia-real-estate-license-lookup`) Actor

Download and filter official Virginia DPOR active and inactive real estate broker and salesperson license records.

- **URL**: https://apify.com/automation-lab/virginia-real-estate-license-lookup.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Virginia Real Estate License Lookup

Download and filter official Virginia Department of Professional and Occupational Regulation (DPOR) real estate credential files. The Actor turns the regulator's active and inactive broker and salesperson lists into normalized JSON records for verification, compliance exports, and scheduled refreshes.

It covers four roles published by the Virginia Real Estate Board:

- associate brokers;
- sole proprietors;
- principal brokers;
- salespeople.

Choose active, inactive, or both status groups. Every result includes its exact official source file and fetch time.

### What can you do with this DPOR license lookup?

- Check supplied certificate numbers against official bulk records.
- Export active Virginia broker and salesperson credentials.
- Review inactive license records separately from active records.
- Filter licensees by name, city, state, ZIP code, dates, or public email availability.
- Build repeatable brokerage due-diligence and compliance snapshots.
- Send normalized records to a spreadsheet, database, CRM, or data warehouse.
- Schedule the same input to compare official files over time.

This Actor downloads regulator-published files. It does not automate the slower one-record-at-a-time DPOR search page.

### Who is this Actor for?

**Brokerage compliance teams** can create bounded lists of active or inactive credentials and retain source provenance.

**Property firms and vendor-risk teams** can verify batches of names or certificate numbers before onboarding or periodic review.

**Data analysts** can normalize DPOR tab-delimited files without maintaining custom parsing and date conversion code.

**Developers** can call one Actor API and receive stable JSON instead of downloading and joining eight source files.

**Operations teams** can schedule a saved Task and compare dataset exports between runs.

### Why use this Virginia real estate license Actor?

- **Official source:** all primary records come from public Virginia DPOR Real Estate Board regulant files.
- **Active and inactive separation:** status is derived from the regulator's named active or inactive list, not guessed from expiration dates.
- **Role-aware output:** associate broker, sole proprietor, principal broker, and salesperson lists are normalized consistently.
- **Fail-closed parsing:** a changed header or unexpected response stops the run instead of silently producing misleading fields.
- **Batch filters:** narrow thousands of public records in one run.
- **Traceable results:** `sourceUrl`, `sourceFile`, and `fetchedAt` accompany every item.
- **Lightweight execution:** direct HTTP is used; no browser or proxy configuration is required.

### What Virginia license data is extracted?

| Field | Meaning |
| --- | --- |
| `certificateNumber` | DPOR certificate number preserved as text |
| `licenseStatus` | `active` or `inactive`, based on the official source list |
| `statusSource` | Human-readable DPOR status and role list |
| `role` / `roleLabel` | Normalized and display forms of the credential role |
| `licenseRank` | Source rank such as `BRKR` or `SALP` |
| `individualName` | Licensee name published by DPOR |
| `businessName` | Business value when present in the source row |
| `addressLine1`, `addressLine2`, `poBox` | Source address components |
| `fullAddress` | Combined display address |
| `city`, `state`, `zipCode` | Normalized domestic location fields |
| `province`, `country`, `postalCode` | International address fields when present |
| `issueDate` | Certification date normalized to `YYYY-MM-DD` |
| `expirationDate` | Expiration date normalized to `YYYY-MM-DD` |
| `email` | Public email when DPOR publishes one |
| `boardCode`, `occupationCode` | Source regulator codes |
| `sourceUrl`, `sourceFile` | Exact official file provenance |
| `fetchedAt` | UTC source-fetch timestamp |

Empty source values remain empty strings. The Actor does not invent missing firms, emails, dates, or affiliations.

### How to run the Virginia real estate license lookup

1. Open the Actor in Apify Console.
2. Choose `active`, `inactive`, or both under **License statuses**.
3. Select one or more real estate roles.
4. Add optional certificate, name, location, date, or email filters.
5. Set **Maximum license records** to control output and cost.
6. Click **Start**.
7. Open the default dataset to inspect, download, or integrate the results.

A useful first run is:

```json
{
  "statuses": ["active"],
  "roles": ["associateBroker", "principalBroker", "salesperson"],
  "maxItems": 20
}
```

### Input parameters

| Input | Type | Default | Description |
| --- | --- | --- | --- |
| `statuses` | array | `["active"]` | Official active and/or inactive files |
| `roles` | array | all four roles | Associate broker, sole proprietor, principal broker, and/or salesperson |
| `licenseNumbers` | string array | empty | Exact certificate numbers |
| `names` | string array | empty | Case-insensitive individual-name contains filters |
| `businessNames` | string array | empty | Case-insensitive business-name contains filters |
| `cities` | string array | empty | Exact city matches, case-insensitive |
| `states` | string array | empty | Exact state abbreviations |
| `zipCodes` | string array | empty | Exact five-digit ZIP codes |
| `emailRequirement` | string | `any` | `any`, `withEmail`, or `withoutEmail` |
| `issuedAfter` | date | none | Certification date on or after `YYYY-MM-DD` |
| `issuedBefore` | date | none | Certification date on or before `YYYY-MM-DD` |
| `expiresAfter` | date | none | Expiration date on or after `YYYY-MM-DD` |
| `expiresBefore` | date | none | Expiration date on or before `YYYY-MM-DD` |
| `maxItems` | integer | `100` | Maximum accepted records, from 1 to 75,000 |

Values within one text-list filter use **OR** logic. Different filters use **AND** logic. For example, two cities plus `withEmail` means either city, but only records that have a public email.

### Output example

The default dataset contains one object per accepted credential. This anonymized example preserves the real output shape:

```json
{
  "certificateNumber": "001234",
  "licenseStatus": "active",
  "statusSource": "DPOR Real Estate Active Salesperson",
  "role": "salesperson",
  "roleLabel": "Salesperson",
  "licenseRank": "SALP",
  "individualName": "EXAMPLE A LICENSEE",
  "businessName": "",
  "addressLine1": "100 MAIN STREET",
  "addressLine2": "",
  "poBox": "",
  "fullAddress": "100 MAIN STREET, RICHMOND, VA, 23219",
  "city": "RICHMOND",
  "state": "VA",
  "zipCode": "23219",
  "zipCodeExtension": "0000",
  "province": "",
  "country": "",
  "postalCode": "",
  "issueDate": "2021-02-25",
  "issueDateSource": "02/25/2021",
  "expirationDate": "2027-02-28",
  "expirationDateSource": "02/28/2027",
  "email": "licensee@example.org",
  "boardCode": "02",
  "occupationCode": "25",
  "sourceUrl": "https://www.dpor.virginia.gov/sites/default/files/Records%20and%20Documents/Regulant%20List/0225s_act.txt",
  "sourceFile": "0225s_act.txt",
  "fetchedAt": "2026-08-22T12:00:00.000Z"
}
```

### How much does it cost to look up Virginia real estate licenses?

This is a pay-per-event Actor. Each run has a **$0.005 start fee**, then charges for each accepted `item` written to the dataset. The BRONZE item price is **$0.003444 per license record**, with lower unit prices on higher Apify pricing tiers.

| Apify tier | Price per accepted record |
| --- | ---: |
| FREE | $0.0039606 |
| BRONZE | $0.003444 |
| SILVER | $0.0026863 |
| GOLD | $0.0020664 |
| PLATINUM | $0.0013776 |
| DIAMOND | $0.00096432 |

At the BRONZE tier, example totals are:

| Accepted records | Estimated total |
| ---: | ---: |
| 20 | $0.0739 |
| 100 | $0.3494 |
| 1,000 | $3.449 |

Filters that produce no records incur only the start event. Rejected, duplicate, or failed source rows are not charged as items. Apify platform plan usage can be billed separately under your account terms.

### Scheduled compliance and refresh workflows

A Task can run the same input daily, weekly, or monthly. For recurring verification:

1. Save an input that identifies the needed roles and status groups.
2. Choose a stable `maxItems` appropriate for the expected export.
3. Schedule the Task in Apify Console.
4. Send each dataset to your storage or automation destination.
5. Compare records by `certificateNumber`, `licenseStatus`, and `role`.
6. Use `fetchedAt` and `sourceFile` to retain provenance for each snapshot.

The Actor emits snapshots. It does not calculate changes or send alerts by itself; connect scheduled datasets to your own comparison workflow.

### Export and integrations

The default dataset can be downloaded as JSON, CSV, Excel, XML, or RSS through Apify's dataset API and Console.

Common patterns include:

- append scheduled exports to Google Sheets;
- upsert records into a compliance database by certificate number and role;
- route newly inactive records into a manual review queue;
- enrich an internal roster with official status and expiry dates;
- trigger Make, Zapier, or webhook workflows after a successful run;
- load snapshots into BigQuery, Snowflake, or another warehouse.

Remember that names are not guaranteed unique. Prefer certificate numbers when matching records.

### Run with the Apify API

Replace `YOUR_APIFY_TOKEN` with your token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~virginia-real-estate-license-lookup/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "statuses": ["inactive"],
    "roles": ["salesperson"],
    "cities": ["Richmond"],
    "maxItems": 20
  }'
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const input = {
  statuses: ['active'],
  roles: ['associateBroker', 'principalBroker'],
  expiresBefore: '2027-12-31',
  emailRequirement: 'withEmail',
  maxItems: 50,
};

const run = await client.actor('automation-lab/virginia-real-estate-license-lookup').call(input);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/virginia-real-estate-license-lookup').call(run_input={
    'statuses': ['active'],
    'roles': ['salesperson'],
    'states': ['VA'],
    'maxItems': 100,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with MCP and AI assistants

Add the Actor as an Apify MCP tool in Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/virginia-real-estate-license-lookup"
```

#### Claude Desktop setup

Add this server entry to the Claude Desktop MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/virginia-real-estate-license-lookup"
    }
  }
}
```

#### Cursor setup

Add the same JSON under Cursor **Settings → MCP → Add server**, then authenticate with your Apify account when prompted.

#### VS Code setup

Add the same HTTP MCP server URL through your VS Code MCP extension or workspace MCP configuration.

Example prompts:

- "Download 50 active Virginia principal broker records and show certificate number, name, and expiration date."
- "Find inactive Virginia salesperson credentials with Richmond addresses."
- "Create a CSV-ready export of active associate brokers expiring through the end of 2027."

MCP clients still use your Apify account and the Actor's active pricing.

### Tips for reliable results

- Start with a small `maxItems` while refining filters.
- Certificate numbers are exact matches; preserve leading zeros.
- Name and business filters are case-insensitive substring matches.
- City, state, and ZIP filters are exact after case normalization.
- Select both statuses when checking whether a credential appears in either published list.
- Use date filters for bounded compliance cohorts, not as a substitute for `licenseStatus`.
- Keep source provenance when moving records into another system.
- Schedule refreshes at a cadence appropriate for your business need; the source controls update timing.

### Source limits and failure behavior

The Actor reads the public bulk lists linked from the DPOR Regulant Lists page. Its scope is the eight active/inactive broker and salesperson files, not every Virginia profession.

Important limits:

- DPOR controls publication timing, availability, and field completeness.
- Business names and emails can be empty.
- Public bulk files do not include a complete business-affiliation graph.
- Status means membership in a named active or inactive source list at fetch time.
- The Actor does not infer disciplinary history, renewal eligibility, or good standing beyond published fields.
- A changed file header, non-tabular response, or failed download causes a non-zero run instead of partial silent output.
- No residential proxy or browser fallback is enabled.

### Responsible use and legality

The Actor processes public professional-license records published by a Virginia regulator. You are responsible for your purpose, retention practices, security controls, and compliance with applicable laws and DPOR terms.

Do not use public contact details for harassment, unlawful discrimination, or unsolicited messaging that violates applicable rules. Treat an automated result as a research and workflow aid. For consequential decisions, retain provenance and verify the current record through the official regulator.

This Actor is not affiliated with or endorsed by the Virginia DPOR or Real Estate Board.

### Troubleshooting and FAQ

#### Why did my run return zero records?

The selected filters are combined with AND logic. Remove filters one at a time, check the chosen active/inactive status, and confirm certificate numbers include leading zeros.

#### Why is `businessName` empty?

Many individual DPOR bulk rows do not publish a business name. The Actor preserves the official value and does not infer an affiliation.

#### Does an unexpired date prove the license is active?

No. Use `licenseStatus`, which identifies the official active or inactive file. Dates are separate source fields.

#### Can I search one exact certificate number?

Yes. Put it in `licenseNumbers`. The Actor checks the selected status and role files and emits matching records.

#### Does the Actor include inactive real estate licenses?

Yes. Add `inactive` to `statuses`, or select it alone.

#### Can it monitor changes automatically?

You can schedule repeated runs and compare the resulting datasets. The Actor creates normalized snapshots; change detection and notifications belong in your downstream workflow.

#### What happens if DPOR changes its file format?

The Actor validates the exact expected header and fails with a source-specific schema error. This prevents shifted columns from being presented as valid license data.

### Related automation-lab Actors

- [Virginia DPOR Contractor License Leads Scraper](https://apify.com/automation-lab/virginia-dpor-contractor-license-leads-scraper) for official Virginia Class A, B, and C contractor records.
- [Texas TREC License Holder Search Scraper](https://apify.com/automation-lab/texas-trec-license-holder-search-scraper) for Texas real estate license-holder workflows.
- [New York eAccessNY Real Estate License Scraper](https://apify.com/automation-lab/new-york-eaccessny-real-estate-license-scraper) for New York real estate credential records.

For Virginia real estate records, use this Actor so status, role, dates, public contact fields, and DPOR provenance stay in one consistent dataset.

# Actor input Schema

## `statuses` (type: `array`):

Choose active records, inactive records, or both official DPOR status lists.

## `roles` (type: `array`):

Choose one or more Virginia real estate credential roles.

## `licenseNumbers` (type: `array`):

Return exact DPOR certificate numbers. Leading zeros are preserved.

## `names` (type: `array`):

Return individual names containing any supplied text, case-insensitively.

## `businessNames` (type: `array`):

Return business names containing any supplied text when DPOR publishes a business value.

## `cities` (type: `array`):

Return exact city matches, case-insensitively, such as Richmond or Norfolk.

## `states` (type: `array`):

Return exact address-state abbreviations. Use VA to keep Virginia addresses.

## `zipCodes` (type: `array`):

Return exact five-digit ZIP code matches.

## `emailRequirement` (type: `string`):

Include all records, only records with a DPOR-published email, or only records without one.

## `issuedAfter` (type: `string`):

Keep licenses with a DPOR certification date on or after this date.

## `issuedBefore` (type: `string`):

Keep licenses with a DPOR certification date on or before this date.

## `expiresAfter` (type: `string`):

Keep licenses expiring on or after this date.

## `expiresBefore` (type: `string`):

Keep licenses expiring on or before this date.

## `maxItems` (type: `integer`):

Stop after this many matching records across the selected official lists.

## Actor input object example

```json
{
  "statuses": [
    "active"
  ],
  "roles": [
    "associateBroker",
    "principalBroker",
    "salesperson"
  ],
  "licenseNumbers": [],
  "names": [],
  "businessNames": [],
  "cities": [],
  "states": [],
  "zipCodes": [],
  "emailRequirement": "any",
  "maxItems": 20
}
```

# Actor output Schema

## `overview` (type: `string`):

Open the default dataset table containing certificate, status, role, name, business, public contact, address, date, and provenance fields.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "statuses": [
        "active"
    ],
    "roles": [
        "associateBroker",
        "principalBroker",
        "salesperson"
    ],
    "licenseNumbers": [],
    "names": [],
    "businessNames": [],
    "cities": [],
    "states": [],
    "zipCodes": [],
    "emailRequirement": "any",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/virginia-real-estate-license-lookup").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "statuses": ["active"],
    "roles": [
        "associateBroker",
        "principalBroker",
        "salesperson",
    ],
    "licenseNumbers": [],
    "names": [],
    "businessNames": [],
    "cities": [],
    "states": [],
    "zipCodes": [],
    "emailRequirement": "any",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/virginia-real-estate-license-lookup").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "statuses": [
    "active"
  ],
  "roles": [
    "associateBroker",
    "principalBroker",
    "salesperson"
  ],
  "licenseNumbers": [],
  "names": [],
  "businessNames": [],
  "cities": [],
  "states": [],
  "zipCodes": [],
  "emailRequirement": "any",
  "maxItems": 20
}' |
apify call automation-lab/virginia-real-estate-license-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/virginia-real-estate-license-lookup"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ns8Ae0BhHPWqm64Yp/builds/uYXjEYlSLI9hs5EFD/openapi.json
