Cannabis Dispensary Monitor — 43 US States + Change Detection avatar

Cannabis Dispensary Monitor — 43 US States + Change Detection

Pricing

from $5.00 / 1,000 results

Go to Apify Store
Cannabis Dispensary Monitor — 43 US States + Change Detection

Cannabis Dispensary Monitor — 43 US States + Change Detection

Track every licensed dispensary across all 43 US legal states. Combines Weedmaps, Leafly, iHeartJane, Dutchie + official state license DBs. Detects new openings, closures & license changes weekly. Menu pricing, market intelligence, expiry alerts & webhooks.

Pricing

from $5.00 / 1,000 results

Rating

0.0

(0)

Developer

Z W

Z W

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

7 hours ago

Last modified

Share

The only cannabis Actor that tracks dispensary openings and closures across weekly runs. Combines 6 platform sources (Weedmaps, Leafly, iHeartJane, Dutchie, Potguide, AllBud) with official state license databases from 43 states and territories — deduplicates everything into one clean dataset, then diffs each run against the last to surface what changed: new stores, closures, license suspensions, and address updates.

Also includes deep menu data (optional) — strain type (indica/sativa/hybrid), THC/CBD percentages, effects, terpenes, per-weight price tiers (gram → ounce), brand, dosage, and staff picks — across 4 menu sources. Market intelligence and license expiry alerts included on every run at no extra cost.

What does Cannabis Dispensary Monitor do?

This Actor scrapes publicly available dispensary listings from major cannabis platforms plus official government licensing databases. It normalizes all records into a consistent schema, deduplicates across sources, and flags changes between runs.

Demo

Output table view (Apify Console → Output tab):

Dataset table view showing dispensary records with name, city, state, license number, status, and rating columns

RUN_HEALTH report (Key-Value store → RUN_HEALTH key):

RUN_HEALTH showing per-source status, item counts, errors, and overall healthy verdict

Coverage:

  • 43 states and territories with official state license databases: PA, MD, DE, NY, NJ, CT, MA, CO, WA, CA, MI, IL, OR, NV, MO, OH, AZ, FL, MN, OK, NM, MT, VA, TX, AK, HI, LA, AR, MS, ND, ME, VT, RI, DC, NH, WV, SD, UT, IA, GA, AL, KY, NC
  • 6 platform sources — Weedmaps, Leafly, iHeartJane, Dutchie, Potguide, AllBud — covering all US states with overlapping coverage for higher deduplication quality
  • Menu pricing (optional) — product counts, price ranges, per-category median/avg/min/max per dispensary
  • Market intelligence — per-state analytics, chain concentration, top MSOs, delivery rates — automatically computed after every run
  • Social media handles (optional) — Instagram, Facebook, Twitter/X, TikTok extracted from dispensary websites

State coverage at a glance

StateProgramEst. licensed dispensariesOfficial DB
California (CA)Recreational + Medical1,200+CA DCC (Socrata)
Florida (FL)Medical only550+FDOH OMMU
Oklahoma (OK)Medical + Recreational2,000+OMMA (Socrata)
Colorado (CO)Recreational + Medical550+CO MED CSV
Washington (WA)Recreational + Medical700+WA LCB (Socrata)
Michigan (MI)Recreational + Medical600+MRA (Socrata)
Oregon (OR)Recreational + Medical700+OLCC (Socrata)
Illinois (IL)Recreational + Medical180+IDFPR (Socrata)
New York (NY)Recreational + Medical250+OCM API
New Jersey (NJ)Recreational + Medical130+CRC (Socrata)
Nevada (NV)Recreational + Medical200+CCB (Socrata)
Massachusetts (MA)Recreational + Medical350+CCC (Socrata)
Pennsylvania (PA)Medical only180+DOH HTML
Maryland (MD)Recreational + Medical100+MCA HTML
Arizona (AZ)Recreational + Medical200+ADHS (Socrata)
Missouri (MO)Recreational + Medical350+DHSS (Socrata)
Ohio (OH)Recreational + Medical350+DOC (Socrata)
Texas (TX)Medical only~50DSHS HTML
+ 25 more statesVariousVariesState-specific

Platform sources (Weedmaps, Leafly, iHeartJane, Potguide, AllBud) supplement official data and provide coverage for all US states.

Quick smoke test: Set testMode: true — runs 3 results per source in under 30 seconds and costs less than $0.01.

