# Dollar General Scraper: Store Prices, DG Coupons & Deals (`vant47/dollar-general-scraper`) Actor

Get Dollar General products with the price at your store: sale prices, DG digital coupons with dates, weekly ad deals, unit price, in-store stock, UPC and size for groceries, household and health items. Search, categories or product links by ZIP or store. About $0.0035 per product. No login.

- **URL**: https://apify.com/vant47/dollar-general-scraper.md
- **Developed by:** [fortbrand](https://apify.com/vant47) (community)
- **Categories:** E-commerce, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 1,000 products

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

## Dollar General Scraper: Store Prices, DG Coupons & Deals

For retail price analysts, brands and comparison services monitoring Dollar General shelf prices and promotions by store. Get live product prices, regular prices, linked DG digital coupons and conditions, store offers, UPCs and online stock signals. About **$0.0035 per delivered product**, so **20 products cost $0.07** and **1,000 cost $3.50**, plus the minimum $0.00005 Actor start charge. No Dollar General login or retailer API key is required.

Choose ZIP codes to find nearby stores or supply exact store numbers for a repeatable monitored basket. Each row identifies the store and product. The same family fields also fit other US grocery price datasets, so you can join retailer snapshots without renaming the core columns.

### What you get

One observation is one distinct product at one selected store. Prices are the store's advertised product prices, with digital coupons and basket conditions preserved separately. Export the dataset as JSON, CSV or Excel, and keep the structured offers when building a promotion database.

| Field | What it means |
| --- | --- |
| `verdict` | Readable product, current price and selected-store summary. |
| `retailer`, `country`, `currency` | Dollar General, US and USD. |
| `storeId`, `storeName`, `location` | Verified store number, readable store name and requested ZIP. Location is null for an exact or default store. |
| `productId`, `sku`, `gtin` | Product UPC key, retailer SKU and UPC as text with leading zeros. |
| `title`, `brand`, `size` | Supplied product title; explicit brand and size when a detail response provides them. |
| `price`, `regularPrice`, `onSale` | Advertised selected-store shelf price, original price and whether the shelf price is lower. |
| `promoText`, `promoType` | Store promotion text and the kind of promotion supplied. |
| `promoStart`, `promoEnd` | Store-offer start and expiration when supplied. |
| `memberPrice`, `memberProgram` | Reserved common fields; null when no explicit membership price is supplied. |
| `unitPrice`, `unitOfMeasure` | Published price per unit and unit label when DG marks them for display. |
| `inStock`, `stockLevel` | Store inventory signal and usable reported quantity. |
| `rating`, `reviewCount` | Supplied aggregate product rating and review count. |
| `category`, `url`, `imageUrl` | Source category labels, public product page and product image. |
| `scrapedAt` | UTC observation time. |

Dollar General fields follow the family fields:

| Field | What it adds |
| --- | --- |
| `storeNumber`, `storeAddress` | Store number and public street, city, state and ZIP. |
| `storeDistance`, `storeTimezone` | Source distance from the requested ZIP centroid and store timezone when supplied. |
| `inStoreStock`, `soldAtStore` | Stock availability kept separate from DG's sellable/catalog flag. |
| `pickupAvailable`, `deliveryAvailable` | Source fulfillment flags. |
| `couponText`, `coupons` | Linked digital-coupon text, codes, validity dates and purchase conditions. |
| `offers` | Store price offers, savings text, method values and expiration dates. |
| `digitalCouponAvailable`, `isDeal` | Linked coupon flag and combined deal flag. |
| `inventoryStatus`, `reportedStockLevel`, `stockCountCaution` | Original inventory evidence, including quantities withheld from the main numeric stock field. |
| `badges`, `categoryIds` | Source badges such as SNAP and category identifiers. |
| `details` | Optional description, highlights, images and category hierarchy. |
| `recordType`, `sourceUrl` | PRODUCT or free NOTE and the public provider endpoint used. |

The **Store prices** dataset view places title, current price, original price, promotion, membership price, unit price, stock and store together. The **Deals and coupon conditions** view emphasizes the promotion fields. The `DEALS` JSON record contains only observations with `isDeal: true`. Large deal exports provide a manifest linking to smaller JSON parts, preserving the same product rows.

Every run writes `SUMMARY`, including delivered products, resolved stores, deals, duplicate exclusions, source outcomes, free failures and whether the buyer's spending limit stopped collection. The `COUPONS` record contains the public coupon catalog when requested by a details or deals run. It includes basket offers separately from product shelf prices.

### Start in three steps

1. Enter a search term, category/product links or UPCs, then choose ZIP codes or exact store numbers.
2. Set your total product limit and optional deals or details selection.
3. Run, check the resolved stores and source outcomes in SUMMARY, then export or connect the dataset to your workflow.

The prefill searches milk near ZIP 37201 with a 20-product cap. A real cloud run on 4 November 2026 returned 20 unique products at Nashville store 21334, including 4 products with deals, in 10.353 seconds. A separate category run returned 30 products over two pages, with 30 product charges and no source failures. Two larger cloud checks each delivered 1,100 unique product/store observations across four stores, using different search terms and ZIP combinations. Both finished with no source failures and exactly one product charge per delivered observation. These are observed tests, not a runtime guarantee.

### Input reference

| Input | Behavior and example |
| --- | --- |
| `searchTerms` | Words searched independently at every selected store, such as `["milk", "Tide"]`. |
| `startUrls` | Plain Dollar General category, product, on-sale or coupon links. |
| `productIds` | UPC barcodes, such as `["070744002196"]`. These are product identifiers, not retailer SKUs. |
| `locations` | US ZIP codes; choose the nearest returned store to each ZIP centroid. ZIP+4 uses its first five digits. |
| `storeIds` | Exact numeric store numbers. These take precedence over ZIP codes. |
| `maxItemsPerSearch` | Maximum new observations per source and store; default 20, maximum 2,000. |
| `maxItems` | Total unique product/store observations; default 20, maximum 10,000. |
| `dealsOnly` | Keep products with a reduced shelf price, store offer or linked coupon. |
| `includeDetails` | Add explicit brand, package size, description, highlights and images. Also save the public coupon catalog. No extra product fee. |
| `proxyConfiguration` | Automatic default-pool datacenter first, with US residential retries. Custom proxy settings can be supplied. |

Empty locations and storeIds select the website's anonymous default store, then verify it through store metadata. For daily monitoring, exact stores are easier to compare because the same location is selected every time. ZIP coordinates come from GeoNames postal data and represent an area centroid, so the nearest store can differ from a browser using a full street address.

Two terms at two ZIP codes can deliver up to 80 observations with these limits, costing up to $0.28 at base pricing:

```json
{
  "searchTerms": ["milk", "coffee"],
  "locations": ["37201", "75203"],
  "maxItemsPerSearch": 20,
  "maxItems": 80
}
```

A repeatable UPC basket:

```json
{
  "productIds": ["070744002196", "070744002202"],
  "storeIds": ["21334", "14838"],
  "maxItems": 4
}
```

A category and promotion watch:

```json
{
  "startUrls": ["https://www.dollargeneral.com/c/grocery/dairy-refrigerated/milk"],
  "storeIds": ["21334"],
  "maxItemsPerSearch": 100,
  "maxItems": 100,
  "dealsOnly": true
}
```

To retrieve full product metadata, add `includeDetails: true`. Search and category collection use the site's normal 24-product pages. Details add one store-specific request per product. A source can run out of matches before your cap, and deals filtering can scan more pages than the number of rows returned. There is a safety limit of 100 pages per source and store.

### Real observation

Selected fields from the Nashville prefill on 4 November 2026:

```json
{
  "retailer": "Dollar General",
  "storeId": "21334",
  "storeName": "Dollar General #21334, Nashville",
  "location": "37201",
  "productId": "070744002196",
  "sku": "12487001",
  "gtin": "070744002196",
  "title": "Clover Valley Whole Milk, Gallon",
  "price": 4.2,
  "regularPrice": 4.2,
  "onSale": false,
  "inStock": true,
  "stockLevel": 12
}
```

The same UPC at verified Poolesville store 14838 returned $4.40 in a separate live product request. Store identity matters for a price comparison. The Actor never substitutes the product's ship-to-home price for the selected-store price.

### Understand coupons, promotions and inventory

A coupon is an offer with conditions, not an automatic reduction of the shelf price. `price` remains the source product price. Linked coupon records retain offer codes, summaries, descriptions, validity and redemption conditions. Some require clipping, minimum quantities, qualifying product combinations or a minimum basket. Evaluate those conditions separately before calculating a shopper basket.

A store offer such as a multi-buy can have a method value and savings text. Preserve the complete `offers` array when you need to distinguish a single-item price from a two-item qualification. Promotion timestamps without an offset retain the source local-time meaning. Do not treat them as UTC solely because `scrapedAt` is UTC.

A public $5 off $25 basket offer, when present in the catalog, belongs in `COUPONS`. It is not attached to every returned item or subtracted from every item price. Coupon catalog coverage and product-linked coupon coverage serve different purposes.

`isDeal` combines the reduced-price, linked-offer and linked-coupon signals. It does not certify checkout eligibility. `memberPrice` stays null unless a distinct membership price is explicitly provided. Public product review totals can differ between observations as the retailer updates its catalog.

Stock follows DG's quantity, sellable and stock-status signals. A product marked unsellable at the selected store is reported unavailable even when the source includes a positive placeholder quantity. A product can be sellable but have zero reported units. DG can also report 5 for products whose exact quantity is not tracked. To avoid treating that as a precise shelf count, `stockLevel` is null for a reported 5, while `reportedStockLevel` preserves the value and `stockCountCaution` explains it.

### Price and spending controls

| Products delivered | Base | Bronze | Silver | Gold |
| --- | --- | --- | --- | --- |
| 20 | $0.07 | $0.0665 | $0.063 | $0.056 |
| 100 | $0.35 | $0.3325 | $0.315 | $0.28 |
| 1,000 | $3.50 | $3.325 | $3.15 | $2.80 |

Base price is $0.0035 per product; Bronze $0.003325, Silver $0.00315 and Gold $0.0028. Add the minimum $0.00005 start charge. Higher tiers use the Gold product price. Optional metadata has no second product fee.

Overlapping sources at one store are deduplicated within the run. The same UPC at two stores is two observations because there are two distinct prices or stock signals to monitor. Free notes, summaries, duplicate rows, failed source requests and empty searches have no product charge. There is no default dataset-item charge.

Set Apify's maximum total charge to bound a job. The Actor checks affordability before saving more product rows and records a clean stop in SUMMARY. Saved rows and charge receipts are reconciled after a reboot so delivery resumes without duplicate product observations or a second product charge.

### Monitor prices every day

Save a task with exact store numbers and a fixed set of UPCs, search terms or categories. In Apify Console, create a schedule, select that task and set the frequency and timezone. Connect a completed-run webhook to your database, Sheets workflow, Make, Zapier or n8n.

Join observations using `retailer + storeId + productId`, and retain `scrapedAt` as the snapshot time. Keep UPCs as text in spreadsheets. Compare `price` and `regularPrice` separately, and preserve coupon dates and minimum quantities alongside the price. Every scheduled run fetches a fresh observation and charges for that run's delivered products.

Before accepting a snapshot, inspect SUMMARY.freeFailures and the per-source outcomes. A completed run with an unavailable source can contain useful observations but incomplete coverage. Keep that distinction in automated alerts, especially when comparing a category with its previous snapshot.

### API and automation

```bash
curl -X POST \
  'https://api.apify.com/v2/acts/vant47~dollar-general-scraper/runs' \
  -H 'Authorization: Bearer YOUR_APIFY_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"searchTerms":["milk"],"locations":["37201"],"maxItems":20}'
```

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("vant47/dollar-general-scraper").call(
    run_input={"productIds": ["070744002196"], "storeIds": ["21334", "14838"], "maxItems": 2}
)
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())
summary = client.key_value_store(run["defaultKeyValueStoreId"]).get_record("SUMMARY")
```

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('vant47/dollar-general-scraper').call({
  searchTerms: ['Tide'], locations: ['75203'], maxItems: 20, dealsOnly: true
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

### Use with AI agents (MCP)

Connect an agent to `https://mcp.apify.com`. Ask for Dollar General store prices, DG coupons, UPCs and stock at named ZIP codes or store numbers. Provide the desired product cap. Ask the agent to inspect SUMMARY, retain null values and preserve coupon conditions rather than subtracting all coupons from shelf price.

