# HDL Municipal Business License Registry Scraper (`jungle_synthesizer/hdl-municipal-business-license-registry-scraper`) Actor

Enumerates the active business-license roll of HdL Companies municipal portals (Pomona, Hayward, El Cajon, Tustin and other reachable HdL cities) by business-type code, returning account number, business name, license status, expiry, and address for every license on file.

- **URL**: https://apify.com/jungle\_synthesizer/hdl-municipal-business-license-registry-scraper.md
- **Developed by:** [BowTiedRaccoon](https://apify.com/jungle_synthesizer) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 record scrapeds

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/actors/running/actors-in-store.md#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

## HDL Municipal Business License Registry Scraper

Pull the full active business-license roll from HdL Companies-hosted municipal portals —
Pomona, Hayward, El Cajon, Tustin, and other reachable HdL city instances. Unlike a
name-or-address lookup, this actor walks every business-type category in a city to
reconstruct its **entire** license registry: account number, business name, status,
issue/expiry dates, and address — no prior knowledge of a business required.

***

### HDL Municipal Business License Registry Scraper Features

- Returns the **full active roster** of a city's business licenses, not just a single
  lookup result — covers every business-type category by default
- Multi-city — target one HdL city instance, several, or every reachable one in a single run
- Derived fields the source doesn't compute for you: `license_status` (active/expired),
  `days_to_expiry`, and `is_new_license` (flags licenses issued within a configurable
  lookback window — built for a weekly "what's new" re-run)
- Deduplicates automatically when the same license could otherwise surface twice
- A city that isn't reachable at run time is skipped, not treated as a failure — the rest
  of your requested cities still complete

***

### Who Uses HDL Municipal Business License Registry Data?

- **B2B marketing and lead-generation teams** — prospect newly-licensed businesses before
  they show up anywhere else (a license often predates a website or a state filing)
- **Hyper-local service providers** — find every licensed business in a category and city
- **Commercial real-estate brokers** — track new tenants taking out a local business license
- **RevOps and data teams** — enrich existing lead lists against the official municipal record

***

### How HDL Municipal Business License Registry Scraper Works

1. Choose which HdL cities to crawl (or leave `cities` empty to crawl every known-candidate
   city instance).
2. Optionally restrict to specific business-type codes with `businessTypeIds`, or leave it
   empty to enumerate every business type the city's portal exposes.
3. The actor walks each requested city, category by category, and returns every license on
   file for that combination.
4. Each record is enriched with `license_status`, `days_to_expiry`, and `is_new_license`
   before it lands in your dataset.

***

### Input

```json
{
  "cities": ["pomona"],
  "businessTypeIds": [],
  "newLicenseLookbackDays": 30,
  "maxItems": 500
}
```

| Field                    | Type    | Default | Description |
|--------------------------|---------|---------|-------------|
| `cities`                 | array   | *(all)* | HdL city instances to crawl (e.g. `pomona`, `hayward`). Leave empty for every known-candidate city instance. |
| `businessTypeIds`        | array   | *(all)* | Optional filter: HdL business-type codes to restrict the crawl to. Leave empty to enumerate every business type the city exposes. |
| `newLicenseLookbackDays` | integer | 30      | Licenses with a `start_date` within this many days of the run are flagged `is_new_license: true`. |
| `maxItems`                | integer | 10      | Maximum number of license records to return this run. |
| `resumeCursor`           | string  | *(none)* | Cursor from a previous run's Output — continue where a large run stopped. |

***

### HDL Municipal Business License Registry Scraper Output Fields

```json
{
  "jurisdiction": "pomona",
  "jurisdiction_subdomain": "pomona",
  "account_number": "00207651",
  "business_name": "Al Dia Immigration & Business Services",
  "start_date": "6/2/2021",
  "expire_date": "6/30/2023",
  "license_status": "expired",
  "business_type": "Accounting & Bookkeeping",
  "business_type_id": "1",
  "address_full": "3628 LYNOAK DR 201, POMONA, CA 91767",
  "street_address": "3628 LYNOAK DR 201",
  "city": "POMONA",
  "state": "CA",
  "zip_code": "91767",
  "matched_by": "Business Type",
  "days_to_expiry": -778,
  "is_new_license": false,
  "source_url": "https://pomona.hdlgov.com/Search/Index/BusinessLicense",
  "scraped_at": "2026-08-20T00:00:00.000Z"
}
```

| Field                     | Type    | Description |
|---------------------------|---------|--------------|
| `jurisdiction`             | string  | HdL city instance the record came from (e.g. `pomona`) |
| `jurisdiction_subdomain`   | string  | Subdomain slug for the city instance |
| `account_number`           | string  | City's business-license account number |
| `business_name`            | string  | Licensed business name |
| `start_date`               | string  | License issue date |
| `expire_date`               | string  | License expiration date |
| `license_status`           | string  | `active` or `expired`, derived by comparing `expire_date` to the run date |
| `business_type`            | string  | Business-type category label (e.g. "Accounting & Bookkeeping") |
| `business_type_id`         | string  | City-specific business-type code |
| `address_full`              | string  | Full address as published |
| `street_address`           | string  | Parsed street address |
| `city`                     | string  | Parsed city |
| `state`                    | string  | Parsed state |
| `zip_code`                  | string  | Parsed ZIP (or ZIP+4) |
| `matched_by`                | string  | Search axis this record was returned under (`Business Type`) |
| `days_to_expiry`           | number  | Days until `expire_date` (negative if already expired) |
| `is_new_license`           | boolean | `true` if `start_date` falls within `newLicenseLookbackDays` of the run |
| `source_url`                | string  | Canonical source page for this city's license search |
| `scraped_at`                | string  | ISO-8601 timestamp when this record was scraped |

***

### Resuming a large crawl

Every run emits a `resumeCursor` in its Output. If a large crawl stops before it finishes —
because it hit `maxItems`, your spend cap (`maxTotalChargeUsd`), or was aborted — start a
new run with **the same input** plus that `resumeCursor` to continue. You are **not
re-charged** for licenses the earlier run already delivered. Resume within your account's
run-retention window — on the free tier, roughly your 10 most recent runs.

***

### FAQ

#### Does this only find businesses I already know the name or address of?

No. Unlike a lookup tool, this actor enumerates every business-type category in a city to
return that city's **entire** active license roster — you don't need to know a business
name in advance.

#### How do I get only the new licenses issued this week?

Set `newLicenseLookbackDays` to `7` and filter your downstream results on
`is_new_license: true`. Re-run weekly to build a recurring new-business lead feed.

#### What happens if a city I request isn't reachable?

That city is skipped for that run and the rest of your requested cities still complete —
a single unreachable instance never fails the whole run.

#### Can I restrict the crawl to specific business types?

Yes — pass the business-type codes you want in `businessTypeIds`. Leave it empty to
enumerate every business type the city's portal exposes.

***

### Need More Features?

Need a city added, the Business Name/Address search axes, or a different output shape?
[File an issue](https://console.apify.com/actors/issues) or get in touch.

### Why Use HDL Municipal Business License Registry Scraper?

- **Full roster, not a single lookup** — every business-type category, every reachable
  city, in one run.
- **Built for recurring use** — `is_new_license` and `newLicenseLookbackDays` turn this
  into a weekly new-business lead feed, not a one-off export.
- **Clean, consistent output** — every license follows the same schema across every city.

# Actor input Schema

## `sp_intended_usage` (type: `string`):

What will this data feed? E.g. lead lists, KYB checks, price tracking.

## `sp_improvement_suggestions` (type: `string`):

Provide any feedback or suggestions for improvements.

## `sp_contact` (type: `string`):

We'll personally help with your use case. No spam.

## `resumeCursor` (type: `string`):

Leave empty for a fresh crawl. To CONTINUE a previous run where it stopped — without paying again for records you already received — paste the `resumeCursor` value from that run's Output (the run's OUTPUT key). Resume promptly: the previous run's data expires with your account's retention window (free tier: your ~10 most recent runs).

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

Which HdL city portals to crawl. Leave empty to crawl every known-candidate HdL city instance (each is probed live; a city that returns a Cloudflare block or has no reachable portal at run time is skipped, never fails the run).

## `businessTypeIds` (type: `array`):

Optional filter: HdL BusinessTypeId codes to restrict the crawl to (numeric, city-specific — discovered from each city's own search form). Leave empty to enumerate every business type the city's portal exposes.

## `newLicenseLookbackDays` (type: `integer`):

Licenses with a start\_date within this many days of the run are flagged is\_new\_license: true

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

Maximum number of license records to scrape across the run

## Actor input object example

```json
{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "newLicenseLookbackDays": 30,
  "maxItems": 10
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "newLicenseLookbackDays": 30,
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("jungle_synthesizer/hdl-municipal-business-license-registry-scraper").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 = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "newLicenseLookbackDays": 30,
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("jungle_synthesizer/hdl-municipal-business-license-registry-scraper").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 '{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "newLicenseLookbackDays": 30,
  "maxItems": 10
}' |
apify call jungle_synthesizer/hdl-municipal-business-license-registry-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jungle_synthesizer/hdl-municipal-business-license-registry-scraper"
        }
    }
}

```

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/8uJuK0cvCpu493gPz/builds/bNgIrdhpXDfdvVPGj/openapi.json
