# Leafly Dispensary Scraper (`solidcode/leafly-scraper`) Actor

\[💰 $3.00 / 1K] Extract Leafly dispensary data at scale — names, addresses, phone, hours, ratings, delivery & pickup options, payment methods, licensing, and optional customer reviews. Search by city or state, or paste specific dispensary URLs.

- **URL**: https://apify.com/solidcode/leafly-scraper.md
- **Developed by:** [SolidCode](https://apify.com/solidcode) (community)
- **Categories:** Agents, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

## Leafly Dispensary Scraper

Pull complete cannabis dispensary profiles from Leafly at scale — 51 fields per store covering street address, phone, email, website, live hours, delivery radius and order minimums, payment acceptance, state license numbers and four separate star ratings, plus optional customer reviews with the dispensary's own replies. Built for cannabis brands mapping retail distribution, dispensary groups benchmarking competitors, and B2B sales teams that need a current, structured storefront list without copying pages out of a directory by hand.

### Why This Scraper?

- **A 51-field store profile, not a directory card** — every dispensary row is enriched from the store's own Leafly page: full `description`, `email`, `website`, `phone`, `licenseNumber`, parent `organizationName`, logo, cover photo and a full `photos` gallery. Search listings carry none of that.
- **Four separate star ratings, not one** — `rating` overall plus `qualityRating`, `serviceRating` and `atmosphereRating`, so you can tell a store with great product and bad service apart from one with the reverse — the split that actually explains a 4.2.
- **Delivery economics on every store** — `deliveryEnabled`, `deliveryFee`, `deliveryMinimum` and `deliveryRadiusMiles` alongside `pickupEnabled` and the quoted `pickupMinutesMinimum`/`pickupMinutesMaximum` wait window, so you can size a real fulfillment footprint instead of guessing which stores ship.
- **Four payment flags plus ATM presence** — `acceptsCash`, `acceptsCreditCards`, `acceptsDebitCards` and `hasAtm`: the exact fields payments, POS and lending vendors prospect on in a cash-heavy industry.
- **State license numbers and operator rollups** — `licenseNumber` straight off the store record wherever the store publishes one, plus `organizationName` and `organizationSlug` so storefronts belonging to a chain group cleanly into their multi-store operator for market-share math.
- **Reviews are opt-in and hard-capped** — `includeReviews` is off by default and `maxReviewsPerDispensary` bounds it per store, so one popular dispensary sitting on thousands of reviews can never quietly inflate your run.
- **Reviews include the dispensary's reply** — each review carries `staffResponse` and `staffResponseDate` next to `wouldRecommend`, `wouldShopAgain`, `upvotesCount` and the reviewer name, so you can measure which operators actually answer criticism and how quickly.
- **Two linked record types in one dataset** — every row carries a `recordType` of `dispensary` or `review`, and each review repeats `dispensaryName`, `dispensarySlug` and `dispensaryUrl` so review rows stand alone in a spreadsheet with no joins.
- **City, state or ZIP — one state sweeps 1,000+ stores** — `"Denver, CO"` targets a metro, `"Colorado"` returns over 1,000 dispensaries statewide, `"80202"` is accepted as another spelling of the same market, and pasted Leafly dispensary URLs skip search entirely to refresh a known account list.
- **Never the wrong city, quietly** — every search is checked against the location Leafly actually matched, so an entry that can't be placed is reported back to you instead of being answered with a full page of stores from another state or another country. That silent-wrong-area failure is the one that poisons a dataset without anyone noticing.
- **United States and Canada in the same run** — Los Angeles, Denver and Las Vegas storefronts alongside Toronto and Vancouver, each with `latitude`, `longitude` and `timeZone` for mapping, plus automatic de-duplication so a store appearing in two overlapping searches is returned — and billed — once.

### Use Cases

**Retail Distribution & Brand Expansion**
- Map every licensed storefront in a new state before a product launch, license numbers included
- Rank target accounts by rating and review volume to decide where a sales rep goes first
- Separate delivery-capable stores from pickup-only ones when planning fulfillment routes
- Spot white space by comparing dispensary density across neighboring metros

**B2B Sales & Lead Generation**
- Build outbound lists with direct phone, email and website for each store
- Segment by payment acceptance — cash-and-ATM-only stores are the warmest payments leads
- Target multi-store operators by grouping rows on `organizationSlug`
- Re-run a fixed list of dispensary URLs on a schedule to keep CRM records fresh

**Competitive & Market Intelligence**
- Track how many dispensaries operate in a metro month over month
- Benchmark quality, service and atmosphere ratings separately against nearby competitors
- Benchmark your rating, review count and follower count against nearby competitors
- Compare delivery fees and order minimums across a region to price your own service
- Monitor which stores keep an active menu using `hasMenuItems` and `lastMenuUpdate`

**Reputation & Customer Experience**
- Pull recent reviews across a competitor set and mine recurring complaint themes
- Measure staff-response coverage and lag from `staffResponse` and `staffResponseDate`
- Track the `wouldRecommend` rate per store as a simple loyalty signal
- Surface the most-upvoted reviews to see what customers actually amplify

**Delivery, Mapping & Tech Platforms**
- Seed a store directory with coordinates, time zones, weekly hours and logos
- Model delivery coverage from radius, fee and minimum-order values
- Prioritize integration targets by menu freshness and review volume
- Enrich an existing store database with photos, descriptions and cover imagery

### Getting Started

#### Simple — one city

```json
{
  "searchLocations": ["Denver, CO"]
}
````

#### Multi-market — full coverage, no cap

```json
{
  "searchLocations": ["Los Angeles, CA", "San Diego, CA", "Toronto, Ontario"],
  "maxDispensariesPerLocation": 0
}
```

`0` means every dispensary in the market, which is 1,000+ rows for a large metro or a whole state. Leave reviews off on a sweep this wide.

#### With customer reviews

```json
{
  "searchLocations": ["Denver, CO"],
  "maxDispensariesPerLocation": 30,
  "includeReviews": true,
  "maxReviewsPerDispensary": 50
}
```

Reviews multiply your row count: 30 stores × 50 reviews adds up to 1,500 review rows on top of the 30 store rows. Keep `maxReviewsPerDispensary` set — see the pricing note below.

#### Known account list — direct dispensary URLs

```json
{
  "searchLocations": [],
  "dispensaryUrls": [
    "https://www.leafly.com/dispensary-info/the-green-solution4afc",
    "https://www.leafly.com/dispensary-info/botanico5210"
  ],
  "includeReviews": true,
  "maxReviewsPerDispensary": 20
}
```

### Input Reference

#### What to Collect

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchLocations` | array of strings | `["Denver, CO"]` | US and Canadian cities, states, provinces or ZIP codes to find dispensaries in — `"Denver, CO"`, `"Colorado"`, `"80202"`, `"Toronto, ON"`, `"Vancouver, British Columbia"`. Each entry runs its own search. Anything that can't be matched to a US or Canadian market is reported back instead of returning another area's stores. |
| `dispensaryUrls` | array of strings | `[]` | Specific Leafly dispensary page URLs to collect directly. Use instead of, or alongside, location search. |

#### Limits & Reviews

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `maxDispensariesPerLocation` | integer | `20` | The most dispensaries to collect per location. **Results arrive 30 at a time, so any limit below 30 still returns — and bills for — 30 stores.** Set it in multiples of 30 for predictable counts. `0` collects every dispensary in that market (1,000+ rows for a whole state). Does not apply to pasted URLs — each URL is one dispensary. |
| `includeReviews` | boolean | `false` | Also collect customer reviews for each dispensary. Off by default, because reviews add extra rows. |
| `maxReviewsPerDispensary` | integer | `20` | When reviews are on, the most reviews to collect per dispensary — collected exactly, not rounded up. Every review is a billed row and a popular store can hold thousands, so `0` (all available) is best kept for short, targeted store lists. Ignored when reviews are off. |

### Output

Results arrive as a single dataset with two record types, told apart by the `recordType` field. Empty fields are removed from each row rather than returned as blanks.

#### `recordType: "dispensary"`

```json
{
  "recordType": "dispensary",
  "id": 20746,
  "slug": "the-green-solution4afc",
  "name": "The Green Solution - Wewatta St. @ Union Station",
  "url": "https://www.leafly.com/dispensary-info/the-green-solution4afc",
  "description": "One of the most-awarded dispensaries in Colorado...",
  "storeType": "dispensary",
  "phone": "720-990-9723",
  "email": "support@tgscolorado.com",
  "website": "https://www.tgscolorado.com/stores/denverwewatta",
  "address": "1995 Wewatta Street",
  "city": "Denver",
  "state": "CO",
  "postalCode": "80202",
  "country": "US",
  "latitude": 39.7566978,
  "longitude": -104.9980103,
  "rating": 4.6091,
  "qualityRating": 4.6,
  "serviceRating": 4.6272,
  "atmosphereRating": 4.6,
  "reviewCount": 110,
  "followerCount": 310,
  "openNow": true,
  "openUntil": "2026-07-24 23:45:00 -0600",
  "hours": "9am - 7pm Daily",
  "schedule": { "monday": { "open": "1901-01-01T09:00:00.000Z", "close": "1901-01-02T23:45:00.000Z", "isOpen": true } },
  "timeZone": "America/Denver",
  "deliveryEnabled": false,
  "deliveryFee": 0,
  "deliveryMinimum": 0,
  "deliveryRadiusMiles": 10,
  "pickupEnabled": true,
  "pickupMinutesMinimum": 15,
  "pickupMinutesMaximum": 30,
  "acceptsCash": true,
  "acceptsCreditCards": false,
  "acceptsDebitCards": true,
  "hasAtm": true,
  "licenseNumber": "402-00883",
  "offersMedicalCards": false,
  "isAdaAccessible": true,
  "hasVeteranDiscount": true,
  "hasMenuItems": true,
  "lastMenuUpdate": "2026-07-24T20:36:46.312Z",
  "organizationName": "The Green Solution - Colorado",
  "organizationSlug": "the-green-solution-colorado",
  "logoUrl": "https://images.leafly.com/menu/...png",
  "coverPhotoUrl": "https://leafly-public.imgix.net/dispensary/photos/...jpg",
  "photos": ["https://leafly-public.imgix.net/dispensary/photos/...jpg"],
  "scrapedAt": "2026-07-24T20:42:38Z"
}
```

##### Core & Identity

| Field | Type | Description |
|-------|------|-------------|
| `recordType` | string | Always `"dispensary"` for store rows |
| `id` | integer | Leafly's internal dispensary identifier |
| `slug` | string | URL slug for the dispensary |
| `name` | string | Dispensary name as displayed |
| `url` | string | Link to the dispensary page on Leafly |
| `storeType` | string | Store category as Leafly classifies it, e.g. `dispensary` |
| `description` | string | The store's own written description or bio |
| `organizationName` | string | Parent operator or chain, for stores that belong to one |
| `organizationSlug` | string | Stable identifier for that parent operator |
| `partial` | boolean | Present and `true` only if the full store page could not be loaded and a basic record was returned instead |
| `scrapedAt` | string | ISO-8601 timestamp of when the row was collected |

##### Address & Location

| Field | Type | Description |
|-------|------|-------------|
| `address` | string | Street address, including a second address line when present |
| `city` | string | City |
| `state` | string | State or province code |
| `postalCode` | string | ZIP or postal code |
| `country` | string | Country code, e.g. `US` or `CA` |
| `latitude` | number | Latitude of the storefront |
| `longitude` | number | Longitude of the storefront |
| `timeZone` | string | Store time zone, e.g. `America/Denver` |

##### Contact & Ratings

| Field | Type | Description |
|-------|------|-------------|
| `phone` | string | Public phone number |
| `email` | string | Public contact email |
| `website` | string | The store's own website |
| `rating` | number | Average overall star rating |
| `qualityRating` | number | Average rating reviewers gave for product quality |
| `serviceRating` | number | Average rating reviewers gave for staff and service |
| `atmosphereRating` | number | Average rating reviewers gave for the store atmosphere |
| `reviewCount` | integer | Total number of reviews on Leafly |
| `followerCount` | integer | Number of Leafly users following the store |

##### Hours & Menu

| Field | Type | Description |
|-------|------|-------------|
| `openNow` | boolean | Whether the store was open at collection time |
| `openUntil` | string | When the store's current opening period ends, with its local UTC offset |
| `hours` | string | Free-text opening hours as written by the store |
| `schedule` | object | Structured per-weekday schedule: opening time, closing time and an is-open flag for each day of the week |
| `hasMenuItems` | boolean | Whether the store currently publishes a product menu |
| `lastMenuUpdate` | string | ISO-8601 timestamp of the store's most recent menu change |

##### Delivery, Pickup & Payments

| Field | Type | Description |
|-------|------|-------------|
| `deliveryEnabled` | boolean | Whether the store delivers |
| `deliveryFee` | number | Delivery fee charged |
| `deliveryMinimum` | number | Minimum order value for delivery |
| `deliveryRadiusMiles` | number | How far the store delivers, in miles |
| `pickupEnabled` | boolean | Whether in-store pickup is offered |
| `pickupMinutesMinimum` | integer | Shortest quoted pickup wait, in minutes |
| `pickupMinutesMaximum` | integer | Longest quoted pickup wait, in minutes |
| `acceptsCash` | boolean | Cash accepted |
| `acceptsCreditCards` | boolean | Credit cards accepted |
| `acceptsDebitCards` | boolean | Debit cards accepted |
| `hasAtm` | boolean | ATM available on site |

##### Licensing, Amenities & Media

| Field | Type | Description |
|-------|------|-------------|
| `licenseNumber` | string | State or provincial license number, where the store publishes one |
| `offersMedicalCards` | boolean | Whether the store helps customers obtain medical cards |
| `isAdaAccessible` | boolean | Wheelchair and ADA accessibility |
| `hasVeteranDiscount` | boolean | Veteran discount offered |
| `logoUrl` | string | Store logo image |
| `coverPhotoUrl` | string | Cover photo image |
| `photos` | array of strings | Gallery image links from the store's page |

#### `recordType: "review"`

Returned only when `includeReviews` is enabled.

```json
{
  "recordType": "review",
  "dispensaryName": "The Green Solution - Wewatta St. @ Union Station",
  "dispensarySlug": "the-green-solution4afc",
  "dispensaryUrl": "https://www.leafly.com/dispensary-info/the-green-solution4afc",
  "reviewId": 3083575,
  "rating": 5,
  "content": "Great selection and the staff walked me through every concentrate on the shelf.",
  "createdAt": "2023-04-22T06:05:38.269Z",
  "wouldRecommend": true,
  "wouldShopAgain": true,
  "userName": "5........m",
  "upvotesCount": 3,
  "staffResponse": "Thank you so much for the kind words and for taking the time to review us!",
  "staffResponseDate": "2023-05-16T15:29:33.147Z",
  "scrapedAt": "2026-07-24T20:42:39Z"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `recordType` | string | Always `"review"` for review rows |
| `dispensaryName` | string | Name of the dispensary being reviewed |
| `dispensarySlug` | string | Slug of the parent dispensary, for joining back to store rows |
| `dispensaryUrl` | string | Link to the parent dispensary page |
| `reviewId` | integer | Leafly identifier for the review |
| `rating` | number | Star rating the reviewer gave, 1 to 5 |
| `content` | string | Full review text |
| `createdAt` | string | ISO-8601 date the review was posted |
| `wouldRecommend` | boolean | Whether the reviewer would recommend the store |
| `wouldShopAgain` | boolean | Whether the reviewer would shop there again |
| `userName` | string | Reviewer display name as shown by Leafly |
| `upvotesCount` | integer | How many people found the review helpful |
| `staffResponse` | string | The dispensary's public reply, when one exists |
| `staffResponseDate` | string | ISO-8601 date of that reply |
| `scrapedAt` | string | ISO-8601 timestamp of when the row was collected |

### Tips for Best Results

- **Write Canadian markets any way you like.** `"Toronto, ON"`, `"Toronto, Ontario"` and `"Vancouver, British Columbia"` all land on the right province — codes and spelled-out names work identically across all 13 provinces and territories, and accents in names like `"Montréal, Québec"` are handled for you. If a location can't be matched with certainty it's reported instead of quietly returning a nearby region.
- **A ZIP is another spelling of the market, not a smaller radius.** `"80202"` and `"Denver"` return the same metro-wide result set, so use a ZIP when it is simply the address format you already have — not to tighten a trade area. `"City, ST"` is the most reliable form and always worth preferring; if you need a genuinely small area, filter the returned `latitude`/`longitude` afterwards.
- **State names run a census.** `"Colorado"` alone returns over 1,000 dispensaries. Pair it with `maxDispensariesPerLocation: 0` for complete statewide coverage, expect a longer run and a much larger dataset, and leave reviews switched off on a sweep that wide.
- **Cap reviews, always.** The default run is one clean row per dispensary. When you want sentiment, `maxReviewsPerDispensary` between 20 and 50 captures the recent, most relevant feedback. `0` means every review a store has ever received — on a large store list that is tens of thousands of extra billed rows, so save it for a short, named set of dispensaries.
- **Results come back 30 at a time.** Caps land on the next multiple of 30 rather than cutting a page short, so a cap of 20 and a cap of 30 both return — and bill for — 30 stores. Set caps in multiples of 30 for predictable counts. Review caps are different: those are collected to the exact number you ask for.
- **Check the `partial` column on very large runs.** Almost every row is the full store profile, but if a store's page won't load, its listing information is kept and the row is flagged `partial` rather than dropped — so you never lose a dispensary. Re-running usually fills those few rows in.
- **Stack overlapping metros freely.** List `"Los Angeles, CA"`, `"Santa Monica, CA"` and `"Long Beach, CA"` in one run — stores appearing in more than one search are returned once, so overlap costs you nothing.
- **Group on `organizationSlug` before you count.** Many storefronts belong to the same operator, so per-store totals overstate how many distinct companies compete in a market. Rolling up first is what turns the dataset into real market share.

### Pricing

**From $3.00 per 1,000 results** — flat pay-per-result pricing for complete dispensary profiles and customer reviews. No compute or time-based charges — you pay per result, plus a small fixed per-run start fee. Bronze, Silver, and Gold subscribers pay progressively less; the table below shows total cost at each discount tier.

| Results | No discount | Bronze | Silver | Gold |
|---------|-------------|--------|--------|------|
| 100 | $0.36 | $0.34 | $0.32 | $0.30 |
| 1,000 | $3.60 | $3.40 | $3.20 | $3.00 |
| 10,000 | $36.00 | $34.00 | $32.00 | $30.00 |
| 100,000 | $360.00 | $340.00 | $320.00 | $300.00 |

A "result" is any row in the output dataset. Each dispensary is one result, and when review collection is enabled **each review is also one result** — so a run with reviews turned on returns, and bills for, more rows than the same run without them. One flat rate covers both, and `maxReviewsPerDispensary` puts a hard ceiling on how many review rows a single store can add. Any Apify platform fees are additional and depend on your plan.

### Integrations

Export data in JSON, CSV, Excel, XML, or RSS. Connect to 1,500+ apps via:

- **Zapier** / **Make** / **n8n** — Workflow automation
- **Google Sheets** — Direct spreadsheet export
- **Slack** / **Email** — Notifications on new results
- **Webhooks** — Trigger custom apps when a run finishes
- **Apify API** — Full programmatic access

### Legal & Ethical Use

This scraper collects publicly listed business information — storefront names, addresses, contact details, published hours, license numbers, and publicly visible customer reviews. Use it for market research, competitive analysis, lead generation, and directory building, and always in line with Leafly's terms of service and applicable law.

Cannabis is a regulated industry with rules that differ by state, province, and country. You are responsible for ensuring your use of this data complies with the marketing, advertising, and licensing regulations that apply to you. Handle reviewer names and review text responsibly and in accordance with applicable data protection laws, including GDPR and CCPA where relevant. Do not use this data to contact individual reviewers or for any unlawful purpose.

# Actor input Schema

## `searchLocations` (type: `array`):

Cities, states, or areas in the United States or Canada to find dispensaries in, such as 'Denver, CO', 'Colorado', '80202' or 'Toronto, ON'. Each entry runs its own search. 'City, ST' is the most reliable format — if an entry can't be matched to a US or Canadian market it is reported instead of returning another area's stores.

## `dispensaryUrls` (type: `array`):

Paste specific Leafly dispensary page URLs to scrape those dispensaries directly. Optional — use instead of or alongside location search.

## `maxDispensariesPerLocation` (type: `integer`):

The most dispensaries to collect for each location you search. Leafly returns results 30 at a time, so any limit below 30 still returns — and bills for — 30 dispensaries; set the limit in multiples of 30 for predictable counts. Set to 0 to collect every dispensary in the market, which can mean 1,000+ rows for a whole state. Very large runs may return a few stores with basic listing information only; those rows are marked 'partial'. Does not apply to pasted URLs (each URL is one dispensary).

## `includeReviews` (type: `boolean`):

Also collect customer reviews for each dispensary. Off by default — reviews add extra rows and cost, so turn this on only when you need review data.

## `maxReviewsPerDispensary` (type: `integer`):

When reviews are enabled, the most reviews to collect for each dispensary. Every review is a separate billed row, and a popular store can hold thousands — 20 to 50 keeps the recent, most useful feedback. Set to 0 to collect all available, but avoid pairing 0 here with 0 above: a whole state with unlimited reviews can run to hundreds of thousands of rows. Ignored when reviews are off.

## Actor input object example

```json
{
  "searchLocations": [
    "Denver, CO"
  ],
  "dispensaryUrls": [],
  "maxDispensariesPerLocation": 20,
  "includeReviews": false,
  "maxReviewsPerDispensary": 20
}
```

# Actor output Schema

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

Table of dispensaries with key fields like name, rating, address, and services.

## `details` (type: `string`):

Full per-dispensary rows including delivery, pickup, payments, licensing, and organization, with a limited-detail flag on any store whose full page could not be loaded.

## `reviews` (type: `string`):

Per-review rows (when reviews are enabled), each tagged with its parent dispensary.

# 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 = {
    "searchLocations": [
        "Denver, CO"
    ],
    "dispensaryUrls": [],
    "maxDispensariesPerLocation": 20,
    "includeReviews": false,
    "maxReviewsPerDispensary": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("solidcode/leafly-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 = {
    "searchLocations": ["Denver, CO"],
    "dispensaryUrls": [],
    "maxDispensariesPerLocation": 20,
    "includeReviews": False,
    "maxReviewsPerDispensary": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("solidcode/leafly-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "searchLocations": [
    "Denver, CO"
  ],
  "dispensaryUrls": [],
  "maxDispensariesPerLocation": 20,
  "includeReviews": false,
  "maxReviewsPerDispensary": 20
}' |
apify call solidcode/leafly-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=solidcode/leafly-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Leafly Dispensary Scraper",
        "description": "[💰 $3.00 / 1K] Extract Leafly dispensary data at scale — names, addresses, phone, hours, ratings, delivery & pickup options, payment methods, licensing, and optional customer reviews. Search by city or state, or paste specific dispensary URLs.",
        "version": "1.0",
        "x-build-id": "aL0XsxMARjeBtvRpv"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/solidcode~leafly-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-solidcode-leafly-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/solidcode~leafly-scraper/runs": {
            "post": {
                "operationId": "runs-sync-solidcode-leafly-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/solidcode~leafly-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-solidcode-leafly-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchLocations": {
                        "title": "Search Locations",
                        "type": "array",
                        "description": "Cities, states, or areas in the United States or Canada to find dispensaries in, such as 'Denver, CO', 'Colorado', '80202' or 'Toronto, ON'. Each entry runs its own search. 'City, ST' is the most reliable format — if an entry can't be matched to a US or Canadian market it is reported instead of returning another area's stores.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "dispensaryUrls": {
                        "title": "Dispensary URLs",
                        "type": "array",
                        "description": "Paste specific Leafly dispensary page URLs to scrape those dispensaries directly. Optional — use instead of or alongside location search.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxDispensariesPerLocation": {
                        "title": "Max Dispensaries Per Location",
                        "minimum": 0,
                        "type": "integer",
                        "description": "The most dispensaries to collect for each location you search. Leafly returns results 30 at a time, so any limit below 30 still returns — and bills for — 30 dispensaries; set the limit in multiples of 30 for predictable counts. Set to 0 to collect every dispensary in the market, which can mean 1,000+ rows for a whole state. Very large runs may return a few stores with basic listing information only; those rows are marked 'partial'. Does not apply to pasted URLs (each URL is one dispensary).",
                        "default": 20
                    },
                    "includeReviews": {
                        "title": "Include Customer Reviews",
                        "type": "boolean",
                        "description": "Also collect customer reviews for each dispensary. Off by default — reviews add extra rows and cost, so turn this on only when you need review data.",
                        "default": false
                    },
                    "maxReviewsPerDispensary": {
                        "title": "Max Reviews Per Dispensary",
                        "minimum": 0,
                        "type": "integer",
                        "description": "When reviews are enabled, the most reviews to collect for each dispensary. Every review is a separate billed row, and a popular store can hold thousands — 20 to 50 keeps the recent, most useful feedback. Set to 0 to collect all available, but avoid pairing 0 here with 0 above: a whole state with unlimited reviews can run to hundreds of thousands of rows. Ignored when reviews are off.",
                        "default": 20
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
