# B2B Pricing Extractor — SaaS Plans & Tiers (AI) (`fuze/b2b-pricing-extractor`) Actor

Turn any SaaS pricing page into structured plans, prices, features, trials and add-ons — plus AI-detected pricing tactics. Competitive pricing intelligence for product, sales and strategy teams.

- **URL**: https://apify.com/fuze/b2b-pricing-extractor.md
- **Developed by:** [Fredrik Hansson](https://apify.com/fuze) (community)
- **Categories:** AI, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $44.00 / 1,000 pricing extracteds

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

## B2B Pricing Extractor — SaaS Plans & Tiers (AI)

**Every competitor's pricing page, turned into a spreadsheet.** A pricing page is marketing: toggles, decoy tiers, "contact us" buttons and fine print designed to be read by humans, not parsed. This Actor visits any SaaS pricing page, reads it with OpenAI, and hands back **structured plans** — names, monthly and annual prices, features, usage limits, free tiers, trials, paid add-ons — plus the **pricing tactics** it detects (per-seat, usage-based, annual discount, decoy/anchor tier, enterprise custom).

You bring a list of competitors. It hands back competitive pricing intelligence.

![B2B Pricing Extractor — SaaS Plans & Tiers (AI) — input and sample output](https://datatools-hub.vercel.app/actor-shots/b2b-pricing-extractor.png)

### 🔗 Chain it after your scraper

Already building competitor or company lists with **[Google Maps Scraper (`compass/crawler-google-places`)](https://apify.com/compass/crawler-google-places)**, **[LinkedIn Company Details Scraper (`harvestapi/linkedin-company`)](https://apify.com/harvestapi/linkedin-company)** or **[Shopify Store Leads Scraper (`clearpath/shopify-store-leads`)](https://apify.com/clearpath/shopify-store-leads)**? Pipe the dataset straight in — paste its dataset ID (via the Integrations tab); it finds each company's pricing page automatically and returns structured plans, prices and tactics. Works with any Maps, LinkedIn or company scraper's output.

### Quick start

1. **Fill in the input** — set the fields in the input tab (prefilled with a working example).
2. **Click Start** — the Actor runs and writes one record per item to the dataset.
3. **Get your data** — export to **JSON, CSV or Excel**, or pull it via the API.

***

### The flow

```
1. Give a pricing URL or a domain      2. Fetch + read the page          3. Get structured pricing
   https://linear.app/pricing      →      (locate /pricing for a    →     plans · prices · features ·
   notion.so                              bare domain, then AI)            trials · add-ons · tactics
```

1. **Give full pricing URLs** (for example `https://linear.app/pricing`) **or bare domains** (`notion.so`). For a bare domain the Actor fetches the homepage and finds the pricing link itself (`/pricing`, `/plans`, `priser`, `preise`), falling back to `https://<domain>/pricing`.
2. **It fetches each page** with a resilient HTTP client ([got-scraping](https://github.com/apify/got-scraping)) that follows redirects and tolerates error statuses, then cleans the HTML down to text with [cheerio](https://cheerio.js.org/).
3. **The AI layer reads that text** (OpenAI `gpt-4o-mini`, a fast and low-cost model) and returns one structured pricing record per page — grounded strictly in the page, `null` where the page is silent, every field in English.

***

### What you get per page

For every pricing page, the Actor returns:

1. **`currency`** — the currency / symbol shown on the page (`USD`, `$`, `EUR`, …).
2. **`billingPeriods`** — which billing cycles are offered (e.g. `["monthly","annual"]`).
3. **`hasFreeTier`**, **`hasFreeTrial`**, **`trialDays`** — whether there is a permanently free plan, a free trial, and how long the trial runs.
4. **`plans`** — an array of every tier on the page, each with:
   - `name` ("Free", "Pro", "Business", "Enterprise", …)
   - `priceMonthly` / `priceAnnual` — parsed into plain numbers
   - `priceText` — the raw price wording exactly as shown
   - `isFree` / `isCustom` — `isCustom` flags "Contact us" / quote-only / Enterprise tiers
   - `features` — the headline features listed under the plan
   - `limits` — usage limits / quotas (seats, projects, API calls, storage …)
   - `ctaText` — the call-to-action button text
5. **`addOns`** — paid extras sold on top of the plans.
6. **`positioningSummary`** — one sentence on how the product is priced and positioned.
7. **`notableTactics`** — the pricing strategies the AI can actually see on the page: `"per-seat"`, `"usage-based"`, `"annual discount ~20%"`, `"decoy/anchor tier"`, `"freemium"`, `"enterprise custom"`, `"metered overage"`, `"feature gating"`.

***

### Three ways people use it

- **Competitive pricing intelligence** — point it at a whole list of competitor pricing pages and get a single, comparable table of plans and prices. **Monitor competitor pricing** by re-running on a schedule and diffing the dataset — catch a price hike or a new Enterprise tier the week it ships.
- **Pricing benchmarking for product & strategy teams** — before a repricing, pull the real tiers, free-trial lengths and packaging of every player in your category and benchmark your own ladder against them: are you under-charging per seat, missing a usage-based lever, or lacking an anchor tier?
- **Sales battlecards** — feed the structured plans and detected tactics straight into battlecards so reps know exactly where a competitor's "Business" plan caps out, what it costs annually, and which add-ons quietly inflate the bill.

***

### Input

| Field | Type | Notes |
|---|---|---|
| `urls` | array | Full pricing-page URLs **or** bare domains. For a bare domain the pricing page is located automatically. One per line. |
| `maxResults` | integer | Cap how many pages to process. Default `100`. |
| `maxConcurrency` | integer | Pages processed in parallel. Default `5`. |
| `model` | string | Override the OpenAI model. Default `gpt-4o-mini`. |

#### Minimal input example

```json
{
  "urls": [
    "https://linear.app/pricing",
    "notion.so"
  ]
}
```

***

### Output example

```json
{
  "url": "https://linear.app/pricing",
  "domain": "linear.app",
  "success": true,
  "currency": "USD",
  "billingPeriods": ["monthly", "annual"],
  "hasFreeTier": true,
  "hasFreeTrial": true,
  "trialDays": 14,
  "plans": [
    {
      "name": "Free",
      "priceMonthly": 0,
      "priceAnnual": 0,
      "priceText": "$0",
      "isFree": true,
      "isCustom": false,
      "features": ["Unlimited members", "Linear Insights (basic)", "GitHub & GitLab integrations"],
      "limits": ["250 issues", "10MB file uploads"],
      "ctaText": "Get started"
    },
    {
      "name": "Business",
      "priceMonthly": 14,
      "priceAnnual": 12,
      "priceText": "$14 per user / month",
      "isFree": false,
      "isCustom": false,
      "features": ["Private teams & guests", "Linear Asks", "SAML & SCIM"],
      "limits": ["Unlimited issues"],
      "ctaText": "Start free trial"
    },
    {
      "name": "Enterprise",
      "priceMonthly": null,
      "priceAnnual": null,
      "priceText": "Contact us",
      "isFree": false,
      "isCustom": true,
      "features": ["Advanced security", "Dedicated support", "Custom contracts"],
      "limits": [],
      "ctaText": "Request a demo"
    }
  ],
  "addOns": [],
  "positioningSummary": "A per-seat, freemium issue tracker that pushes teams up a three-tier ladder toward a custom Enterprise plan.",
  "notableTactics": ["freemium", "per-seat", "annual discount ~14%", "enterprise custom"]
}
```

A page that is blocked, empty, or has no parseable plans comes back with `success: false` and an `error` string (and is not charged).

***

### Pay-per-event pricing

This Actor uses **pay-per-event** billing with a single event:

| Event | Charged when | Price |
|---|---|---|
| `pricing-extracted` | Once per pricing page turned into structured plans, prices, features and AI-detected pricing tactics. | $0.10 |

The Actor logs its OpenAI token usage and the estimated AI cost per page at the end of every run, so the event price always stays safely above the model cost.

***

### Setup

The AI layer calls the OpenAI API. Set the environment variable / secret **`OPENAI_API_KEY`** on the Actor. Without it the run stops immediately — the extraction is the whole product.

***

### Use it from an AI agent (Apify MCP server)

This Actor is available through the [Apify MCP server](https://mcp.apify.com), so AI agents (Claude, ChatGPT, or anything that speaks MCP) can call it as a tool — hand it a list of pricing URLs or domains and read back the structured plans and tactics — with no custom integration code.

***

### Run it locally

```bash
npm install
## put your input in storage/key_value_stores/default/INPUT.json
export OPENAI_API_KEY=sk-...   # required — the AI layer is the product
apify run -p
```

***

### Chain it

**This Actor is a building block in the fuze B2B suite.** Wire it to the next step with no code in the **Integrations** tab (trigger: *Run succeeded* → start the next Actor), or run them in sequence.

- ⬇️ Next: [B2B Competitor Teardown](https://apify.com/fuze/b2b-competitor-teardown) and [DTC Brand Teardown](https://apify.com/fuze/dtc-brand-teardown) — fold pricing into a full battlecard.
- 🔁 Pair with: [B2B Competitor Monitor](https://apify.com/fuze/b2b-competitor-monitor) — watch the pricing page for changes on a schedule.

***

### Related actors

- [B2B Competitor Teardown](https://apify.com/fuze/b2b-competitor-teardown) — One domain in, a full competitor teardown out: positioning, messaging, pricing and gaps.
- [B2B Tech Stack Detector](https://apify.com/fuze/b2b-tech-stack-detector) — Detect the tools, frameworks and SaaS a company runs on, straight from its site.
- [B2B Competitor Monitor](https://apify.com/fuze/b2b-competitor-monitor) — Watch competitors over time and get notified when their site, pricing or messaging changes.
- [AI Company Enrichment](https://apify.com/fuze/ai-company-enrichment) — Turn a list of domains into structured company profiles — firmographics, contacts, socials and ICP fit.

# Actor input Schema

## `urls` (type: `array`):

Full pricing-page URLs (e.g. https://linear.app/pricing) OR bare domains (e.g. notion.so). For a bare domain the pricing page is located automatically. One per line. Optional if you supply a datasetId for chaining.

## `maxResults` (type: `integer`):

Max pricing pages to extract. One pay-per-event charge per page extracted.

## `maxConcurrency` (type: `integer`):

How many pages to process in parallel.

## `model` (type: `string`):

Override the model (default gpt-4o-mini).

## `datasetId` (type: `string`):

Optional. Read the URLs/domains from a previous Actor run's dataset — for no-code chaining via the Integrations tab.

## `datasetField` (type: `string`):

Which dataset field holds the URL/domain. Leave blank to auto-detect (url, website, domain, pageUrl, companyUrl, link).

## Actor input object example

```json
{
  "urls": [
    "https://linear.app/pricing",
    "https://www.notion.so/pricing"
  ],
  "maxResults": 100,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `pricing` (type: `string`):

All extracted pricing records in the default dataset.

# 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 = {
    "urls": [
        "https://linear.app/pricing",
        "https://www.notion.so/pricing"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fuze/b2b-pricing-extractor").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 = { "urls": [
        "https://linear.app/pricing",
        "https://www.notion.so/pricing",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fuze/b2b-pricing-extractor").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 '{
  "urls": [
    "https://linear.app/pricing",
    "https://www.notion.so/pricing"
  ]
}' |
apify call fuze/b2b-pricing-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fuze/b2b-pricing-extractor"
        }
    }
}
```

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/o5JgiUM9GP0qNN6Mc/builds/6JzhZPq3fPBUQ9HW9/openapi.json