For a monitored basket, give the agent exact UPCs and stores. For discovery, give search terms or category links. Exporting the common retail fields makes it easier to combine Dollar General observations with other retailer Actors that use the same family schema.

### Limits

- Public signed-out observations only. Account offers, clipped-account state, checkout eligibility and personalized prices are outside coverage. The Actor does not sign in or solve CAPTCHAs.
- DG can change or refuse its public responses. Retries use fresh anonymous sessions. A permanently unavailable source produces a free note and appears in SUMMARY.
- ZIP selection uses a bundled GeoNames centroid dataset. A ZIP can be missing or outdated, and the nearest store to an address can differ. Use exact store numbers for stable comparisons.
- Prices exclude checkout taxes and service charges. Prices, stock and promotions can change after collection. Historical backfill is unavailable.
- Unit price, brand, size and promotion start dates are not present on every public response. Missing values remain null. Brand and size are more complete with includeDetails. Zero unit-price placeholders are withheld.
- Store quantity is not an audited shelf count. Reported counts of 5 are treated cautiously as explained above. Fulfillment flags do not guarantee a checkout slot.
- The coupon catalog is saved for details or deals runs. Product-linked coupons are included on ordinary searches. Weekly-ad images and every flyer panel are not independently parsed; published store offers are retained when linked to returned products.
- The deals view displays deal signals for inspection. Use the DEALS JSON output or dealsOnly input for a filtered export.

