# Hillsborough County Building Permits Scraper (`automation-lab/hillsborough-county-building-permits-scraper`) Actor

Search and export public Hillsborough County building permits with property details, statuses, valuations, applicants, licensed professionals, owners, dates, inspections, and official source links.

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

## Pricing

from $1.44 / 1,000 item extracteds

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

## Hillsborough County Building Permits Scraper

Export public Hillsborough County building permits as structured JSON without manually searching county pages.
The Actor combines the county's public permit map feed with public permit-detail pages to return permit identity,
status, property, valuation, applicant, licensed-professional, owner, and optional inspection information.

Use it for recurring construction intelligence, contractor activity monitoring, property diligence,
territory research, and compliance workflows. Results go to the default Apify dataset for download,
API access, schedules, webhooks, and integrations.

### What does this Actor do?

The Actor searches the public Hillsborough County permit data available through official county systems.
It supports server-side filters for:

- permit number;
- property address;
- parcel or folio number;
- city or community;
- permit type;
- permit status;
- issue or completion date range.

It can also enrich selected records from the public Accela detail page with:

- applicant information;
- licensed professional or contractor information;
- owner information;
- application and expiration dates when displayed;
- completed and upcoming inspection rows when displayed.

Applicant and contractor searches inspect public detail pages after applying another selective filter.
They therefore require a start date, permit number, address, or parcel number.

### Who is Hillsborough County building permit data for?

#### Construction sales teams

Find recently issued work in a territory and route projects to sales or estimating pipelines.
Filter by location, permit type, status, and date before enriching the records you need.

#### Contractors and subcontractors

Monitor public permits associated with a licensed professional or company.
Use scheduled runs to refresh a bounded date window and compare stable permit numbers downstream.

#### Property and risk teams

Look up public permit history by address, parcel, or exact permit number.
Review source links and publicly displayed status, valuation, party, and inspection context.

#### Analysts and civic-data teams

Export normalized records to CSV, Excel, JSON, a database, or a BI tool.
Use deterministic date-and-ID ordering for repeatable bounded extracts.

### Why use this Hillsborough County permits scraper?

- **Official public sources** — discovery uses the county's public ArcGIS permit feed and public Accela pages.
- **Typed output** — dates, values, coordinates, areas, and counts are normalized where the source supplies them.
- **Useful search controls** — narrow by property, permit identity, status, type, city, or date.
- **Optional deep enrichment** — skip detail pages for fast list exports, or include public parties and inspections.
- **Stable record keys** — `permitNumber` supports deduplication and change monitoring.
- **Source traceability** — every result contains the official data-layer URL and public record URL.
- **Bounded execution** — `maxItems` and `maxCandidates` prevent accidental unbounded scans.

This Actor does not claim to cover permits issued by the City of Tampa or another municipality outside the
records exposed by Hillsborough County's selected public systems.

### What Hillsborough County permit fields are extracted?

| Field | Meaning |
| --- | --- |
| `permitNumber` | Stable public permit identifier |
| `permitType` | County permit classification |
| `status` | Public record status |
| `category` | Source category such as issued or completed |
| `description` | Public project or work description |
| `address`, `city` | Permitted work location |
| `parcelNumber`, `folio` | Public property identifiers when available |
| `issuedDate`, `completedDate` | Normalized ISO dates when supplied |
| `applicationDate`, `expirationDate` | Dates displayed on the public detail page |
| `valuation` | Declared job value when public |
| `applicant` | Normalized public applicant section |
| `contractor` | Normalized licensed-professional section |
| `owner` | Normalized public owner section |
| `occupancyType`, `occupancyCategory` | Public occupancy attributes |
| `bedrooms`, `bathrooms`, `units` | Building counts when supplied |
| `livingAreaSqFt`, `totalAreaSqFt` | Public area fields when supplied |
| `latitude`, `longitude` | WGS84 map coordinates |
| `inspections` | Public inspection type, status, date, inspector, and row text |
| `recordUrl` | Official Accela permit-detail URL |
| `sourceUrl` | Official ArcGIS source-layer URL |
| `scrapedAt` | UTC extraction timestamp |

