# Dutchie Dispensary & Menu Scraper - Cannabis Prices (`confidential_gnat/dutchie-dispensary-menu-scraper`) Actor

Scrape Dutchie (dutchie.com) cannabis dispensaries and menus: products by size, recreational and medical prices, specials, THC and CBD, stock, hours and location. Search by city, zip or state. Cache returns only new or changed products. Export JSON, CSV or Excel.

- **URL**: https://apify.com/confidential_gnat/dutchie-dispensary-menu-scraper.md
- **Developed by:** [ActorFlow](https://apify.com/confidential_gnat) (community)
- **Security:** Limited permissions
- **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. 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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Dutchie (dutchie.com) Dispensary & Menu Scraper - Cannabis Prices

**Scrape cannabis dispensaries and menus from Dutchie (dutchie.com)**: every product by size with **recreational and medical prices**, live specials, THC and CBD, stock, brand and category, plus the store's address, phone, hours and coordinates. Paste a dispensary menu link, or search by **city, zip code, coordinates or whole state**, and press Start. Export **JSON, CSV or Excel**, or call it as an **API**.

**Target website:** [dutchie.com](https://dutchie.com)

![Dutchie Dispensary Menu Scraper cover: recreational and medical prices on every size, only what changed](https://i.postimg.cc/qMhQTSqj/Gemini-Generated-Image-cbppo3cbppo3cbpp.jpg)

### ✨ Features of this Dutchie dispensary and menu scraper

- **Full menu extraction** — one row per product size with brand, category, subcategory, strain type, THC, CBD, terpenes, cannabinoids, effects, images and an optional description.
- **Recreational and medical prices** — both prices are saved on every row, and you choose which menu is the shelf price.
- **Specials and sales** — live special names, kinds and dates, the sale price, and a specials-only filter.
- **Stock** — units available for each size and an in-stock flag.
- **Find dispensaries** — search by city and state, by zip or postal code with a radius, by coordinates, or cover a whole state or province in one run.
- **Dispensary details** — name, address, phone, chain, time zone, coordinates, pickup and delivery hours, and order options repeated on every product row. A dispensary-only mode saves just the store details without opening any menu.
- **Brand, store name and review filters** — keep only chosen brands or stores whose name contains a word, and add customer reviews (author, rating, text, effects) to reviewed products.
- **Pagination support** — whole menus of thousands of products are read page by page.
- **Category and menu filters** — keep only Flower, Pre-Rolls, Edibles and so on, and choose the recreational or medical menu.
- **Cache, only new or changed products** — repeat runs return only products with a new price, special or stock.
- **Closed and test stores skipped** — location searches keep real, open stores unless you ask for the rest.
- **No browser required** — plain data requests make runs fast and light.

### 🚀 How to scrape Dutchie menus in 5 steps

1. [Sign up](https://apify.com/sign-up) for a free Apify account — includes **$5 monthly credit**.
2. Open the actor page and click **Try for free**.
3. Paste one or more Dutchie dispensary links in **Dispensary URLs**, or add **Search dispensaries by location**.
4. Click **Start** and wait for the run to complete.
5. Download results from the **Output** tab in JSON, CSV, or Excel format.

You can also run this actor via the [Apify API](https://docs.apify.com/api/v2) or integrate it directly into your workflows using [Zapier](https://zapier.com/apps/apify), [Make](https://www.make.com/), or [n8n](https://n8n.io/).

### 💰 Pricing for the Dutchie scraper

This actor uses **pay-per-result** billing: you pay for the rows saved. A product with three sizes makes three rows.

- New Apify accounts include **$5 of free monthly credit**.
- The cache skips products that did not change, so scheduled runs cost less over time.
- It uses plain data requests instead of a browser, so it costs significantly less to run than browser-based scrapers.

### 🖼️ Dutchie scraper input screenshot

![Dutchie Dispensary Menu Scraper input form in Apify Console: dispensary URLs, max products per dispensary, cache project name, search by location, what to save, menu type, categories and specials only](https://i.postimg.cc/Gh8zCVty/Gemini-Generated-Image-whq5pbwhq5pbwhq5.jpg)

The numbers match the input fields below:

1. **Dispensary URLs**: Dutchie menu links to scrape.
2. **Max products per dispensary**: how many product rows are saved for each store.
3. **Cache project name**: reuse the same name on each run to get only new or changed products.
4. **Search dispensaries by location**: find stores by city, zip code, coordinates or state.
5. **What to save**: menu products, or only the dispensary details.
6. **Menu type**: which menu's price is the shelf price, recreational or medical.
7. **Categories**: keep only the chosen menu categories.
8. **Specials only**: keep only products with a live sale or special.

### 🔧 Dutchie scraper input configuration

The form starts with the dispensary links, the product limit and the cache name. Everything else is in the collapsible optional settings and filters.

| Field | Type | Required | Default | Description |
| ----- | ---- | -------- | ------- | ----------- |
| Dispensary URLs (`startUrls`) | array | — | example menu | Dutchie dispensary menu links, embedded menu links and product page links. |
| Max products per dispensary (`maxItems`) | integer | — | 5 | Product rows saved for each dispensary. |
| Cache project name (`cacheProjectName`) | string | — | — | Same name on each run to get only new or changed products. |
| Search dispensaries by location (`searchLocations`) | array | — | — | One search per line: `Boston, MA`, a zip or postal code, `42.36,-71.06`, or a state or province code such as `CO`. |
| Search radius (`radiusMiles`) | integer | — | 25 | Miles around a zip code or coordinates, up to 150. |
| Max dispensaries per search (`maxDispensaries`) | integer | — | 5 | Stores kept per location search, nearest first. |
| What to save (`outputMode`) | string | — | products | Menu products (one row per size) or dispensary details only. |
| Max rows in total (`maxTotalItems`) | integer | — | — | Optional cap for the whole run. |
| Menu type (`menuType`) | string | — | rec | Recreational or medical menu for the shelf price. |
| Categories (`categories`) | array | — | — | Keep only these categories. |
| Specials only (`offersOnly`) | boolean | — | off | Keep only products with a live special or sale. |
| Include product descriptions (`includeDescriptions`) | boolean | — | off | Adds the full product description to every row. |
| Include closed and test stores (`includeClosedStores`) | boolean | — | off | Keep stores that are not open and test or demo stores in location searches. |
| Store name contains (`storeNames`) | array | — | — | Keep only stores whose name contains one of these words, for example a chain name. |
| Brands (`brands`) | array | — | — | Keep only products of these brands. |
| Include product reviews (`includeReviews`) | boolean | — | off | Adds customer reviews to products that have them. |
| Max reviews per product (`maxReviewsPerProduct`) | integer | — | 5 | Newest reviews kept per product. |

**Supported URL types:**

- Dispensary menu: `https://dutchie.com/dispensary/pinnacle-cannabis-quincy`
- Embedded menu: `https://dutchie.com/embedded-menu/<store-name>`
- Product page: `https://dutchie.com/dispensary/<store-name>/product/<product>`

**Search locations:** `Boston, MA` searches that city, `02169` or `42.36,-71.06` search the radius around the point, and `CO` covers a whole state with overlapping searches. A store found by several searches is saved once.

### 📦 Dutchie scraper output data

Every record has the same keys (`null` when there is no value): `recordType`, `dispensaryId`, `dispensaryName`, `dispensarySlug`, `dispensaryUrl`, `dispensaryAddress`, `city`, `state`, `zipcode`, `country`, `dispensaryPhone`, `latitude`, `longitude`, `timezone`, `chain`, `storeStatus`, `offersPickup`, `offersDelivery`, `recreational`, `medical`, `pickupHours`, `deliveryHours`, `dispensaryEmail`, `dispensaryDescription`, `logoImage`, `bannerImage`, `menuCategories`, `distanceMiles`, `dispensaryCreatedAt`, `productId`, `productName`, `productUrl`, `brand`, `category`, `subcategory`, `strainType`, `size`, `sizeLabel`, `menuType`, `price`, `specialPrice`, `recPrice`, `medPrice`, `recSpecialPrice`, `medSpecialPrice`, `currency`, `onSpecial`, `specials`, `thc`, `cbd`, `thcValue`, `cbdValue`, `totalTerpenes`, `terpenes`, `cannabinoids`, `effects`, `quantityAvailable`, `inStock`, `imageUrl`, `images`, `description`, `medicalOnly`, `recreationalOnly`, `rating`, `reviewCount`, `reviews`, `productCreatedAt`, `productUpdatedAt`, `changeType`, `scrapedAt`. Product rows have `recordType: product`, dispensary-only rows have `recordType: dispensary` and leave the product fields empty.

There are 2 views: **Menu products** shows the product, brand, category, size, price, special price, THC, CBD and stock, and **Dispensaries** shows the store details.

**Output at a glance:**

| Product | Brand | Size | Price | Special | THC | Stock |
| ------- | ----- | ---- | ----- | ------- | --- | ----- |
| [Jointz Sports Balm RSO CBD](https://dutchie.com/dispensary/pinnacle-cannabis-quincy/product/jointz-sports-balm-rso-cbd) | Jointz | 0.01g | 50 |  | 848.34mg | 21 |
| [Rosin Capsules 100mg](https://dutchie.com/dispensary/pinnacle-cannabis-quincy/product/rosin-capsules-100mg) | Harbor House Collective | .1g | 20 |  | 100mg | 10 |
| [Trop Cherry x Cherry Whip 1g Live Hash Rosin](https://dutchie.com/dispensary/pinnacle-cannabis-quincy/product/trop-cherry-x-cherry-whip-1g-live-hash-rosin) | Brown Bag | 1g | 47.5 |  | 81.24mg | 1 |
| [Yellow Zushi](https://dutchie.com/dispensary/colorado-wellness-inc/product/yellow-zushi-93847) | DRO | 1/4oz | 49.99 | 34.99 |  | 10 |
| [Vanilla Berry Pie](https://dutchie.com/dispensary/colorado-wellness-inc/product/vanilla-berry-pie-47330) | DRO | 1/2oz | 65.99 | 46.19 |  | 3 |

**Sample output (raw JSON):**

```json
[
  {
    "recordType": "product",
    "dispensaryId": "670ec32b882fe8cc1a14c248",
    "dispensaryName": "Pinnacle Cannabis - Quincy",
    "dispensarySlug": "pinnacle-cannabis-quincy",
    "dispensaryUrl": "https://dutchie.com/dispensary/pinnacle-cannabis-quincy",
    "dispensaryAddress": "15 Liberty Street, Quincy, MA 02169, USA",
    "city": "Quincy",
    "state": "MA",
    "zipcode": "02169",
    "country": "United States",
    "dispensaryPhone": "(617) 481-5472",
    "latitude": 42.2404373,
    "longitude": -71.0060973,
    "timezone": "America/New_York",
    "chain": "pinnacle-cannabis",
    "storeStatus": "open",
    "offersPickup": true,
    "offersDelivery": false,
    "recreational": true,
    "medical": false,
    "pickupHours": {
      "Monday": "8:00 AM - 11:00 PM",
      "Tuesday": "8:00 AM - 11:00 PM",
      "Wednesday": "8:00 AM - 11:00 PM",
      "Thursday": "8:00 AM - 11:00 PM",
      "Friday": "8:00 AM - 11:00 PM",
      "Saturday": "8:00 AM - 11:00 PM",
      "Sunday": "8:00 AM - 11:00 PM"
    },
    "deliveryHours": null,
    "dispensaryEmail": null,
    "dispensaryDescription": null,
    "logoImage": null,
    "bannerImage": null,
    "menuCategories": null,
    "distanceMiles": null,
    "dispensaryCreatedAt": null,
    "productId": "6920de89f7e7fb59bb757cd9",
    "productName": "Jointz Sports Balm RSO CBD",
    "productUrl": "https://dutchie.com/dispensary/pinnacle-cannabis-quincy/product/jointz-sports-balm-rso-cbd",
    "brand": "Jointz",
    "category": "Topicals",
    "subcategory": "balms",
    "strainType": "2 to 1",
    "size": "0.01g",
    "sizeLabel": "0.01g",
    "menuType": "rec",
    "price": 50,
    "specialPrice": null,
    "recPrice": 50,
    "medPrice": 50,
    "recSpecialPrice": null,
    "medSpecialPrice": null,
    "currency": "USD",
    "onSpecial": false,
    "specials": null,
    "thc": "848.34mg",
    "cbd": "1530mg",
    "thcValue": 848.34,
    "cbdValue": 1530,
    "totalTerpenes": null,
    "terpenes": null,
    "cannabinoids": [
      {
        "name": "CBD (Cannabidiol)",
        "value": 25.5,
        "unit": "MILLIGRAMS_PER_GRAM"
      },
      {
        "name": "CBN (Cannabinol)",
        "value": 3.14,
        "unit": "MILLIGRAMS_PER_GRAM"
      }
    ],
    "effects": {
      "relaxed": 5
    },
    "quantityAvailable": 21,
    "inStock": true,
    "imageUrl": "https://s3-us-west-2.amazonaws.com/dutchie-images/010263bb19929ffa3b181609a220c6ed",
    "images": [
      "https://s3-us-west-2.amazonaws.com/dutchie-images/010263bb19929ffa3b181609a220c6ed"
    ],
    "description": "1:4 (RSO:CBD) Muscle Salve\n?\n\nJointz Muscle Salve has a strong aroma of menthol and other essential oils. It's a solid salve that begins to melt with body he...",
    "medicalOnly": false,
    "recreationalOnly": false,
    "rating": null,
    "reviewCount": null,
    "productCreatedAt": "2025-11-21T21:50:01.657Z",
    "productUpdatedAt": "2026-11-02T23:35:22.635Z",
    "changeType": null,
    "scrapedAt": "2026-11-04T17:05:05.728Z"
  },
  {
    "recordType": "product",
    "dispensaryId": "wPM2uAQJsEk2CZyTn",
    "dispensaryName": "Good Chemistry (Colfax)",
    "dispensarySlug": "good-chemistry-colfax",
    "dispensaryUrl": "https://dutchie.com/dispensary/good-chemistry-colfax",
    "dispensaryAddress": "330 E Colfax Ave, Denver, CO 80203, USA",
    "city": "Denver",
    "state": "CO",
    "zipcode": "80203",
    "country": "United States",
    "dispensaryPhone": "(720) 524-4657",
    "latitude": 39.7398235,
    "longitude": -104.982628,
    "timezone": "US/Mountain",
    "chain": "good-chemistry",
    "storeStatus": "open",
    "offersPickup": true,
    "offersDelivery": false,
    "recreational": true,
    "medical": false,
    "pickupHours": {
      "Monday": "9:00 AM - 8:45 PM",
      "Tuesday": "9:00 AM - 8:45 PM",
      "Wednesday": "9:00 AM - 8:45 PM",
      "Thursday": "9:00 AM - 8:45 PM",
      "Friday": "9:00 AM - 8:45 PM",
      "Saturday": "9:00 AM - 8:45 PM",
      "Sunday": "11:00 AM - 8:30 PM"
    },
    "deliveryHours": {
      "Monday": "8:00 AM - 9:00 PM",
      "Tuesday": "8:00 AM - 9:00 PM",
      "Wednesday": "8:00 AM - 9:00 PM",
      "Thursday": "8:00 AM - 9:00 PM",
      "Friday": "8:00 AM - 9:00 PM",
      "Saturday": "8:00 AM - 9:00 PM",
      "Sunday": "10:00 AM - 9:00 PM"
    },
    "dispensaryEmail": null,
    "dispensaryDescription": null,
    "logoImage": null,
    "bannerImage": null,
    "menuCategories": null,
    "distanceMiles": null,
    "dispensaryCreatedAt": null,
    "productId": "6ae2646bcd98150023776cc3",
    "productName": "GC Popcorn Biscotti",
    "productUrl": "https://dutchie.com/dispensary/good-chemistry-colfax/product/gc-popcorn-biscotti",
    "brand": "Good Chemistry Nurseries",
    "category": "Flower",
    "subcategory": "smalls-popcorn",
    "strainType": "Indica",
    "size": "1g",
    "sizeLabel": "1.0g",
    "menuType": "rec",
    "price": 5.01,
    "specialPrice": 5.01,
    "recPrice": 5.01,
    "medPrice": 5.01,
    "recSpecialPrice": 5.01,
    "medSpecialPrice": 5.01,
    "currency": "USD",
    "onSpecial": true,
    "specials": null,
    "thc": "21.17%",
    "cbd": null,
    "thcValue": 21.17,
    "cbdValue": null,
    "totalTerpenes": null,
    "terpenes": null,
    "cannabinoids": null,
    "effects": {
      "Relaxed": 9,
      "Pain-Relief": 7,
      "Sleepy": 8,
      "Happy": 8,
      "Euphoric": 8
    },
    "quantityAvailable": 4,
    "inStock": true,
    "imageUrl": "https://s3-us-west-2.amazonaws.com/dutchie-images/flower-stock-12-v1.jpg",
    "images": null,
    "description": null,
    "medicalOnly": false,
    "recreationalOnly": false,
    "rating": null,
    "reviewCount": null,
    "productCreatedAt": "2026-10-28T21:08:59.797Z",
    "productUpdatedAt": "2026-11-03T18:37:15.962Z",
    "changeType": null,
    "scrapedAt": "2026-11-04T17:07:59.753Z"
  }
]
```

### 🔁 Scrape only new or changed Dutchie products with the cache

Set the same **Cache project name** on every scheduled run. Products already saved under that name with the same price, special and stock are skipped, not charged and not counted towards the maximums, so each run returns only products that are new (`changeType: "new"`) or whose price, special or stock changed (`changeType: "updated"`). Different names keep separate caches. Combine it with Apify Schedules to track a store's menu every day.

### 🐍 How to scrape Dutchie with Python, JavaScript or the API

Run the actor programmatically with the official Apify clients. Replace `<YOUR_API_TOKEN>` with the token from your [Apify Console](https://console.apify.com/account/integrations).

**Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")

run = client.actor("confidential_gnat/dutchie-dispensary-menu-scraper").call(run_input={
    "startUrls": [{"url": "https://dutchie.com/dispensary/pinnacle-cannabis-quincy"}],
    "maxItems": 50,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

**JavaScript** (`npm install apify-client`):

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });

const run = await client.actor('confidential_gnat/dutchie-dispensary-menu-scraper').call({
    startUrls: [{ url: 'https://dutchie.com/dispensary/pinnacle-cannabis-quincy' }],
    maxItems: 50,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

**cURL** — start a run and wait for the dataset:

```bash
curl -X POST "https://api.apify.com/v2/acts/confidential_gnat~dutchie-dispensary-menu-scraper/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"startUrls": [{"url": "https://dutchie.com/dispensary/pinnacle-cannabis-quincy"}], "maxItems": 50}'
```

### 💡 What you can use Dutchie menu data for

- Price monitoring and price comparison across dispensaries in a city or state
- Tracking specials, sales and mix-and-match deals over time
- Brand and assortment analysis: which brands, strains and sizes each store carries
- Market research on recreational versus medical pricing and potency
- Building a dispensary directory or lead list with addresses, phones, hours and coordinates

Cannabis brands, retailers, analysts, marketplaces and data teams typically use this data for pricing, distribution and competitor research.

### ⚠️ Limitations of the Dutchie scraper

- **Dutchie stores only** — it reads menus that are hosted on Dutchie. Stores listed only on other platforms are not covered.
- **Location search needs a place** — a state is covered with overlapping searches, a zip code or coordinates use a radius of up to 150 miles, and a state name alone as text (for example `Colorado`) is not understood: use the code (`CO`).
- **Hidden products** — products the store hides because of low stock thresholds do not show on its menu and are not returned.
- **Reviews** — ratings, review counts and reviews are filled only for products that customers have reviewed. Reviewers appear as first name and last initial.
- **No store license numbers** — Dutchie does not publish license numbers on its menus, so they are not returned.

### ❓ Dutchie scraper FAQ

#### Can I scrape Dutchie legally?

The actor only collects menu and store data that is already publicly visible on dutchie.com, with no login or private content. Scraping publicly available data is generally considered lawful (see *hiQ Labs v. LinkedIn*), but you are responsible for complying with Dutchie's Terms of Service and the laws that apply to you, including cannabis advertising and privacy rules.

#### What data does the Dutchie scraper return?

One row per product size with the store details, brand, category, strain type, prices for both menus, specials, THC and CBD, terpenes, cannabinoids, effects, stock and images. Switch on **Include product descriptions** for the full description, or choose **Dispensary details only** to save just the stores.

#### How many products can I scrape from one dispensary?

**Max products per dispensary** limits the rows saved for each store, and **Max rows in total** can cap the whole run. Menus are read 100 products per page with no depth limit, so a store with thousands of products can be scraped in full by raising the limit.

#### How do I find all dispensaries in a city, zip code or state?

Add the place to **Search dispensaries by location** (`Boston, MA`, `02169`, `42.36,-71.06` or `CO`) and raise **Max dispensaries per search**. Use **Dispensary details only** first if you want to list the stores before reading their menus.

#### How do I scrape Dutchie with Python?

Use the Python example above: start the actor with `ApifyClient` and iterate over the dataset items to get every row.

#### Can I run this Dutchie scraper on a schedule?

Yes. Use Apify Schedules and set the same **Cache project name** on each run, so every run saves only products that are new or whose price, special or stock changed.

#### What output formats are supported?

JSON, CSV, Excel, XML and RSS, either from the **Output** tab or through the Apify API.

#### Why do some products have no THC or strain type?

Stores publish potency and strain type only for products that have them, so accessories and apparel, for example, leave those fields `null`.

### 🔗 Relevant actors for Dutchie and price data

| Scraper | Description |
| ------- | ----------- |
| [🍷 Total Wine Scraper](https://apify.com/confidential_gnat/totalwine-scraper) | Scrape Total Wine & More wine, liquor and beer prices, sizes, ratings and stock. |
| [🇺🇸 Yellow Pages USA Scraper - Emails & Leads](https://apify.com/confidential_gnat/yellowpages-usa-scraper) | Scrape US businesses with emails: name, phone, address and website. |
| [🛒 Google Shopping Scraper - Prices, Deals & Product Data](https://apify.com/confidential_gnat/google-shopping-scraper) | Scrape Google Shopping product listings, prices and deals for any search. |
| [🛍️ eBay Listings Scraper](https://apify.com/confidential_gnat/ebay-listings-scraper) | Scrape eBay search results and item pages: title, price, condition and seller. |

### 🔗 Other actors you may find useful

| Scraper | Description |
| ------- | ----------- |
| [🧴 Incidecoder Scraper](https://apify.com/confidential_gnat/incidecoder-scraper) | Scrapes skincare product pages with full ingredient lists. |
| [✈️ Kiwi.com Flight Scraper](https://apify.com/confidential_gnat/kiwi-flight-scraper) | Scrapes flight prices and schedules from Kiwi.com. |
| [🔎 WHOIS Domain Lookup Scraper](https://apify.com/confidential_gnat/whois-com) | Bulk WHOIS lookups from URLs, bare domains or whois.com links. |
| [📄 Google Patents Scraper](https://apify.com/confidential_gnat/google-patents-scraper) | Scrapes patent data from Google Patents by keyword or URL. |
| [💼 Dice Jobs Scraper](https://apify.com/confidential_gnat/dice-jobs-scraper) | Scrapes tech job listings from Dice by keyword or URL. |

### 💬 Support & contact

If you encounter any issues or have questions, please [open an issue](https://apify.com/confidential_gnat/dutchie-dispensary-menu-scraper/issues/open).

You can also find more of our actors on the [Actor Flow](https://apify.com/confidential_gnat) page.

# Actor input Schema

## `startUrls` (type: `array`):

Dutchie dispensary menu pages, for example https://dutchie.com/dispensary/pinnacle-cannabis-quincy. Embedded menu links work too. Leave empty if you only use the search locations below.

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

Maximum product rows saved for each dispensary. A product with three sizes makes three rows. In dispensary details mode this is not used.

## `cacheProjectName` (type: `string`):

Use the same name on each scheduled run to get only new or changed products. Products already saved under that name with the same price, special and stock are skipped, not charged and not counted towards the maximums. Every row gets changeType: new or updated. Leave empty to turn the cache off.

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

One search per line: a city and state (Boston, MA), a zip or postal code (02169), coordinates (42.36,-71.06) or a whole state or province (CO). A city searches that city only, a zip or coordinates search the radius below, and a state is covered with a grid of searches.

## `radiusMiles` (type: `integer`):

Distance around a zip code or coordinates, up to 150 miles.

## `maxDispensaries` (type: `integer`):

Maximum stores kept for each location search, nearest first. Closed and test stores are not counted.

## `outputMode` (type: `string`):

Menu products (one row per product size) or only the dispensary details, without opening any menu.

## `maxTotalItems` (type: `integer`):

Optional cap for the whole run, across all dispensaries. Leave empty for no total cap.

## `menuType` (type: `string`):

Which menu's price is the shelf price (price, specialPrice). Recreational and medical prices are saved on every row either way.

## `categories` (type: `array`):

Keep only these menu categories. Leave empty for the whole menu.

## `offersOnly` (type: `boolean`):

Keep only products with a live sale or mix-and-match special.

## `includeDescriptions` (type: `boolean`):

Adds the full product description to every row. It makes each menu page larger and the run a little slower.

## `includeClosedStores` (type: `boolean`):

Location searches skip stores that are not open and test or demo stores. Turn this on to keep them.

## `storeNames` (type: `array`):

Keep only stores whose name contains one of these words, for example the name of a chain. Applies to location searches. Leave empty to keep every store.

## `brands` (type: `array`):

Keep only products of these brands (name match, case does not matter). Leave empty for every brand.

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

Adds customer reviews (first name and last initial, rating, text, effects) to products that have reviews. Makes the run slower.

## `maxReviewsPerProduct` (type: `integer`):

Newest reviews kept for each product when reviews are included.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://dutchie.com/dispensary/pinnacle-cannabis-quincy"
    }
  ],
  "maxItems": 5,
  "radiusMiles": 25,
  "maxDispensaries": 5,
  "outputMode": "products",
  "menuType": "rec",
  "offersOnly": false,
  "includeDescriptions": false,
  "includeClosedStores": false,
  "includeReviews": false,
  "maxReviewsPerProduct": 5
}
```

# Actor output Schema

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

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://dutchie.com/dispensary/pinnacle-cannabis-quincy"
        }
    ],
    "maxItems": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("confidential_gnat/dutchie-dispensary-menu-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 = {
    "startUrls": [{ "url": "https://dutchie.com/dispensary/pinnacle-cannabis-quincy" }],
    "maxItems": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("confidential_gnat/dutchie-dispensary-menu-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 '{
  "startUrls": [
    {
      "url": "https://dutchie.com/dispensary/pinnacle-cannabis-quincy"
    }
  ],
  "maxItems": 5
}' |
apify call confidential_gnat/dutchie-dispensary-menu-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,confidential_gnat/dutchie-dispensary-menu-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/R7H14ZxhkAufyGEUY/builds/J0C6ztE7Vamhu5kZj/openapi.json
