# Electronic Components Bom Price Stock Monitor (`arezdev/electronic-components-bom-price-stock-monitor`) Actor

Check electronic component MPNs for stock, quantity pricing, lead times and datasheets. Get one selected distributor quote per part and calculate BOM costs for your target quantity. Export snapshots for procurement and scheduled monitoring.

- **URL**: https://apify.com/arezdev/electronic-components-bom-price-stock-monitor.md
- **Developed by:** [Arezdev](https://apify.com/arezdev) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 component quote extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

**Turn a list of manufacturer part numbers into current distributor stock, volume pricing, and quantity-aware BOM costs.**

Paste your MPNs, set an order quantity, and download a flat dataset ready for procurement workflows. Each unique MPN produces one selected distributor quote or an informative, uncharged error record. The Actor uses direct HTTP requests and runs with 256 MiB of memory.

Best for checking a BOM against publicly available supplier quotes. The primary LCSC lookup and Findchips fallback return one selected quote per MPN, not an exhaustive market comparison. Prices and stock are snapshots; confirm them with the distributor before ordering.

### How to use

1. Enter manufacturer part numbers in **Manufacturer part numbers**, one per line.
2. Set **Target order quantity** to the quantity you need for every component.
3. Enable **Only immediately available parts** to exclude unavailable or unconfirmed stock.
4. Run the Actor and export the dataset as JSON, CSV, Excel, or through the Apify API.

```json
{
  "partNumbers": ["STM32F103C8T6", "NE555P"],
  "onlyInStock": false,
  "targetOrderQuantity": 100,
  "maxConcurrency": 10,
  "timeoutSecs": 15
}
```

MPNs are matched exactly after trimming whitespace and ignoring case. Suffixes and punctuation remain significant: `NE555P`, `NE555PWR`, and `NE555P-HXY` are different parts. Duplicate queries are processed once.

The primary source is the current [LCSC catalog search API](https://wmsc.lcsc.com/ftps/wm/search/v3/global), with product detail enrichment when the search response lacks usable pricing. If the API fails, has no exact quote, does not satisfy the stock filter, or cannot price your quantity, the Actor reads structured distributor offers from [Findchips](https://www.findchips.com/). Those offers identify the actual distributor, such as TME or Newark. Distributor-supplied aggregator data can lag the distributor's own catalog.

One quote is saved per MPN. LCSC is preferred when it can price the requested quantity. Fallback selection prefers a price applicable to your quantity, confirmed immediate stock, and USD pricing. It does not perform a global cheapest-price comparison or currency conversion. If an exact listing has published price tiers but your quantity is not orderable, the listing can still be returned with null target cost fields.

### What data can you extract?

| Fields | Meaning |
| --- | --- |
| `mpnQuery`, `status`, `matchedMpn` | Requested MPN, result status, and exact matched manufacturer part number |
| `manufacturer`, `distributorName`, `distributorSku` | Manufacturer and selected distributor identity |
| `packageCase`, `packagingType` | Physical package and supply packaging such as tube, tray, or reel |
| `inStockQty`, `isImmediateStockAvailable` | Reported stock quantity and whether immediate stock is confirmed |
| `minOrderQty` | Published minimum order quantity |
| `unitPrice1`, `unitPrice10`, `unitPrice100`, `unitPrice1000` | Applicable per-unit prices at the four reference quantities |
| `targetOrderQuantity`, `effectiveUnitPriceAtTargetQty`, `totalExtendedCost` | Your requested quantity, applicable unit price, and extended component cost |
| `currency`, `rohsCompliant` | Source currency and explicit RoHS compliance status |
| `datasheetUrl`, `productUrl` | Public datasheet and product links when available |
| `scrapedAt`, `errorMessage` | Retrieval timestamp in UTC and a safe failure description |

Every record contains exactly these 24 scalar fields. Unknown values are `null`; zero stock and false compliance remain distinct from unknown values. The specified flat schema has no factory lead-time field, so factory lead times are not exported.

Price calculations use the published tier with the greatest minimum quantity that does not exceed your quantity. They respect published maximum quantities, MOQ, and order multiples. A price for 2,500 pieces is never used to quote 100 pieces. If the minimum order is five, `unitPrice1` is null. If the order multiple is five and you request 101, the target price and cost are null; quantities are never silently rounded up.

Extended cost is the applicable unit price multiplied by the exact target quantity, using decimal arithmetic before conversion to a JSON number. Shipping, tax, duties, handling, and currency conversion are excluded. Extremely large totals outside the safe numeric range remain null. Stock availability indicates that some immediate stock exists; it does not guarantee that the entire target quantity is available.

### Input settings

| Setting | Default | Accepted values |
| --- | --- | --- |
| `partNumbers` | Prefill: `STM32F103C8T6`, `NE555P` | Required; 1–10,000 MPNs, up to 128 characters each |
| `onlyInStock` | `false` | Boolean; only confirmed immediately available quotes pass when true |
| `targetOrderQuantity` | `100` | Integer from 1 to 1,000,000,000; applied to every MPN |
| `maxConcurrency` | `10` | Integer from 1 to 30; reduced automatically for available memory |
| `timeoutSecs` | `15` | Integer from 3 to 60; total lookup deadline per MPN |
| `proxyConfiguration` | Omitted | Optional Apify proxy editor configuration |

Direct connections are attempted first. HTTP 403, 429, and 503 can trigger a datacenter proxy retry, first using SHADER and then the account's default datacenter proxy. This requires the runtime-injected proxy credential and access to the selected proxy group. A configured final proxy tier, including residential, is used only when `useApifyProxy: true` is explicitly supplied. Set `useApifyProxy: false` to force direct requests. Custom `proxyUrls` force the supplied proxies and bypass the automatic cascade.

The first source receives at most half the lookup deadline, preserving time for a fallback. Each redirect is checked again. TLS certificate verification remains enabled during HTTP/1.1 retries and proxy requests.

### Output example

This example illustrates the schema and arithmetic. Availability and prices change between runs.

```json
{
  "mpnQuery": "NE555P",
  "status": "SUCCESS",
  "matchedMpn": "NE555P",
  "manufacturer": "TI",
  "distributorName": "LCSC",
  "distributorSku": "C46749",
  "packageCase": "DIP-8",
  "inStockQty": 36830,
  "isImmediateStockAvailable": true,
  "minOrderQty": 5,
  "packagingType": "Tube",
  "unitPrice1": null,
  "unitPrice10": 0.2541,
  "unitPrice100": 0.1953,
  "unitPrice1000": 0.141,
  "targetOrderQuantity": 100,
  "effectiveUnitPriceAtTargetQty": 0.1953,
  "totalExtendedCost": 19.53,
  "currency": "USD",
  "rohsCompliant": true,
  "datasheetUrl": "https://datasheet.lcsc.com/datasheet/pdf/bf41a18b474249308084584192c5b6ae.pdf?productCode=C46749",
  "productUrl": "https://www.lcsc.com/product-detail/C46749.html",
  "scrapedAt": "2026-10-20T12:00:00.000Z",
  "errorMessage": null
}
```

An unsuccessful lookup keeps `mpnQuery`, `targetOrderQuantity`, and `scrapedAt`, sets `status` to `ERROR`, and supplies a safe error code in `errorMessage`. Other extracted fields are null. Intentionally excluded out-of-stock matches produce no row.

### Use the results in Clay, n8n, Make, or your API

- **Clay:** Export CSV, import it into your table, and join on `mpnQuery`. Use `totalExtendedCost` and `isImmediateStockAvailable` as procurement filters.
- **n8n:** Run the Actor with the Apify integration or an HTTP Request node, then retrieve the run's default dataset. Branch on `status` before using a quote.
- **Make:** Add an Apify Actor run module followed by a dataset retrieval module. Send successful quotes to a spreadsheet or purchasing workflow.
- **API:** Start an Actor run with your MPN array, wait for completion, and retrieve items using the returned `defaultDatasetId`. See the official [Actor run API](https://docs.apify.com/api/v2/act-runs-post) and [dataset items API](https://docs.apify.com/api/v2/dataset-items-get).

For recurring BOM monitoring, create an Apify Task and schedule it. Compare successive datasets by `mpnQuery`, `distributorName`, and `currency`. Sum extended costs only within the same currency. Revalidate prices with the distributor before placing an order.

### Pricing and limits

The custom pay-per-event event is **`part-quoted`**. Only saved `SUCCESS` records receive that event. **`ERROR` rows cost $0 in event fees.** Matches intentionally excluded by the stock filter also incur no custom event fee. Platform usage, storage, and any proxy charges follow your Apify account's terms.

The active event price is shown on the Actor's Apify Store pricing panel. For a concrete arithmetic example, **if the configured price is $0.001 per successful quote, 1,000 successful quotes cost $1.00 in event fees**. A run with 900 successful quotes and 100 errors would cost $0.90 in event fees at that illustrative rate. This example does not set or promise the deployed price.

Free Apify accounts are limited to **25 saved records per run**, counting both successes and errors. Paying accounts and local runs have no additional application-level saved-item cap. The input allows up to 10,000 MPNs per run. The Actor stops cleanly when its event budget is exhausted and flushes buffered results.

For deployment, configure `part-quoted` in Apify Console. Leave the automatic `apify-default-dataset-item` event free or disabled so error rows remain free of event fees. The Actor refuses to extract under an automatic paid dataset-item configuration. Event prices are managed by Apify Console rather than the repository. See [Apify pay-per-event documentation](https://docs.apify.com/sdk/js/docs/concepts/pay-per-event).

### FAQ and troubleshooting

**Why is there no result for an MPN?**

Only exact manufacturer part numbers are accepted as matches. Similar or substitute components are never silently returned. An unavailable catalog, blocked request, malformed response, or missing public price becomes an uncharged error row. With `onlyInStock: true`, known matches without confirmed immediate availability are filtered out.

**Why are some price fields empty?**

The source may not publish a price for that quantity, the quantity may be below MOQ, or the quantity may violate an order multiple or maximum. JSON-LD aggregate low prices and scalar prices without an explicit eligible quantity are not treated as prices for one piece.

**Why does stock differ from the distributor's checkout?**

Catalog availability can change during a run. Stock totals can include delayed inventory while the immediate-stock flag is false. Aggregator feeds can update later than direct distributor data. The Actor does not reserve stock.

**Can each BOM line have its own quantity?**

The current input applies one target quantity to all MPNs. Group MPNs by required quantity and use separate runs when your BOM contains different line quantities.

**Can this run with limited permissions?**

Yes. Plan eligibility is derived from the injected paying-user flag. The application never requests `/v2/users/me`; proxy configuration disables account access checks and uses only the runtime proxy credential or your explicitly supplied custom proxies.

**How are interrupted downloads and shutdown handled?**

HTML responses are limited to 4 MiB after decompression, JSON to 2 MiB, and XML to 15 MiB. Complete quotes recovered before a response limit can be retained. A timeout or reset can salvage HTML after a successful HTTP status and at least 16 KiB of parsed data. Incomplete table rows and scripts are discarded. JSON is never salvaged partially. SIGINT, SIGTERM, and Apify abort events cancel active requests and flush buffered dataset rows.

**How is untrusted data handled?**

Requests and every redirect require public IP addresses, with validated DNS answers pinned to the connection. Proxy tunnels connect to the validated destination IP while preserving the original TLS hostname. Private addresses, metadata endpoints, URL credentials, unexpected protocols, and insecure redirects are rejected. Parsers do not resolve external entities, nesting is capped at 128, dangerous JSON keys are removed, and formula-like dataset strings receive a leading apostrophe. Failure records expose safe identifiers and codes rather than source responses or stack traces.

### Development and verification

Requires Node.js 22 or newer.

```sh
npm ci --ignore-scripts
npm run build
npm test
npm run smoke
```

`npm test` compiles and runs the `node:test` suite with production environment settings and `UV_THREADPOOL_SIZE=64`. It covers SSRF, mixed DNS answers, DNS pinning, redirects, HTTP/2 fallback, proxy selection, stream caps, partial salvage, exact MPN matching, price tiers, decimal arithmetic, schema compatibility, free-plan limits, cancellation, and success-only event billing.

`npm run smoke` runs the real Actor in a fresh temporary local storage directory, using the two prefilled MPNs and a 160 MiB V8 heap limit. It checks the process exit code, saved dataset schema, exact matches, and positive target costs. Pass additional MPNs as arguments to inspect other real catalog queries:

```sh
npm run smoke -- SN74LVC1G08DBVR LM358DR
```

For a local Actor run, save the input as `storage/key_value_stores/default/INPUT.json`, then run `npm start`. No credential file is needed for direct requests.

```sh
docker build -t electronic-components-bom-price-stock-monitor .
```

Mount a storage directory containing `key_value_stores/default/INPUT.json` at `/app/storage` when running the container locally. The multi-stage image uses `node:22-alpine`, runs as the non-root `node` user, and sets `UV_THREADPOOL_SIZE=64` and `NODE_ENV=production`.

Repository initialized by Arezgit.

# Actor input Schema

## `partNumbers` (type: `array`):

Paste one MPN per line. Exact matching ignores case; package and order-code suffixes remain significant. Duplicate MPNs are processed once.

## `onlyInStock` (type: `boolean`):

Save a quote only when the source explicitly reports immediate stock. Filtered MPNs produce no row or event fee.

## `targetOrderQuantity` (type: `integer`):

Quantity applied to every MPN. Costs remain empty when MOQ, order multiples, or published price tiers do not support this quantity.

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

Maximum parallel MPN lookups. The runtime lowers this when necessary for the available memory.

## `timeoutSecs` (type: `integer`):

Total lookup deadline per MPN, including source fallbacks and proxy retries.

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

Direct connections run first. Datacenter fallback is automatic after blocking. Explicitly enable Apify Proxy to allow the configured final tier; custom proxy URLs force your selected proxies.

## Actor input object example

```json
{
  "partNumbers": [
    "STM32F103C8T6",
    "NE555P"
  ],
  "onlyInStock": false,
  "targetOrderQuantity": 100,
  "maxConcurrency": 10,
  "timeoutSecs": 15
}
```

# Actor output Schema

## `results` (type: `string`):

Default dataset items. Review each record status before using extracted data downstream.

# 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 = {
    "partNumbers": [
        "STM32F103C8T6",
        "NE555P"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("arezdev/electronic-components-bom-price-stock-monitor").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 = { "partNumbers": [
        "STM32F103C8T6",
        "NE555P",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("arezdev/electronic-components-bom-price-stock-monitor").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 '{
  "partNumbers": [
    "STM32F103C8T6",
    "NE555P"
  ]
}' |
apify call arezdev/electronic-components-bom-price-stock-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,arezdev/electronic-components-bom-price-stock-monitor"
        }
    }
}
```

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/rLscfa1jAIBBBvbJN/builds/e3EyOhn4mqFKyJmoP/openapi.json