Why use Cannabis Dispensary Monitor?

For developers and data teams

  • Cross-run change detection — every run diffs against the previous snapshot and outputs new_dispensary, dispensary_closed, license_suspended, and dispensary_updated events. POST them to your webhook endpoint in real time
  • Official license data — government Socrata APIs (CA DCC, CO MED, WA LCB, NY OCM, MA CCC, OR OLCC, NV CCB, AZ ADHS, and 34 more) provide verified license numbers, issue/expiry dates, and addresses the platforms often get wrong
  • Deep menu data (optional) — enable includeMenuData: true to get strain type (indica/sativa/hybrid/CBD), THC/CBD%, effects (up to 10), terpenes (up to 8), brand, dosage, per-weight price tiers (gram → ounce), staff picks, and in-stock status. Sourced from Weedmaps, Leafly, iHeartJane, and Dutchie across 4 overlapping APIs. Pushed to a separate menu_items dataset
  • Multi-source deduplication — same location found on Weedmaps, Leafly, Dutchie, Potguide, and the state DB → one clean merged record, not five duplicates. State source wins on address/license; platform source wins on ratings/hours. More overlap = higher confidence data
  • 6 platform sources — Dutchie powers ~40% of US dispensaries (unique coverage). Potguide and AllBud surface thousands of independents that never list on Weedmaps or Leafly
  • License expiry alerts — flags dispensaries whose license expires within 30/60/90 days via the EXPIRING_LICENSES KV key and webhook events
  • Run health monitoringRUN_HEALTH report shows per-source item counts, error counts, and suspicious_zero flags (ran but returned nothing — silent break detection)
  • Any format — JSON, CSV, Excel via Apify's native export

Use cases by buyer type

Cannabis operators — track competitor openings within 5 miles of your stores. Get a webhook when a new license is issued in your market. Export to CSV for your sales team.

B2B sales teams — build contact lists of licensed dispensaries with phone numbers, websites, addresses, and social media handles. Filter by state, category (medical vs recreational), and chain affiliation. 18,000–25,000 unique dispensaries with contact info across a full run.

Investors and M&A — track chain expansion by monitoring chain field changes over time. Detect when a regional operator crosses a threshold. License status + expiry dates surface distressed assets before they make the news.

Compliance and legal — automatic license expiry notifications at 30/60/90 days. License status change webhooks (active → suspended) deliver via POST the same day the government database updates. Covers 42 state databases.

Commercial real estate — dispensary density maps using lat/lng coordinates. Find saturated markets and underserved zip codes. Cross-reference against zoning data. Export to GeoJSON.

Market research — per-dispensary product counts and pricing stats across flower, edibles, vapes, concentrates when includeMenuData: true. Median prices and sale counts enable competitive price benchmarking.

App developers — build a dispensary finder with fresh weekly data instead of maintaining your own scrapers. The deduplicated dataset + coordinates is production-ready.

Use Case Examples

Dispensary operator: monitor competitor openings in your market

A Colorado dispensary chain wants to know within 24 hours when a new license is issued within 50 miles of their stores. They run this Actor on a weekly schedule with states: ["CO"], webhookUrl pointing to their Slack integration, and webhookStateFilter: ["CO"]. Each Monday morning they receive a POST payload listing any new_dispensary events from the prior week — name, address, coordinates, license number, and license issue date. When a competitor opens near one of their locations, their ops team sees it before customers do.

B2B sales team: build a dispensary contact list for the Southeast

A cannabis software company (POS systems, compliance tools) wants to reach every active licensed dispensary in GA, AL, KY, NC, TN, FL, TX. They run the Actor with states: ["GA","AL","KY","NC","FL","TX"], maxResultsPerSource: 0, includeStateSources: true, enrichSocialMedia: true. The output CSV gives them 3,500–5,000 records with business name, phone, website, social media handles, license number, license status, and category (medical vs recreational). They filter out chain !== null to target independents, and filter licenseStatus: "active" to skip expired licenses. Total cost: under $0.50.

Cannabis investor: track MSO footprint expansion

A private equity analyst tracks multi-state operator (MSO) expansion across quarterly runs. They run the Actor on all 43 states with maxResultsPerSource: 0 twice per quarter. Each run outputs a CHANGES KV key with new_dispensary events. By filtering changes where dispensary.chain === "Trulieve" (or any target MSO), they see exactly which markets each chain entered or exited. They also pull MARKET_INTELLIGENCE.topChains for national chain concentration numbers — data that traditional cannabis data vendors (Headset, BDSA) charge $5,000+/year to access.

