# California Cannabis License & Business Leads (`scrapesignal_labs/california-cannabis-license-scraper`) Actor

Search official California DCC cannabis licenses by status, type, county, dates, contacts, and expiration—ready for lead generation, compliance, and market research.

- **URL**: https://apify.com/scrapesignal\_labs/california-cannabis-license-scraper.md
- **Developed by:** [ScrapeSignal Labs](https://apify.com/scrapesignal_labs) (community)
- **Categories:** Lead generation, Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## California Cannabis License & Business Leads

Build targeted California cannabis business lists from the official Department of Cannabis Control registry—without searching licenses one at a time. Filter by status, license type, county, city, issue date, expiration date, and contact availability, then export clean records to CSV, Excel, JSON, or your CRM.

Every result can include the license number and status, legal and DBA names, public owner and business contacts, premises address, county, parcel number, coordinates, issue date, expiration date, and a direct official source link.

The Actor calls California's public JSON API directly. It does not launch a browser, require an API key, or use a proxy.

### Built for actionable lists—not just bulk exports

- Find active retailers, delivery operators, laboratories, distributors, manufacturers, cultivators, event organizers, and microbusinesses.
- Require a published email or phone before paying for and saving a result.
- Identify newly issued licenses with an exact issue-date window.
- Find upcoming renewals with expiration filters and `daysUntilExpiration`.
- Segment the market by county, city, ZIP code, license category, or designation.
- Preserve direct source links and the DCC data-refresh timestamp for verification.

### Why this dataset is useful

- **Lead generation:** find licensed retailers, delivery operators, laboratories, distributors, manufacturers, cultivators, and microbusinesses with published email and phone contacts.
- **New-license monitoring:** sort by newest issue date or set an issue-date window to find newly licensed operators.
- **Renewal workflows:** query an expiration window and use `daysUntilExpiration` to identify upcoming renewals.
- **Compliance and verification:** check official status, designation, license type, business owner, and source record.
- **Market mapping:** analyze operators by county, city, ZIP code, category, and coordinates.

At the time this Actor was built, the registry contained more than 20,000 historical licenses and more than 7,500 active licenses. Counts change as DCC refreshes the registry.

### Quick start

The default run returns the first 100 active licenses statewide.

To collect active retailers in Los Angeles County that have both an email and phone:

```json
{
  "activeOnly": true,
  "licenseCategories": ["retailer"],
  "county": "Los Angeles",
  "withEmailOnly": true,
  "withPhoneOnly": true,
  "maxItems": 1000
}
```

To find the newest licenses issued in a date window:

```json
{
  "activeOnly": true,
  "issuedFrom": "2026-08-01",
  "issuedTo": "2026-08-31",
  "sortBy": "newestIssued",
  "maxItems": 500
}
```

To monitor active licenses expiring in the next quarter, supply the actual start and end dates for the quarter:

```json
{
  "activeOnly": true,
  "expiresFrom": "2026-10-01",
  "expiresTo": "2026-12-31",
  "sortBy": "soonestExpiration",
  "maxItems": 5000
}
```

### Input

All filters combine.

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `searchQuery` | string | empty | Free-text search across license, business, owner, type, and address fields. |
| `licenseNumber` | string | empty | Full or partial DCC license number. |
| `activeOnly` | boolean | `true` | Restrict results to official status `Active`. |
| `licenseStatuses` | string\[] | `[]` | Statuses to include when `activeOnly` is false. Empty means all. |
| `licenseCategories` | string\[] | `[]` | Normalized categories: retailer, delivery, testing-laboratory, microbusiness, event-organizer, distributor, manufacturer, cultivator. |
| `licenseDesignation` | string | empty | Official designation, such as `Adult-Use and Medicinal`. |
| `county` | string | empty | Premises county. |
| `city` | string | empty | Premises city. |
| `zipCode` | string | empty | Five-digit premises ZIP code. |
| `issuedFrom`, `issuedTo` | date | empty | Inclusive issue-date window in `YYYY-MM-DD` format. |
| `expiresFrom`, `expiresTo` | date | empty | Inclusive expiration-date window in `YYYY-MM-DD` format. |
| `withEmailOnly` | boolean | `false` | Require a published business email. |
| `withPhoneOnly` | boolean | `false` | Require a published business phone. |
| `sortBy` | string | `licenseNumberAsc` | License number, newest issued, soonest expiration, or business name. |
| `maxItems` | integer | `100` | Maximum records to save, up to 50,000. |
| `includeRaw` | boolean | `false` | Include the unmodified DCC API object under `raw`. |

When `activeOnly` is true, `licenseStatuses` is intentionally ignored.

### Output

One dataset item represents one state license. Important fields include:

- License: `licenseNumber`, `licenseStatus`, `licenseCategory`, `licenseType`, `licenseDesignation`, `licenseTerm`
- Dates: `issueDate`, `expirationDate`, `daysUntilExpiration`, `expiresWithin90Days`
- Business: `businessName`, `legalName`, `dbaName`, `ownerName`, `businessStructure`, `activity`
- Contact: `email`, `phone`
- Location: `streetAddress`, `city`, `county`, `state`, `zipCode`, `fullAddress`, `parcelNumber`, `latitude`, `longitude`
- Traceability: `sourceUrl`, `sourceApiUrl`, `sourceDataRefreshedAt`, `scrapedAt`

Source strings such as `Data Not Available` are returned as `null`. Dates are normalized to `YYYY-MM-DD`; emails are lowercased. No missing value is guessed or enriched from a third party.

### Run through the Apify API

```bash
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~california-cannabis-license-scraper/runs?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"activeOnly":true,"licenseCategories":["distributor"],"maxItems":500}'
```

You can also save an Apify Task and attach a schedule for daily or weekly monitoring. Use `licenseNumber` or `recordId` as the stable upsert key in downstream systems.

### Data source and limitations

Data comes from the [California Cannabis Unified License Search](https://search.cannabis.ca.gov/) and its [public DCC API](https://as-dcc-pub-cann-w-p-002.azurewebsites.net/index.html). Each item links back to the official record.

- This is an independent Actor and is not affiliated with or endorsed by the California Department of Cannabis Control.
- A status reflects the source at its last published refresh. Always open `sourceUrl` for a time-sensitive compliance decision.
- DCC may publish inconsistent capitalization or historical records whose dates appear unusual. The Actor preserves substantive source values and does not reinterpret official status.
- Contact and owner fields are public registry data. Users are responsible for lawful outreach, privacy compliance, and honoring opt-out requests.

### Local development

Requires Node.js 20 or newer.

```bash
npm install
npm test
npm start
```

Local Apify storage is written to `storage/`. Set Actor input in `storage/key_value_stores/default/INPUT.json` or through the Apify CLI.

### License

MIT

# Actor input Schema

## `searchQuery` (type: `string`):

Free-text search across license number, business names, owners, type, and address.

## `licenseNumber` (type: `string`):

Full or partial DCC license number, for example C10-0000007-LIC.

## `activeOnly` (type: `boolean`):

Return only records whose official DCC status is Active.

## `licenseStatuses` (type: `array`):

Used only when Active licenses only is off. Leave empty for every status.

## `licenseCategories` (type: `array`):

Normalized business categories. Leave empty for all license types.

## `licenseDesignation` (type: `string`):

Optional official designation such as Adult-Use, Medicinal, or Adult-Use and Medicinal.

## `county` (type: `string`):

California county name, for example Los Angeles or Humboldt.

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

Premises city, for example Oakland or Santa Rosa.

## `zipCode` (type: `string`):

Five-digit premises ZIP code.

## `issuedFrom` (type: `string`):

Start of the issue-date window (YYYY-MM-DD). Useful for newly licensed business leads.

## `issuedTo` (type: `string`):

End of the issue-date window (YYYY-MM-DD).

## `expiresFrom` (type: `string`):

Start of the expiration-date window (YYYY-MM-DD).

## `expiresTo` (type: `string`):

End of the expiration-date window (YYYY-MM-DD). Useful for renewal monitoring.

## `withEmailOnly` (type: `boolean`):

Keep only records with a published business email.

## `withPhoneOnly` (type: `boolean`):

Keep only records with a published business phone.

## `sortBy` (type: `string`):

The official API applies this ordering before the result limit.

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

Maximum number of matching license records saved to the dataset.

## `includeRaw` (type: `boolean`):

Attach the complete unmodified DCC API object under raw. Normalized fields are always included.

## Actor input object example

```json
{
  "searchQuery": "",
  "licenseNumber": "",
  "activeOnly": true,
  "licenseStatuses": [],
  "licenseCategories": [],
  "licenseDesignation": "",
  "county": "",
  "city": "",
  "issuedFrom": "",
  "issuedTo": "",
  "expiresFrom": "",
  "expiresTo": "",
  "withEmailOnly": false,
  "withPhoneOnly": false,
  "sortBy": "licenseNumberAsc",
  "maxItems": 100,
  "includeRaw": false
}
```

# Actor output Schema

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

Normalized license records in the run's default dataset.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapesignal_labs/california-cannabis-license-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapesignal_labs/california-cannabis-license-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 '{}' |
apify call scrapesignal_labs/california-cannabis-license-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapesignal_labs/california-cannabis-license-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/D2H5deaQ2jbwmKX8m/builds/2dWSlz3n3rPS66ag5/openapi.json
