SaaS Pricing Scraper
Pricing
from $0.50 / 1,000 results
SaaS Pricing Scraper
Extract structured pricing data from any SaaS company's public pricing page. The dedicated SaaS pricing intelligence tool on the Apify Store.
Pricing
from $0.50 / 1,000 results
Rating
0.0
(0)
Developer

Mick
Actor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Extract structured pricing data from any SaaS company's public pricing page. Point it at a URL or domain and get back plan names, prices, features, billing models, and more as clean JSON. No API keys required. MCP-ready for AI agent integration.
What does it do?
SaaS Pricing Scraper renders pricing pages with Playwright (headless Chromium), then extracts structured plan data using multi-strategy HTML parsing. It handles JavaScript-rendered pages, cookie banners, billing toggles, and various pricing layouts -- cards, grids, rows, comparison tables.
Smart input -- no modes to think about. Provide URLs or domains in a single list:
- Pricing page URLs (e.g.
https://linear.app/pricing) -- scraped directly with Playwright - Bare domains (e.g.
linear.app) -- the scraper auto-discovers the pricing page, then scrapes it
Mix and match in the same run. The scraper auto-detects which is which.
Use cases
- Competitive intelligence -- track competitor pricing changes over time
- Market research -- compare pricing across an entire SaaS category
- Sales enablement -- feed pricing data into CRM workflows
- Investment analysis -- evaluate SaaS business models at scale
- AI agent tooling -- pipe structured pricing data into AI agents via MCP
What data does it extract?
Each record represents one pricing plan (tier) from a SaaS product:
| Field | Description |
|---|---|
plan_name | Name of the pricing tier (e.g. "Pro", "Enterprise") |
plan_position | Position on the page (1 = leftmost/first) |
monthly_price | Monthly price in the detected currency |
annual_price | Annual price per month (if annual billing shown) |
annual_savings_pct | Percentage saved with annual billing |
currency | Detected currency (default USD) |
pricing_model | flat_rate, per_seat, usage_based, tiered, freemium, custom, hybrid |
price_unit | e.g. "per user/month", "per seat" |
has_free_tier | Whether the plan is a free tier |
has_trial | Whether a free trial is offered |
trial_days | Trial duration if detected |
is_custom_pricing | True if "Contact Sales" / custom pricing |
features | List of features included in this tier |
highlighted_feature | Badge text like "Most Popular", "Best Value" |
cta_text | Call-to-action button text |
cta_url | Call-to-action link |
extraction_confidence | high, medium, or low |
extraction_notes | Details on any extraction issues |
Input
| Field | Type | Default | Description |
|---|---|---|---|
urls | array | required | Pricing page URLs or company domains (max 100) |
maxResults | integer | 100 | Max pricing records to return (1-500) |
includeFeaturesPerPlan | boolean | true | Extract feature lists per tier |
includeRawHtml | boolean | false | Include raw pricing section HTML |
requestIntervalSecs | number | 2.0 | Min seconds between requests |
timeoutSecs | integer | 30 | Page load timeout |
maxRetries | integer | 3 | Retry attempts per request |
Example input
{"urls": ["https://linear.app/pricing","https://github.com/pricing","https://supabase.com/pricing","https://1password.com/pricing"],"maxResults": 50}
Output
Example: Linear (4 plans extracted)
[{"schema_version": "1.0","type": "pricing_plan","company_name": "Linear","company_domain": "linear.app","pricing_page_url": "https://linear.app/pricing","plan_name": "Free","plan_position": 1,"monthly_price": 0,"annual_price": 0,"currency": "USD","pricing_model": "freemium","has_free_tier": true,"is_custom_pricing": false,"features": ["Unlimited members", "2 teams", "250 issues", "Slack and GitHub", "AI agents"],"cta_text": "Get started","extraction_confidence": "high"},{"plan_name": "Basic","plan_position": 2,"monthly_price": 10,"pricing_model": "per_seat","price_unit": "per user/month","features": ["5 teams", "Unlimited issues", "Unlimited file uploads", "Admin roles"],"extraction_confidence": "high"},{"plan_name": "Business","plan_position": 3,"monthly_price": 16,"pricing_model": "per_seat","price_unit": "per user/month","features": ["Unlimited teams", "Private teams and guests", "Triage Intelligence", "Linear Insights", "Linear Asks", "Issue SLAs", "Zendesk and Intercom integrations"],"extraction_confidence": "high"},{"plan_name": "Enterprise","plan_position": 4,"is_custom_pricing": true,"pricing_model": "custom","features": ["Sub-initiatives", "Advanced Linear Asks", "Dashboards", "SAML and SCIM", "Advanced security", "Migration and onboarding support"],"cta_text": "Contact sales","extraction_confidence": "high"}]
Output is trimmed for readability. Each record includes all fields from the schema -- see the full field list above.
What works well
The scraper performs best on standard SaaS pricing pages with clearly structured plan cards or grids:
| Site | Plans | Accuracy |
|---|---|---|
| Linear | 4 (Free, Basic, Business, Enterprise) | All prices and features correct |
| GitHub | 3 (Free, Team, Enterprise) | All prices correct |
| 1Password | 3 (Individual, Families, Business) | All prices correct, monthly + annual |
| Supabase | 4 (Free, Pro, Team, Enterprise) | All prices correct |
| Dropbox | 4 (Plus, Professional, Standard, Advanced) | 3/4 prices correct |
Limitations
- Bot-protected sites may fail. Sites using aggressive bot detection (Cloudflare, Akamai, or custom anti-bot) may not render pricing content for headless browsers. This includes some major tech companies like Notion, Slack, Figma, and Vercel. The scraper returns a low-confidence empty record when this happens.
- Catalog pages are not supported. Pages that list dozens of products (like Azure's pricing overview) rather than showing plan tiers for a single product will produce poor results. Point the scraper at a specific product's pricing page instead.
- Prices in non-standard locations. Some sites put prices outside of plan cards (e.g. only in FAQ sections or comparison table footnotes). The scraper extracts prices from plan containers and nearby DOM elements but may miss prices embedded in prose.
- Heavy SPAs with long load times. Some single-page applications take over 45 seconds to render on Apify's infrastructure. These will time out.
- USD assumed by default. The scraper detects currency symbols ($, €, £, ¥, ₹) but defaults to USD when ambiguous.
Cost
This actor uses pay-per-event (PPE) pricing. You pay only for the results you get.
- $0.50 per 1,000 results ($0.0005 per result)
- No proxy costs -- Playwright runs in the actor's Docker container
- Free tier: 25 results per run (no subscription required)
Typical run: 5 URLs produces 15-20 plan records in about 30 seconds. Cost: ~$0.01.
MCP Integration
This actor works as an MCP tool through Apify's hosted MCP server. No custom server needed.
- Endpoint:
https://mcp.apify.com?tools=labrat011/saas-pricing-scraper - Auth:
Authorization: Bearer <APIFY_TOKEN> - Transport: Streamable HTTP
- Works with: Claude Desktop, Cursor, VS Code, Windsurf, Warp, Gemini CLI
Example MCP config (Claude Desktop / Cursor):
{"mcpServers": {"saas-pricing-scraper": {"url": "https://mcp.apify.com?tools=labrat011/saas-pricing-scraper","headers": {"Authorization": "Bearer <APIFY_TOKEN>"}}}}
Agent prompt example: "Compare the pricing of Linear, GitHub, and Supabase. Which offers the best value for a 10-person engineering team?"
The agent calls this tool, gets structured JSON for all tiers across all three products, and can compute total costs and compare features programmatically.
Technical details
- Python 3.12, async architecture with
asyncio.Semaphoreconcurrency control - Playwright (headless Chromium) for full JavaScript rendering
- Stealth configuration: Chrome user agent, viewport 1920x1080, webdriver flag removal
- Cookie banner auto-dismissal
- Two-phase page wait:
domcontentloaded+ smart pricing wait, with full-load fallback for heavy SPAs - Multi-strategy extraction pipeline: plan headings, CSS card detection, sibling block analysis
- Positional price correlation for row/grid layouts where prices live outside plan containers
- BeautifulSoup4 for HTML parsing
- SSRF prevention (blocks private IPs, cloud metadata endpoints)
- Batch push (25 items) for memory efficiency
- State persistence for resumable runs
FAQ
What kinds of pricing pages work best?
Pages with clearly structured plan cards or grids -- the typical SaaS pricing layout with 3-5 tiers shown side by side. The scraper handles both static HTML and JavaScript-rendered pages.
Why did a site return empty results?
Most likely the site uses aggressive bot detection that blocks headless browsers from rendering the pricing content. Check the extraction_notes field -- it will say "Playwright timeout" or "Could not extract any pricing plans" to help diagnose the issue.
Can I scrape non-English pricing pages?
The scraper detects prices by currency symbols and numeric patterns, so it can extract prices from pages in any language. Plan names and features will be in whatever language the page uses.
How do I get annual prices?
Many SaaS sites show both monthly and annual pricing via a billing toggle. The scraper detects billing toggles and extracts both prices when available. Annual prices appear in the annual_price field (normalized to per-month).
Can I use this with the Apify API?
Yes. Call the actor via the Apify API and retrieve results programmatically in JSON, CSV, or other formats. Works with the Apify Python and JavaScript clients.
Feedback
Found a bug or have a feature request? Open an issue on the actor's Issues tab in Apify Console.