App developer: dispensary finder with fresh weekly data

A developer building a dispensary-finder mobile app needs a dataset of all US dispensaries with coordinates, hours, services (pickup/delivery/storefront), and ratings — updated weekly without maintaining their own scrapers. They configure a weekly Apify schedule with states set to their target markets, geocodeMissingCoordinates: true (fills null coordinates via OpenStreetMap), and sync the dataset to their database via the Apify API after each run. The deduplicated dataset (~18,000 records for a full run) arrives as production-ready JSON with consistent schema across all sources.

Compliance team: license expiry monitoring

A cannabis law firm tracks renewal deadlines for 200+ dispensary clients across PA, MD, NJ, NY, CT, MA. They run the Actor weekly with licenseExpiryAlertDays: [30, 60, 90] and webhookUrl pointing to their case management system. The license_expiring events fire exactly 30, 60, and 90 days before each license expiration date — automatically, with no manual tracking spreadsheet. The EXPIRING_LICENSES KV key also gives them a full snapshot of every client with an upcoming renewal.


How to use Cannabis Dispensary Monitor

  1. Open the Input tab in Apify Console
  2. Select which Platform Sources to scrape (Weedmaps, Leafly, iHeartJane, Potguide, AllBud enabled by default; Dutchie requires a residential proxy)
  3. Enter the US States you want, e.g. ["CA", "CO", "WA"]
  4. Keep Include Official State Databases enabled for license numbers and expiry dates
  5. Optionally add a webhookUrl to receive change events after each run
  6. Click Start — a typical 4-state run takes 5–15 minutes
  7. Download from the Output tab in JSON, CSV, or Excel

Run via API:

curl -X POST "https://api.apify.com/v2/acts/YOUR_ACTOR_ID/runs" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"states": ["CA", "CO"], "sources": ["weedmaps", "iheartjane"], "maxResultsPerSource": 0}'

Schedule weekly with change detection:

  1. Run once to build the baseline snapshot
  2. Add a weekly schedule (Monday morning recommended)
  3. Each subsequent run posts only what changed to your webhookUrl

Input

FieldTypeDefaultDescription
testModebooleanfalseCollect only 3 results/source, skip snapshot update. Free smoke test
sourcesarray["weedmaps","leafly","iheartjane","potguide","allbud"]Platform sources to scrape. Options: weedmaps, leafly, iheartjane, potguide, allbud, dutchie (residential proxy required for Dutchie)
statesarray["PA","MD","DE","NY","NJ","CT","MA","CO","WA"]US state abbreviations. Supported state DBs: PA MD DE NY NJ CT MA CO WA CA MI IL OR NV MO OH AZ FL MN OK NM MT VA TX AK HI LA AR MS ND ME VT RI DC NH WV SD UT IA GA AL KY NC
includeStateSourcesbooleantrueInclude official state license databases (adds license numbers, expiry dates)
maxResultsPerSourceinteger500Max dispensaries per source per state. 0 = unlimited
sourceTimeoutSecsinteger300Max seconds per source before cutoff (prevents one hung source from killing the run)
includeMenuDatabooleanfalseScrape deep menu data per dispensary — strain type (indica/sativa/hybrid), THC/CBD%, effects, terpenes, brand, dosage, per-weight price tiers, staff picks. Pushed to separate menu_items dataset
webhookUrlstringHTTPS endpoint to receive change/expiry events after each run
webhookStateFilterarrayOnly send webhook events for these states (empty = all states)
licenseExpiryAlertDaysarray[30,60,90]Days-before-expiry windows for license expiry alerts
suppressInitialStateChangesbooleantrueSuppress new_dispensary events when adding a new state for the first time
geocodeMissingCoordinatesbooleanfalseFill null coordinates via free OpenStreetMap Nominatim API
enrichSocialMediabooleanfalseScrape each dispensary's website to extract Instagram, Facebook, Twitter/X, TikTok, YouTube handles. Capped at 1,000 dispensaries. Adds run time.
proxyConfigurationobjectApify proxy settings (recommended for large runs or rate-limited sources)

Quick test:

{
"testMode": true,
"states": ["CA", "CO"],
"sources": ["weedmaps"]
}