### FAQ

**Can I select a specific store?** Yes. Use storeIds and check its verified address in SUMMARY. Exact store IDs override locations.

**Why do two stores show different milk prices?** Prices are requested with each store number. That is the intended unit of observation.

**Does the Actor apply digital coupons?** It reports them and their conditions. It does not clip offers or calculate a personalized checkout total.

**Can I retrieve only deals?** Use dealsOnly. A product qualifies through a lower shelf price, linked store offer or linked coupon.

**Why is stockLevel null when reportedStockLevel is 5?** The site can use 5 as a placeholder. The original evidence is retained without presenting it as an exact count.

**Why is brand or size null?** Search results do not always provide those fields. Turn on includeDetails to request explicit product metadata.

**What happens with an invalid input?** Parseable invalid selections produce a free NOTE and SUMMARY. The platform can reject schema-invalid input before a run starts. Neither path creates a product charge.

**What happens after a reboot?** The Actor reads its saved dataset and billing receipts, reconciles the last saved product if necessary, then resumes cached source pages. Ambiguous billing evidence stops further charging.

**Can I combine these rows with another US grocery Actor?** Yes. The core store, product, price, promotion and availability fields follow the shared retail schema.

ZIP centroid data is adapted from [GeoNames postal codes](https://www.geonames.org/export/zip/) under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Only ZIP codes and coordinates are bundled. This Actor is independently developed and is not affiliated with or endorsed by Dollar General.

# Actor input Schema

## `searchTerms` (type: `array`):

Search words at each selected store, such as milk or Tide.

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

Dollar General category, product, on-sale or coupons URLs.

## `productIds` (type: `array`):

UPC barcodes. Leading zeros are preserved.

## `locations` (type: `array`):

Nearest store to each ZIP centroid. Use exact storeIds for a stable monitored basket.

## `storeIds` (type: `array`):

Select verified store numbers instead of ZIP codes.

## `maxItemsPerSearch` (type: `integer`):

Maximum delivered unique product/store rows.

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

Maximum delivered unique product/store rows.

## `dealsOnly` (type: `boolean`):

Only products with store offers, lower shelf prices or a linked digital coupon.

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

Add brand, size, description and images using one detail request per product, plus the public coupon catalog. No extra product fee.

## `proxyConfiguration` (type: `object`):

Automatic default-pool datacenter attempt followed by US residential sessions. Empty settings use automatic routing.

## Actor input object example

```json
{
  "searchTerms": [
    "milk"
  ],
  "locations": [
    "37201"
  ],
  "maxItemsPerSearch": 20,
  "maxItems": 20,
  "dealsOnly": false,
  "includeDetails": false,
  "proxyConfiguration": {}
}
```

# Actor output Schema

## `products` (type: `string`):

No description

## `dealsView` (type: `string`):

No description

## `dealsOnly` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `coupons` (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 = {
    "searchTerms": [
        "milk"
    ],
    "locations": [
        "37201"
    ],
    "maxItemsPerSearch": 20,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("vant47/dollar-general-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 = {
    "searchTerms": ["milk"],
    "locations": ["37201"],
    "maxItemsPerSearch": 20,
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("vant47/dollar-general-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 '{
  "searchTerms": [
    "milk"
  ],
  "locations": [
    "37201"
  ],
  "maxItemsPerSearch": 20,
  "maxItems": 20
}' |
apify call vant47/dollar-general-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vant47/dollar-general-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/eMJ42Dkal6UVu67PN/builds/QIKeP45sAflKgILhj/openapi.json