Source fields can be blank. Optional properties are omitted instead of filled with invented values.

### How to run the Actor

1. Open the Actor in Apify Console.
2. Choose a selective search, such as a recent date window, exact permit, address, parcel, city, or permit type.
3. Set **Maximum permits**.
4. Keep **Include permit details** on when you need public party information.
5. Keep **Include inspections** on only when inspection rows are needed; this mode uses a lightweight browser.
6. Click **Start**.
7. Open the **Permit records** dataset and export JSON, CSV, Excel, XML, or RSS.

A fast list-only search can set both detail options to `false`.

### Input parameters

| Input | Type | Default | Notes |
| --- | --- | --- | --- |
| `permitNumber` | string | — | Full or partial permit number |
| `address` | string | — | Full or partial street address |
| `parcelNumber` | string | — | Full or partial parcel or folio identifier |
| `city` | string | — | City or community text |
| `permitType` | string | — | Full or partial type |
| `status` | string | — | Full or partial public status |
| `fromDate` | `YYYY-MM-DD` | — | Issue/completion date lower bound |
| `toDate` | `YYYY-MM-DD` | — | Inclusive issue/completion date upper bound |
| `applicant` | string | — | Public detail-text match; requires another selective filter |
| `contractor` | string | — | Licensed-professional match; requires another selective filter |
| `includeDetails` | boolean | `true` | Add public parties and detail dates |
| `includeInspections` | boolean | `true` | Add public inspection rows; also enables details |
| `maxItems` | integer | `25` | Save 1–1,000 matching permits |
| `maxCandidates` | integer | `250` | Examine 1–2,000 candidates for detail-text searches |

Example list-only input:

```json
{
  "fromDate": "2026-07-01",
  "toDate": "2026-08-14",
  "city": "Tampa",
  "maxItems": 100,
  "includeDetails": false,
  "includeInspections": false
}
```

Example exact-permit input:

```json
{
  "permitNumber": "HC-BLD-26-0083889",
  "maxItems": 1,
  "includeDetails": true,
  "includeInspections": true
}
```

### Output example

The default dataset contains one object per permit. This representative example is anonymized;
actual values come from the public source.

```json
{
  "permitNumber": "HC-BLD-25-0012345",
  "permitType": "Residential New Construction",
  "status": "Issued",
  "category": "ISSUED",
  "description": "New single-family residence.",
  "address": "100 Sample Avenue",
  "city": "Tampa 33602",
  "parcelNumber": "012345.0000",
  "issuedDate": "2025-01-15",
  "valuation": 350000,
  "applicant": "Sample Applicant, Example Permits LLC",
  "contractor": "Sample Contractor, License EX123",
  "latitude": 27.95,
  "longitude": -82.45,
  "inspections": [
    {
      "type": "Electrical Final",
      "status": "Passed",
      "date": "01/20/2025",
      "inspector": "Inspector A"
    }
  ],
  "recordUrl": "https://aca-prod.accela.com/HCFL/Cap/CapDetail.aspx?Module=Building",
  "sourceUrl": "https://services.arcgis.com/apTfC6SUmnNfnxuF/arcgis/rest/services/AccelaDashBoard_MapService20211019/FeatureServer/0",
  "scrapedAt": "2025-01-15T12:00:00.000Z"
}
```

### How much does it cost to export Hillsborough County building permits?

The Actor uses pay-per-event pricing:

- a **$0.015 start event** once per run;
- one `item` event for each permit record saved;
- detail and inspection fields included in a permit have no separate event charge.

The per-record price decreases by usage tier. At the BRONZE tier it is **$0.0024 per permit**.
The Apify Console pricing panel shows the tier applicable to your account and is the source of truth.

BRONZE-tier examples:

| Saved permits | Calculation |
| ---: | --- |
| 1 | $0.015 start + 1 × $0.0024 per permit |
| 25 | $0.015 start + 25 × $0.0024 per permit |
| 100 | $0.015 start + 100 × $0.0024 per permit |

A run that finds no matching records still emits the one-time start event.
Apify platform usage may be charged separately according to your plan and the active pricing configuration.

### Monitoring new and changed permits

1. Choose a bounded recent `fromDate` and optional territory or permit-type filter.
2. Run the Actor on an Apify schedule.
3. Store `permitNumber` as the stable key in your database or automation.
4. Compare status, completion date, valuation, contractor, and inspections with the prior snapshot.
5. Use an Apify webhook to notify a workflow only after successful runs.

The Actor returns a snapshot. It does not maintain a cross-run change database or send alerts itself.

### Integration ideas

- Send new construction permits to a CRM with Make or Zapier.
- Load permit rows into BigQuery, Snowflake, PostgreSQL, or Google Sheets.
- Trigger a webhook when scheduled datasets are ready.
- Join `parcelNumber` or `folio` to an authorized property dataset.
- Build contractor activity summaries using public licensed-professional text.
- Audit an exact permit and retain its official `recordUrl` for review.

Do not treat a source omission or delayed county update as proof that work is unpermitted.

### Use the Apify API

Replace `$APIFY_TOKEN` with your Apify API token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~hillsborough-county-building-permits-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"fromDate":"2026-07-01","maxItems":25,"includeInspections":false}'
```

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/hillsborough-county-building-permits-scraper').call({
  permitType: 'Residential New Construction',
  fromDate: '2026-01-01',
  maxItems: 50,
  includeDetails: true,
  includeInspections: false,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/hillsborough-county-building-permits-scraper').call(run_input={
    'city': 'Seffner',
    'fromDate': '2026-01-01',
    'maxItems': 25,
    'includeDetails': True,
    'includeInspections': False,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with MCP and AI assistants

Add the Actor to Claude Code through Apify MCP:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/hillsborough-county-building-permits-scraper"
```

#### Claude Desktop