Full run with webhook alerts:

{
"states": ["PA", "NY", "CO", "CA"],
"sources": ["weedmaps", "leafly", "iheartjane", "potguide", "allbud"],
"includeStateSources": true,
"maxResultsPerSource": 0,
"webhookUrl": "https://your-endpoint.com/cannabis-alerts",
"licenseExpiryAlertDays": [30, 60, 90]
}

Output

Main Dataset — Dispensary Records

Download in JSON, CSV, HTML, or Excel from the Output tab or via the Apify API.

Example records:

[
{
"id": "wm_48291",
"sources": ["weedmaps", "state-pa"],
"name": "Maitri Medicinals",
"slug": "maitri-medicinals",
"url": "https://weedmaps.com/dispensaries/maitri-medicinals",
"address": {
"street": "6056 Broad St",
"city": "Pittsburgh",
"state": "PA",
"zip": "15206",
"country": "US"
},
"coordinates": { "lat": 40.4551, "lng": -79.9218 },
"phone": "+14123625220",
"email": null,
"website": "https://maitrimedicinals.com",
"hours": {
"monday": "10am-7pm", "tuesday": "10am-7pm", "wednesday": "10am-7pm",
"thursday": "10am-7pm", "friday": "10am-7pm",
"saturday": "10am-7pm", "sunday": "11am-5pm"
},
"rating": 4.7,
"reviewCount": 312,
"services": { "delivery": false, "pickup": true, "storefront": true },
"licenseNumber": "MM-PA-0012432",
"licenseStatus": "active",
"licenseIssuedDate": "2021-03-15",
"licenseExpiresDate": "2026-03-14",
"categories": ["medical"],
"amenities": ["atm", "parking", "ada_accessible"],
"acceptsCreditCard": true,
"chain": null,
"menu": {
"totalProducts": 87,
"onSaleCount": 5,
"byCategory": { "flower": 22, "edibles": 18, "vapes": 15, "concentrates": 12 },
"priceRange": { "min": 5, "max": 95 },
"priceByCategory": {
"flower": { "count": 22, "min": 10, "max": 55, "avg": 28.50, "median": 27.00, "onSale": 3 },
"edibles": { "count": 18, "min": 5, "max": 35, "avg": 18.20, "median": 16.50 },
"vapes": { "count": 15, "min": 25, "max": 75, "avg": 48.00, "median": 45.00 }
}
},
"lastScraped": "2025-01-15T14:22:05.000Z"
},
{
"id": "wm_55102",
"sources": ["weedmaps", "leafly"],
"name": "Housing Works Cannabis Co.",
"address": { "street": "750 Broadway", "city": "New York", "state": "NY", "zip": "10003", "country": "US" },
"coordinates": { "lat": 40.7285, "lng": -73.9920 },
"phone": "+12125054100",
"website": "https://hwcannabis.co",
"rating": 4.4,
"reviewCount": 890,
"services": { "delivery": false, "pickup": true, "storefront": true },
"licenseNumber": "OCM-RD-2023-00047",
"licenseStatus": "active",
"categories": ["recreational"],
"amenities": null,
"acceptsCreditCard": null,
"chain": null,
"menu": null,
"googleMapsUrl": "https://www.google.com/maps/search/Housing+Works+Cannabis+Co.+750+Broadway+New+York+NY+10003",
"lastScraped": "2025-01-15T14:22:05.000Z"
}
]

Data Field Reference

