E-Commerce Price Monitor
Track product prices across Shopify stores and any e-commerce website with structured data. This actor automatically detects Shopify stores and uses their product API for bulk extraction, while falling back to JSON-LD, Open Graph, and meta tag parsing for all other e-commerce sites. Price history is stored between runs so you can detect price drops, sales, and competitor pricing shifts over time.
Maintenance Pulse
90/100Cost Estimate
How many results do you need?
Pricing
Pay Per Event model. You only pay for what you use.
| Event | Description | Price |
|---|---|---|
| product-monitored | Charged per product price monitored. Uses multi-strategy extraction, maintains price history, detects price changes with direction and magnitude. | $0.05 |
Example: 100 events = $5.00 · 1,000 events = $50.00
Documentation
Track product prices across Shopify stores and any e-commerce website with structured data. This actor automatically detects Shopify stores and uses their product API for bulk extraction, while falling back to JSON-LD, Open Graph, and meta tag parsing for all other e-commerce sites. Price history is stored between runs so you can detect price drops, sales, and competitor pricing shifts over time.
Why Use This Actor?
Manually checking competitor prices is tedious and error-prone. This actor automates price monitoring across two distinct modes:
- Shopify stores — Fetches up to 10,000 products in bulk via the
/products.jsonAPI endpoint, including all variants, SKUs, compare-at prices, and availability status. No HTML parsing needed. - Any other e-commerce site — Uses a four-layer extraction strategy (JSON-LD → Open Graph → product meta tags → regex) to find prices on any product page that embeds structured data.
- Price history across runs — Stores the last 30 price points per product in Apify's Key-Value Store, automatically computing direction (up/down/unchanged/new), dollar change, and percentage change.
Whether you're a dropshipper tracking supplier margins, a brand owner enforcing MAP pricing, or a market researcher building pricing benchmarks, this actor handles the data collection so you can focus on decisions.
Features
- Shopify bulk extraction — Automatically detects Shopify stores and paginates through the
/products.jsonAPI endpoint (250 products per page), including all variants, SKUs, compare-at prices, and inventory availability - Universal e-commerce support — Extracts prices from any product page using a four-layer strategy: JSON-LD structured data, Open Graph meta tags, product meta tags, and regex pattern matching
- Price change tracking — Stores price history in the Key-Value Store across multiple runs, reporting direction (up/down/unchanged/new), absolute change, and percentage change for every product
- Variant-level detail — Captures individual product variants with separate prices, SKUs, and stock status for stores that sell products in multiple sizes, colors, or configurations
- Sale detection — Reports both the current selling price and the original compare-at price on Shopify stores, making it easy to identify active discounts and promotional pricing
- Flexible output — Download results as JSON, CSV, Excel, or HTML table with product names, prices, availability, brands, categories, and images
How to Use
- Click Try for free on this page
- Enter one or more product URLs or Shopify store URLs in the Product URLs field
- Optionally toggle Track Price History to track changes between runs
- Click Start and wait for the run to finish
- Download your results from the Dataset tab in JSON, CSV, or Excel format
For Shopify stores, provide the store root URL (e.g., https://store.myshopify.com). The actor will automatically fetch all products. For other e-commerce sites, provide the direct URL of each product page you want to monitor.
To track price changes over time, schedule the actor to run daily or weekly. The actor stores price history in the Key-Value Store and reports changes automatically on each subsequent run.
Input Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
productUrls | string[] | Yes | Product page URLs or Shopify store root URLs to monitor (e.g., https://store.myshopify.com or https://example.com/products/widget) |
checkShopifyApi | boolean | No | Try the Shopify /products.json API endpoint first. Disable to force generic HTML scraping only. Default: true |
trackPriceHistory | boolean | No | Store price history in the Key-Value Store so price changes are detected between runs. Default: true |
notifyOnChange | boolean | No | Log price changes prominently in the actor run log when detected. Default: false |
currency | string | No | Expected currency code for display when the site does not specify one (e.g., USD, EUR, GBP). Default: USD |
maxProducts | integer | No | Maximum number of products to extract per store URL. Useful for large Shopify stores. Range: 1–10,000. Default: 100 |
Input Examples
Monitor a Shopify store (all products):
{
"productUrls": ["https://store.myshopify.com"],
"checkShopifyApi": true,
"trackPriceHistory": true,
"maxProducts": 500
}
Track specific product pages with change alerts:
{
"productUrls": [
"https://example.com/products/wireless-earbuds",
"https://another-store.com/products/laptop-stand"
],
"trackPriceHistory": true,
"notifyOnChange": true,
"currency": "USD"
}
One-time price snapshot (no history tracking):
{
"productUrls": ["https://store.myshopify.com"],
"checkShopifyApi": true,
"trackPriceHistory": false,
"maxProducts": 50
}
Tips for Input
- Shopify stores: Provide the store root URL (e.g.,
https://store.myshopify.com). The actor auto-detects Shopify via the URL and fetches all products via API. - Other e-commerce sites: Provide the direct product page URL where the price is displayed. Category or search result pages will not produce useful data.
- Mixed inputs: You can mix Shopify store URLs and individual product page URLs from different sites in a single run. The actor processes each URL independently.
- Large stores: Set
maxProductsto limit extraction from stores with thousands of products. Start with 10–50 when testing.
Output Example
Each product in the dataset includes the following fields:
{
"url": "https://allbirds.com/products/mens-tree-runners",
"source": "shopify",
"storeDomain": "allbirds.com",
"productName": "Men's Tree Runners",
"description": "Our lightweight, breezy sneaker made with responsibly sourced eucalyptus tree fiber for everyday wear.",
"currentPrice": 98,
"compareAtPrice": 110,
"currency": "USD",
"available": true,
"sku": "TR-M-NBLK-8",
"brand": "Allbirds",
"category": "Shoes",
"imageUrl": "https://cdn.shopify.com/s/files/1/0076/1045/products/tree-runners-black.jpg",
"variants": [
{
"title": "8 / Natural Black",
"price": 98,
"sku": "TR-M-NBLK-8",
"available": true
},
{
"title": "9 / Natural Black",
"price": 98,
"sku": "TR-M-NBLK-9",
"available": true
},
{
"title": "10 / Natural Black",
"price": 98,
"sku": "TR-M-NBLK-10",
"available": false
}
],
"priceChange": {
"previousPrice": 110,
"changeAmount": -12,
"changePercent": -10.91,
"direction": "down",
"lastChecked": "2025-12-01T08:30:00.000Z"
},
"scrapedAt": "2025-12-08T14:22:33.000Z",
"tags": ["mens", "tree-runners", "shoes", "best-sellers"]
}
Output Fields
| Field | Type | Description |
|---|---|---|
url | string | Product page URL (constructed from handle for Shopify products) |
source | string | Extraction method used: shopify, json-ld, opengraph, meta, or regex |
storeDomain | string | Hostname of the store (e.g., allbirds.com) |
productName | string | Product title extracted from the store |
description | string|null | Product description (HTML stripped, max 1,000 chars) |
currentPrice | number|null | Current selling price as a number |
compareAtPrice | number|null | Original/compare-at price (Shopify only — indicates a sale) |
currency | string | Currency code (from site data or input fallback) |
available | boolean | Whether the product is currently in stock |
sku | string|null | Product SKU (from first variant on Shopify, from JSON-LD on other sites) |
brand | string|null | Brand or vendor name |
category | string|null | Product type or category |
imageUrl | string|null | Primary product image URL |
variants | array|null | Product variants (included when >1 variant exists) — each has title, price, sku, available |
priceChange | object|null | Price change data (populated when history tracking is enabled) |
priceChange.previousPrice | number|null | Price from the last run (null for new products) |
priceChange.changeAmount | number|null | Absolute price change in currency units |
priceChange.changePercent | number|null | Percentage change (positive = increase, negative = decrease) |
priceChange.direction | string | "up", "down", "unchanged", or "new" |
priceChange.lastChecked | string|null | ISO timestamp of the previous run |
scrapedAt | string | ISO timestamp of when this data was collected |
tags | string[] | Product tags (Shopify stores only, empty array for other sites) |
Use Cases
- E-commerce managers: Monitor competitor product pages daily to detect price changes and adjust your own pricing strategy in response
- Dropshippers: Track wholesale supplier prices on Shopify stores to calculate real-time margins and spot new deals as they appear
- Market researchers: Collect pricing data across an entire product category to build competitive landscape reports and pricing benchmarks
- Deal hunters and affiliates: Watch product pages for price drops and trigger notifications when items go on sale
- Brand owners: Verify that authorized retailers are listing your products at the correct MAP (Minimum Advertised Price)
- Data analysts: Build historical pricing datasets for trend analysis, seasonal pattern detection, and demand forecasting models
API & Programmatic Access
Python
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("ryanclinton/ecommerce-price-monitor").call(run_input={
"productUrls": ["https://store.myshopify.com"],
"checkShopifyApi": True,
"trackPriceHistory": True,
"notifyOnChange": True,
"maxProducts": 200,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
name = item.get("productName", "Unknown")
price = item.get("currentPrice")
change = item.get("priceChange", {})
direction = change.get("direction", "new") if change else "new"
pct = change.get("changePercent", 0) if change else 0
print(f"{name}: ${price} ({direction} {pct:+.1f}%)")
JavaScript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('ryanclinton/ecommerce-price-monitor').call({
productUrls: ['https://store.myshopify.com'],
checkShopifyApi: true,
trackPriceHistory: true,
notifyOnChange: true,
maxProducts: 200,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
const dir = item.priceChange?.direction ?? 'new';
const pct = item.priceChange?.changePercent ?? 0;
console.log(`${item.productName}: $${item.currentPrice} (${dir} ${pct > 0 ? '+' : ''}${pct}%)`);
}
cURL
# Start the actor
curl -X POST "https://api.apify.com/v2/acts/ryanclinton~ecommerce-price-monitor/runs?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"productUrls": ["https://store.myshopify.com"],
"checkShopifyApi": true,
"trackPriceHistory": true,
"maxProducts": 200
}'
# Fetch results (use defaultDatasetId from the response above)
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_API_TOKEN&format=json"
How It Works — Technical Details
Input: productUrls[]
│
▼
For each URL ─────────────────────────────────────────────────
│ │
├─ checkShopifyApi = true? │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ SHOPIFY MODE │ │
│ │ │ │
│ │ 1. Try /products.json?limit=250 │ │
│ │ 2. Paginate (?page=1,2,3...) │ │
│ │ 3. Stop when: │ │
│ │ - products >= maxProducts │ │
│ │ - empty page returned │ │
│ │ - page < 250 items (last page) │ │
│ │ 4. Map each ShopifyProduct: │ │
│ │ - First variant → main price │ │
│ │ - compare_at_price → sale price │ │
│ │ - Any variant available? → stock │ │
│ │ - Build URL from handle │ │
│ │ - Strip HTML from body_html │ │
│ └────────────┬────────────────────────┘ │
│ │ Products found? │
│ │ │
│ Yes │ No │
│ │ │ ──── Fallback ────┐ │
│ │ ▼ │
│ │ ┌──────────────────────────────────┐ │
│ │ │ GENERIC MODE │ │
│ │ │ │ │
│ │ │ fetch HTML (30s timeout, 2 │ │
│ │ │ retries, exponential backoff) │ │
│ │ │ │ │
│ │ │ Strategy 1: JSON-LD │ │
│ │ │ <script type="ld+json"> │ │
│ │ │ → @type: "Product" │ │
│ │ │ → offers.price / lowPrice │ │
│ │ │ → priceCurrency, availability │ │
│ │ │ → sku, brand, image │ │
│ │ │ │ │
│ │ │ Strategy 2: Open Graph │ │
│ │ │ og:price:amount │ │
│ │ │ product:price:amount │ │
│ │ │ og:price:currency │ │
│ │ │ │ │
│ │ │ Strategy 3: Product Meta Tags │ │
│ │ │ product:price:amount │ │
│ │ │ product:price:currency │ │
│ │ │ │ │
│ │ │ Strategy 4: Regex Fallback │ │
│ │ │ $X.XX / USD X.XX / price: $X.XX │ │
│ │ │ │ │
│ │ │ (first strategy that finds a │ │
│ │ │ price wins — cascading order) │ │
│ │ └──────────┬───────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ PRICE HISTORY (per product) │ │
│ │ │ │
│ │ Key = sanitized URL (max 200 chars) │ │
│ │ │ │
│ │ New product: │ │
│ │ direction = "new" │ │
│ │ Save initial record to KV store │ │
│ │ │ │
│ │ Existing product: │ │
│ │ diff = current - previous │ │
│ │ |diff| > 0.001 → "up" or "down" │ │
│ │ else → "unchanged" │ │
│ │ changePercent = (diff/prev) × 100 │ │
│ │ Append to history (max 30 entries) │ │
│ │ │ │
│ │ If notifyOnChange + changed: │ │
│ │ >>> PRICE UP: ... or │ │
│ │ <<< PRICE DOWN: ... │ │
│ └────────────┬────────────────────────┘ │
│ │ │
│ ▼ │
│ Push to Dataset │
│ │
└───────────────────────────────────────────────────────────┘
Four-Layer Extraction Strategy (Non-Shopify Sites)
The actor cascades through four extraction methods in order, stopping at the first one that finds a valid price:
| Strategy | Source | Fields Extracted | Best For |
|---|---|---|---|
| JSON-LD | <script type="application/ld+json"> with @type: "Product" | name, price, currency, availability, sku, brand, category, image, description | Modern e-commerce sites (WooCommerce, BigCommerce, Magento) |
| Open Graph | og:price:amount / product:price:amount meta tags | title, price, currency, description, image | Sites with social sharing metadata |
| Product Meta | product:price:amount / product:price:currency meta tags | title, price, currency, description, image | Sites using product-specific meta tags |
| Regex | Pattern matching: $X.XX, USD X.XX, price: $X.XX | price only (title from <title> tag) | Last resort for pages without structured data |
Shopify API Pagination
The Shopify /products.json endpoint returns up to 250 products per page. The actor paginates automatically:
Page 1: /products.json?limit=250&page=1 → 250 products
Page 2: /products.json?limit=250&page=2 → 250 products
Page 3: /products.json?limit=250&page=3 → 137 products (< 250 = last page)
Total: 637 products (capped by maxProducts setting)
Price History Storage
Price history is stored in Apify's Key-Value Store using sanitized URL keys:
- Key format: URL with protocol stripped, non-alphanumeric chars replaced with
_, max 200 chars - Example:
https://store.com/products/shoes→store.com_products_shoes - History limit: 30 entries per product (rolling window)
- Change threshold: Price differences smaller than $0.001 are treated as "unchanged"
- Persistence: Data persists between actor runs on the same Apify account
HTTP Fetch Details
- User-Agent:
Mozilla/5.0 (compatible; ApifyBot/1.0) - Timeout: 30 seconds per request
- Retries: Up to 2 retries with exponential backoff (1s, 2s delays)
- Shopify detection: URL contains
myshopify.comorshopify
How Much Does It Cost?
This actor runs on the Apify platform with very low resource requirements. It uses minimal memory (256 MB) and completes quickly because it relies on API calls and lightweight HTML parsing rather than browser rendering.
| Scenario | Products | Estimated Time | Estimated Cost |
|---|---|---|---|
| Single product page | 1 | ~5 seconds | < $0.001 |
| Small Shopify store | 50 products | ~15 seconds | ~$0.005 |
| Medium Shopify store | 250 products | ~30 seconds | ~$0.01 |
| Large Shopify store | 1,000 products | ~2 minutes | ~$0.03 |
| 10 product pages | 10 | ~30 seconds | ~$0.01 |
The Apify Free plan includes $5 of monthly credits, which is enough to monitor hundreds of products daily.
| Plan | Monthly Credits | Approximate Runs (100 products each) |
|---|---|---|
| Free | $5 | ~500 runs |
| Starter ($49/mo) | $49 | ~5,000 runs |
| Scale ($499/mo) | $499 | ~50,000 runs |
Tips
- Schedule daily runs to build price history. The actor tracks up to 30 historical price points per product, giving you a full month of daily snapshots.
- Use Shopify store root URLs (e.g.,
https://store.myshopify.com) rather than individual product URLs to extract the entire catalog in a single run. - Enable "Notify on Price Change" when running via the Apify scheduler so price movements appear prominently in the run log and email notifications.
- Start with a small
maxProductsvalue (e.g., 10) when testing a new store to verify the data looks correct before scaling up. - For non-Shopify sites, ensure you provide the actual product page URL where the price is displayed. Category or search result pages will not produce useful data.
- Combine with webhooks — Set up an Apify webhook to trigger a Slack or email notification whenever the actor finishes, so you can review price changes immediately.
- Check the
sourcefield to understand how the price was extracted.json-ldandshopifysources are the most reliable;regexis a last resort.
Limitations
- Shopify-specific features only via API — Compare-at prices, variants, SKUs, tags, and vendor names are only available when the Shopify
/products.jsonendpoint is accessible. Stores that disable this endpoint fall back to generic scraping. - No JavaScript rendering — The generic scraper fetches raw HTML only. Sites that load prices dynamically via JavaScript (e.g., single-page apps, React-based stores) may not return price data.
- Large marketplace sites — Amazon, eBay, Walmart, and similar marketplaces use aggressive anti-bot measures and dynamically loaded content. This actor is not designed for these sites.
- Currency detection — If a site does not include currency in its structured data, the actor uses the
currencyinput parameter as a fallback. It does not perform currency conversion. - Regex extraction accuracy — The regex fallback may match non-product prices (e.g., shipping costs, page element prices) on pages without structured data. Check results from
source: "regex"carefully. - Sequential processing — URLs are processed one at a time. Large batches of individual product pages may take longer than expected.
- No authentication — The actor cannot access products behind login walls, password-protected stores, or private Shopify storefronts.
- Rate limits — Shopify stores may rate-limit the
/products.jsonendpoint. The actor uses fetch retries with backoff but cannot bypass persistent rate limiting.
Responsible Use
This actor accesses only publicly visible product data that any website visitor can see. It does not bypass authentication, CAPTCHA, or access controls. When monitoring competitor prices:
- Respect each site's
robots.txtdirectives - Use reasonable scheduling intervals (daily is sufficient for most use cases)
- Do not use collected pricing data to engage in predatory pricing or price-fixing
- Comply with all applicable laws regarding competitive intelligence in your jurisdiction
- See Apify's guide on web scraping legality for general guidance
FAQ
Q: What e-commerce platforms does this actor support?
A: The actor has native Shopify support via the /products.json API. For all other platforms (WooCommerce, Magento, BigCommerce, custom stores), it extracts data from JSON-LD structured data, Open Graph tags, product meta tags, and price regex patterns. Any site that includes structured product data in its HTML will work.
Q: How does price history tracking work? A: When "Track Price History" is enabled, the actor stores the last known price for each product in the Apify Key-Value Store (keyed by sanitized URL). On subsequent runs, it compares the current price against the stored value and reports the direction, amount, and percentage of any change. Up to 30 historical price points are kept per product.
Q: Can I monitor products from multiple stores in a single run? A: Yes. Simply add multiple URLs to the "Product URLs" input field. You can mix Shopify store URLs and individual product page URLs from different sites. The actor processes each URL independently.
Q: Does this actor work with Amazon, eBay, or Walmart? A: These large marketplaces use aggressive anti-bot measures and dynamically loaded content. This actor is optimized for Shopify stores and standard e-commerce sites that include product data in their HTML or via JSON-LD. For Amazon scraping, consider dedicated Amazon scraper actors on the Apify Store.
Q: How often should I schedule runs to track prices? A: Daily runs work well for most use cases. For fast-moving markets or flash sales, you can schedule runs every few hours. The actor keeps up to 30 historical entries per product, so daily runs give you a full month of price history.
Q: What does the source field tell me?
A: It indicates which extraction method was used: shopify (API endpoint), json-ld (structured data in HTML), opengraph (OG meta tags), meta (product meta tags), or regex (pattern matching). Shopify and JSON-LD are the most reliable and complete. Regex is the least reliable fallback.
Q: Why is compareAtPrice null for non-Shopify products?
A: The compare-at price (original price before sale) is a Shopify-specific concept available via their product API. Most other e-commerce platforms do not expose this in their structured data. You can still detect sales by tracking currentPrice changes over time.
Q: Is it legal to scrape product prices from e-commerce websites? A: Product prices are publicly available information displayed to all website visitors. This actor accesses only publicly visible data and does not bypass any authentication or access controls. For guidance on your specific situation, consult legal counsel regarding local regulations. See Apify's guide on web scraping legality.
Q: What happens if a product page does not contain structured price data?
A: The actor uses a four-layer extraction strategy. If JSON-LD is not found, it tries Open Graph tags, then product meta tags, and finally regex pattern matching for common price formats (e.g., $29.99). If none of these methods find a price, the product is skipped and a warning is logged.
Integrations
Connect this actor to your existing tools and workflows:
- Zapier — Trigger actions in 5,000+ apps when prices change
- Make — Build complex pricing automation workflows
- Google Sheets — Export price data directly to spreadsheets for analysis
- Slack — Get instant notifications when products drop in price
- The Apify API — Programmatic access to results via REST API
- Apify Webhooks — Trigger custom actions when a run finishes
Related Actors
| Actor | Use Case |
|---|---|
| ryanclinton/shopify-store-intelligence | Deep analysis of Shopify stores including technology stack, theme detection, and store metrics |
| ryanclinton/brand-protection-monitor | Monitor unauthorized use of your brand across the web, including pricing violations |
| ryanclinton/website-change-monitor | Track changes on any web page, useful for detecting product listing updates beyond just price |
| ryanclinton/serp-rank-tracker | Track search engine rankings for product keywords alongside pricing data |
| ryanclinton/website-tech-stack-detector | Identify the e-commerce platform powering any online store |
How it works
Configure
Set your parameters in the Apify Console or pass them via API.
Run
Click Start, trigger via API, webhook, or set up a schedule.
Get results
Download as JSON, CSV, or Excel. Integrate with 1,000+ apps.
Use cases
Sales Teams
Build targeted lead lists with verified contact data.
Marketing
Research competitors and identify outreach opportunities.
Data Teams
Automate data collection pipelines with scheduled runs.
Developers
Integrate via REST API or use as an MCP tool in AI workflows.
Related actors
Website Content to Markdown
Convert any website to clean Markdown for RAG pipelines, LLM training, and AI apps. Crawls pages, strips boilerplate, preserves headings, tables, and code blocks. GFM support.
PubMed Biomedical Literature Search
Search and extract structured metadata from PubMed, the world's largest biomedical literature database with over 37 million citations. Query by keyword, author, journal, date range, and article type using the NCBI E-utilities API. Returns clean JSON with titles, authors, DOIs, PMC IDs, journal details, and direct PubMed links -- ready for systematic reviews, bibliometric analysis, and research monitoring.
Company Deep Research - Business Intelligence Agent
Generate comprehensive company research reports from 7+ sources: SEC filings, stock data, Wikipedia, GitHub, Trustpilot reviews, DNS records, and social media verification.
CFPB Consumer Complaint Search
Search and extract consumer complaint data from the CFPB database. Essential for compliance screening, AML due diligence, KYC risk assessment, and regulatory monitoring.
Ready to try E-Commerce Price Monitor?
Start for free on Apify. No credit card required.
Open on Apify Store