Add this server to your Claude Desktop MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/hillsborough-county-building-permits-scraper"
    }
  }
}
```

#### Cursor

Create an MCP server named `apify` in Cursor and use the same HTTP URL shown above.

#### VS Code

Add an HTTP MCP server named `apify` to your VS Code MCP configuration with the same URL.

Example prompts:

- “Find Hillsborough County residential permits issued since 2026-07-01 and summarize valuations by city.”
- “Look up permit HC-BLD-26-0083889 and list its public inspection history.”
- “Export recent Seffner permits associated with this licensed contractor.”

### Limits and source behavior

- Public source coverage and update timing are controlled by Hillsborough County and Accela.
- Some records omit valuations, occupancy attributes, parties, coordinates, or inspections.
- Date filters apply to the combined issue/completion date exposed by the official map feed.
- Applicant and contractor filters are case-insensitive text matches over selected public detail pages.
- `maxCandidates` can stop a detail-text search before every possible source record is examined.
- Inspection mode uses browser rendering because Accela loads inspection rows after the initial page response.
- The Actor retries transient network and server failures but does not blindly retry invalid requests.
- If optional detail enrichment fails, list fields can still be returned when no detail-only filter was requested.
- A detail-only applicant or contractor search fails closed rather than returning an unverified match.

### Responsible use and legality

This Actor accesses public government records without login.
You are responsible for complying with applicable law, Apify's terms, source terms, privacy obligations,
and rules governing solicitation, profiling, retention, and automated decisions.

Use public contact and party information only for a lawful purpose.
Do not use results to harass individuals, infer protected characteristics, or make unsupported claims.
Verify consequential decisions against the official `recordUrl` and relevant county authority.

### Troubleshooting

#### Why did the Actor return no records?

Confirm the date range and spelling of the permit, city, address, parcel, type, or status.
Start with one broad selective filter, then add more filters. A date window can naturally contain no records.

#### Why did a contractor search return fewer records than expected?

The contractor filter examines only records within the other filters and `maxCandidates` bound.
Increase `maxCandidates` carefully, widen the date range, or use a city/property filter that reflects the workflow.
The match uses the public licensed-professional text displayed by Accela.

#### Why is an inspection list absent?

The county may display no inspection rows for that permit, or inspection enrichment may have been disabled.
Run an exact permit with `includeInspections: true` and verify the official record link.

#### Why are some fields missing?

The source does not populate every field for every permit type or lifecycle stage.
The Actor omits missing values rather than guessing.

### FAQ

#### Can I search by address or parcel?

Yes. Both accept full or partial text. Use an exact value when you need a narrow result set.

#### Can I search by contractor?

Yes. Provide `contractor` plus a start date, permit number, address, or parcel number.
The Actor enriches bounded candidates and matches the public licensed-professional section.

#### Does it include City of Tampa permits?

Only records present in the selected Hillsborough County public feed are returned.
The Actor does not merge a separate City of Tampa permit system.

#### Can I schedule recurring runs?

Yes. Use Apify schedules and compare records by `permitNumber` in your own database or automation.

#### Can I export to Excel or CSV?

Yes. Open the default dataset and choose Excel, CSV, JSON, XML, or another supported export.

### Related automation-lab Actors

- [Chicago Building Permits & Contractor Leads Scraper](https://apify.com/automation-lab/chicago-building-permits-scraper)
- [Los Angeles Building Permits Scraper](https://apify.com/automation-lab/los-angeles-building-permits-scraper)
- [NYC DOB NOW Building Permits Scraper](https://apify.com/automation-lab/nyc-dob-now-building-permits-scraper)

These Actors cover separate public jurisdictions and are not merged into this Actor's results.

# Actor input Schema

## `permitNumber` (type: `string`):

Full or partial permit number, such as HC-BLD-26.

## `address` (type: `string`):

Full or partial street address.

## `parcelNumber` (type: `string`):

Full or partial public parcel identifier.

## `city` (type: `string`):

City or community name in the permit address.

## `permitType` (type: `string`):

Full or partial permit type, such as Residential New Construction.

## `status` (type: `string`):

Full or partial public status, such as Issued or Complete.

## `fromDate` (type: `string`):

Include records issued or completed on or after this date.

## `toDate` (type: `string`):

Include records issued or completed on or before this date.

## `applicant` (type: `string`):

Match text in the public applicant section. Requires a date, permit, address, or parcel filter.

## `contractor` (type: `string`):

Match text in the public licensed-professional section. Requires a date, permit, address, or parcel filter.

## `includeDetails` (type: `boolean`):

Add public applicant, licensed professional, owner, and detail-page dates.

## `includeInspections` (type: `boolean`):

Add publicly displayed inspection rows when available. This also enables permit details.

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

Maximum matching permit records to save.

## `maxCandidates` (type: `integer`):

Safety limit for records examined during applicant or contractor filtering.

## Actor input object example

```json
{
  "address": "11720 E Dr Martin Luther King Jr Blvd",
  "includeDetails": true,
  "includeInspections": true,
  "maxItems": 10,
  "maxCandidates": 250
}
```

# Actor output Schema

## `dataset` (type: `string`):

Default dataset containing the extracted permits.

# 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 = {
    "address": "11720 E Dr Martin Luther King Jr Blvd",
    "includeDetails": true,
    "includeInspections": true,
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/hillsborough-county-building-permits-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 = {
    "address": "11720 E Dr Martin Luther King Jr Blvd",
    "includeDetails": True,
    "includeInspections": True,
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/hillsborough-county-building-permits-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 '{
  "address": "11720 E Dr Martin Luther King Jr Blvd",
  "includeDetails": true,
  "includeInspections": true,
  "maxItems": 10
}' |
apify call automation-lab/hillsborough-county-building-permits-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/hillsborough-county-building-permits-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/b8oiivUSqSlUOYacq/builds/He7JCYy6e6VF2qMJm/openapi.json