FieldTypeDescription
idstringStable unique ID — source-prefixed (wm_, lf_, jhj_, state_pa_, etc.)
sourcesstring[]All sources that contributed data to this record
namestringDispensary display name
slugstringURL slug (from platform sources)
urlstringPlatform listing URL
addressobjectstreet, city, state, zip, country
coordinatesobjectlat, lng decimal degrees
phonestringE.164 format (+1XXXXXXXXXX)
emailstringPublic email if listed
websitestringDispensary website URL
hoursobjectKeyed by day name (mondaysunday)
ratingnumberPlatform rating (0–5 scale)
reviewCountnumberTotal review count
servicesobjectdelivery, pickup, storefront booleans
licenseNumberstringState-issued license number (from official DB when available)
licenseStatusstringactive, suspended, expired, revoked, pending, etc.
licenseIssuedDatestringISO date string (YYYY-MM-DD)
licenseExpiresDatestringISO date string — used for expiry alerts
categoriesstring[]medical, recreational, or both
amenitiesstring[]Normalized amenity list (atm, parking, ada_accessible, etc.) — from Weedmaps and Leafly when available
acceptsCreditCardbooleantrue if any source confirms credit card acceptance (iHeartJane, Weedmaps, Leafly), null if unknown
chainstringMSO chain name if detected (Curaleaf, Trulieve, GTI, etc.), else null
menuobjectProduct counts + per-category pricing when includeMenuData: true. Includes totalProducts, onSaleCount, byCategory, priceRange, and priceByCategory (min/max/avg/median/onSale per category)
socialMediaobjectInstagram, Facebook, Twitter/X, TikTok, YouTube handles when enrichSocialMedia: true
googleMapsUrlstringDirect Google Maps search link for the dispensary (computed from name + address)
lastScrapedstringISO timestamp of this scrape

A separate menu_items dataset is pushed alongside the main dispensaries dataset. Each record represents a single product from a dispensary's menu:

{
"dispensaryId": "wm_48291",
"dispensaryName": "Maitri Medicinals",
"source": "weedmaps",
"productId": "prod_9928471",
"name": "Blue Dream (1g)",
"brand": "Hollyweed",
"category": "flower",
"subcategory": "pre-roll",
"strainType": "hybrid",
"weightGrams": 1.0,
"dosageMg": null,
"priceUSD": 12.00,
"salePriceUSD": null,
"onSale": false,
"priceTiers": { "gram": 12.00, "eighth": 38.00, "quarter": 70.00, "ounce": 240.00 },
"thcPct": 22.4,
"cbdPct": 0.1,
"effects": ["euphoric", "creative", "energetic", "uplifted"],
"terpenes": ["myrcene", "caryophyllene", "limonene"],
"staffPick": false,
"inStock": true,
"imageUrl": "https://images.weedmaps.com/products/...",
"description": "A classic sativa-dominant hybrid with sweet berry aromas...",
"scrapedAt": "2025-01-15T14:22:05.000Z"
}

Menu item fields:

FieldDescription
strainTypeindica, sativa, hybrid, cbd, or null — sourced from all 4 platforms
dosageMgMilligrams per serving — populated for edibles, capsules, tinctures
thcPctTHC percentage (e.g. 22.4 for 22.4%) — available from Weedmaps, Leafly, iHeartJane, Dutchie
cbdPctCBD percentage — same sources
effectsArray of up to 10 effect strings (e.g. ["euphoric","creative","relaxed"]) — from Leafly strain data, iHeartJane, Dutchie
terpenesArray of up to 8 terpene names (e.g. ["myrcene","limonene"]) — from Leafly, iHeartJane, Dutchie
staffPickBoolean — staff-curated picks from Dutchie and iHeartJane
priceTiersPer-weight prices: halfGram, gram, twoGram, eighth, quarter, halfOz, ounce — from Weedmaps and iHeartJane
brandBrand/manufacturer name — enables brand market share analysis across dispensaries

This dataset is what makes the menu data genuinely valuable for market research — strain mix by dispensary, terpene preferences by region, brand distribution, effect profile trending across markets.

Webhook Events

Set webhookUrl to receive a POST request after each run. The payload is a JSON array of change events:

[
{
"event": "new_dispensary",
"dispensary": { "name": "Acme Cannabis", "address": { "city": "Denver", "state": "CO" }, ... },
"detectedAt": "2025-01-22T10:00:00.000Z"
},
{
"event": "license_suspended",
"dispensary": { "name": "Green Leaf Denver", ... },
"changedFields": ["licenseStatus"],
"detectedAt": "2025-01-22T10:00:00.000Z"
},
{
"event": "dispensary_updated",
"dispensary": { "name": "The Green Solution", ... },
"changedFields": ["hours.monday", "services.delivery"],
"detectedAt": "2025-01-22T10:00:00.000Z"
},
{
"event": "license_expiring",
"dispensary": { "name": "High Five Dispensary", "licenseExpiresDate": "2025-02-15", ... },
"daysUntilExpiry": 24,
"detectedAt": "2025-01-22T10:00:00.000Z"
}
]

Event types: new_dispensary, dispensary_closed, dispensary_updated, license_suspended, license_expired, license_expiring.

Note: rating-only changes are tracked in changedFields but do not trigger webhook delivery (too noisy at scale). All other field changes trigger delivery.

CHANGES Key (Key-Value Store)

Every run saves a structured change report to CHANGES in the default Key-Value store:

{
"summary": { "new": 3, "closed": 1, "updated": 8 },
"suppressedNew": 12,
"changes": [
{ "changeType": "new_dispensary", "dispensary": { "name": "New Store", "address": {...} }, "detectedAt": "..." },
{ "changeType": "updated", "dispensary": { "name": "Green Leaf", ... }, "changedFields": ["hours.monday"], "detectedAt": "..." }
]
}

RUN_HEALTH Key (Key-Value Store)

{
"overallStatus": "healthy",
"totalDispensaries": 712,
"deduplicationRate": "18%",
"sources": {
"weedmaps": { "status": "ok", "itemsScraped": 380, "errors": 0 },
"leafly": { "status": "ok", "itemsScraped": 290, "errors": 0 },
"state-ny": { "status": "ok", "itemsScraped": 88, "errors": 0 },
"state-pa": { "status": "degraded", "itemsScraped": 42, "errors": 1 }
},
"changesDetected": { "new": 3, "closed": 1, "updated": 8 }
}

Status values: ok · degraded (partial data) · failed (0 items) · suspicious_zero (zero when previous run had data — silent break).

MARKET_INTELLIGENCE Key (Key-Value Store)

Computed automatically after every run. Zero extra configuration needed.

{
"generatedAt": "2025-01-22T10:00:00.000Z",
"national": {
"totalDispensaries": 18247,
"medical": 4891,
"recreational": 9823,
"both": 3533,
"withDelivery": 3841,
"withPickup": 14322,
"chainAffiliated": 5734,
"independent": 12513,
"chainConcentration": 0.3143,
"avgRating": 4.21,
"stateCount": 43
},
"byState": {
"FL": {
"total": 2487,
"medical": 2487,
"recreational": 0,
"both": 0,
"chainAffiliated": 1823,
"chainConcentration": 0.7329,
"avgRating": 4.3,
"topChains": [
{ "chain": "Trulieve", "count": 134 },
{ "chain": "Curaleaf", "count": 57 },
{ "chain": "Fluent Cannabis Care", "count": 32 }
],
"withDelivery": 2100,
"sourceCoverage": ["weedmaps", "leafly", "state-fl"]
},
"CO": {
"total": 591,
"medical": 221,
"recreational": 370,
"both": 154,
"chainAffiliated": 187,
"chainConcentration": 0.3164,
"avgRating": 4.1,
"topChains": [
{ "chain": "Schwazze (Star Buds)", "count": 34 },
{ "chain": "LivWell", "count": 26 },
{ "chain": "Native Roots", "count": 18 }
],
"sourceCoverage": ["weedmaps", "leafly", "iheartjane", "state-co"]
}
},
"topChains": [
{ "chain": "Trulieve", "count": 187, "stateCount": 12, "states": ["FL","PA","MA","CT","MD","GA","AL","WV","OH","TX","CO","AZ"] },
{ "chain": "Curaleaf", "count": 156, "stateCount": 23, "states": ["FL","NY","PA","NJ","CT","MA","MD","OH","MI","IL","OR","AZ","CO","MO","OK","NV","UT","WV","MN","ND","SD","MS","ME"] },
{ "chain": "Verano", "count": 143, "stateCount": 14, "states": ["IL","OH","PA","NJ","MD","FL","MA","WV","NM","NV","AZ","AR","MO","MI"] }
],
"marketConcentration": {
"top5SharePct": 14.2,
"top10SharePct": 21.8,
"top25SharePct": 31.4,
"largestChain": "Trulieve",
"largestChainCount": 187,
"largestChainPct": 1.03
},
"recentActivity": {
"newDispensaries": 12,
"closedDispensaries": 3,
"updatedDispensaries": 47
}
}

This level of market intelligence — per-state chain concentration, MSO footprint, delivery penetration rates — costs thousands of dollars per report from traditional cannabis data vendors (Headset, BDSA, New Cannabis Ventures). Here it's a free KV output on every run.

EXPIRING_LICENSES Key (Key-Value Store)

{
"alertedAt": "2025-01-22T10:00:00.000Z",
"windows": {
"30": [{ "name": "High Five Dispensary", "licenseExpiresDate": "2025-02-15", "daysUntilExpiry": 24, "state": "CO" }],
"60": [...],
"90": [...]
}
}

Pricing — How much does it cost?

Run scopeApprox resultsEstimated cost
1 state, 1 platform source50–300< $0.05
Northeast corridor (PA MD DE NY NJ CT MA)1,500–2,500$0.15–$0.45
West Coast (CA OR WA)2,600–3,500$0.25–$0.60
Full default (9 states, 5 platform sources)4,000–7,000$0.40–$0.90
Full default + menu data4,000–7,000 dispensaries + menu items$1.00–$2.00
All 43 states, all 6 sources18,000–25,000$2.00–$4.00

Costs depend on Apify compute units. All platform sources use HTTP crawling (no browser, fast and cheap). Official state sources run 4 in parallel.

Tips

  • Free smoke test: testMode: true returns 3 results per source/state, skips the snapshot update, costs < $0.01. Run this first to verify the Actor works before a paid run
  • Weekly scheduling: Use Apify's built-in scheduler (Monday morning recommended). The first run builds the baseline — every subsequent run reports only what changed
  • Unlimited results: Set maxResultsPerSource: 0 to remove the per-source cap. Needed for CA (~1,200), WA (~700), OR (~700), CO (~550), MI (~500)
  • Targeted alerts: Combine webhookUrl with webhookStateFilter: ["CO", "CA"] to only receive webhook events for the states you care about — reduces noise for single-market operators
  • Adding a new state: Set suppressInitialStateChanges: false if you want new_dispensary events on the first run for a freshly added state. Default (true) suppresses the flood
  • Debugging: Check RUN_HEALTH in the Key-Value store — per-source item counts and suspicious_zero catch silent scraper breaks before they affect your pipeline
  • Proxy: Enable Apify proxy for large runs (500+ dispensaries) to reduce rate-limiting from Weedmaps and Leafly. Use RESIDENTIAL group in proxyConfiguration to unlock Dutchie coverage (~40% of US dispensaries)
  • Social media: enrichSocialMedia: true hits each dispensary's website and extracts Instagram, Facebook, Twitter/X, TikTok handles — great for marketing contact lists. Capped at 1,000 dispensaries per run

FAQ, Disclaimers, and Support

Is scraping dispensary data legal? This Actor scrapes publicly available information from dispensary listing platforms and official state government databases. It does not bypass authentication, access private data, or collect personally identifiable information beyond what is publicly posted. Users are responsible for complying with applicable platform Terms of Service and laws in their jurisdiction.

What if a source breaks? The Actor degrades gracefully — one failed source doesn't stop the run. All remaining sources continue, the failure is logged in RUN_HEALTH, and the suspicious_zero flag catches silent breaks (scraper ran but extracted nothing, often caused by a site redesign). The change detection regression guard also refuses to overwrite a valid snapshot if the new run returns 80%+ fewer records than the previous run.

What states are supported? 43 states/territories have dedicated official license database scrapers. All 6 platform sources cover every US state. States with small programs (Iowa: 5 dispensaries, New Hampshire: ~6, North Dakota: ~10) are fully supported — every active licensed dispensary is captured.

What is chain detection? The chain field is populated by pattern-matching on dispensary names to identify multi-state operators (MSOs): Curaleaf, Trulieve, Green Thumb (GTI), Verano, Acreage, Cannabist (Columbia Care), PharmaCann, Cresco Labs, MedMen, Dutchie, Planet 13, Cookies, Jars Cannabis, and 160+ others. Useful for filtering out chain locations when analyzing independent operators, or for tracking MSO expansion footprint.

Known limitations:

  • Dutchie requires a residential proxy to bypass Cloudflare Bot Management — not in the default sources list, but fully supported. Configure proxyConfiguration with useApifyProxy: true, apifyProxyGroups: ["RESIDENTIAL"] and add "dutchie" to sources
  • Colorado MED state source is intermittently 403 from some IP ranges — Weedmaps covers CO well as a fallback
  • Coordinates are null for some state-source-only records where the government database doesn't publish lat/lng. Enable geocodeMissingCoordinates to fill via OpenStreetMap
  • Menu data requires a separate pass per dispensary and can significantly increase run time for large states

Support: Open an issue on the Issues tab in Apify Console. For custom data pipelines, enterprise licensing, or state coverage requests, contact the author directly.