# Stuller Jewelry Product Scraper — Catalog Specs & Images (`muhammadafzal/stuller-jewelry-product-scraper`) Actor

Extract Stuller jewelry product data from product URLs: item number, metal, stone, weight, specifications, options and images. USD 5 per 1,000 products.

- **URL**: https://apify.com/muhammadafzal/stuller-jewelry-product-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 stuller 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

## Stuller Jewelry Product Scraper — Catalog Specs & Images

Stuller Jewelry Product Scraper extracts public product records from the Stuller jewelry catalog: item number, series, title, product type, metal quality, primary stone type, shape and size, availability, weight, full specifications, selectable options and image URLs. It is built for jewelry retailers, catalog managers and product-data teams who need structured Stuller product data from specific product pages, and it costs USD 5 per 1,000 products on the FREE tier (USD 4 on GOLD).

### What Stuller jewelry data does the scraper return?

Each dataset row is one Stuller inventory item, the exact variant selected by the URL you supply. Rows are deduplicated by `productId`.

| Field | What it contains |
|---|---|
| `productId`, `itemNumber`, `series`, `groupId` | Stuller identifiers, for example item number `124090:600:P` |
| `title`, `description`, `productType` | Product name, Stuller's attribute summary line, and type such as `Rings` |
| `url`, `sourceUrl` | Clean product URL and the page actually fetched |
| `metalQuality`, `jewelryState`, `finishState` | For example `14K White Gold`, `Set`, `Polished` |
| `primaryStoneType`, `primaryStoneShape`, `primaryStoneSize` | For example `Natural Diamond`, `Round`, `3.8 mm` |
| `availability`, `isMadeToOrder`, `soldBy` | For example `Made To Order`, `true`, `Each` |
| `weightGrams` | Product weight in grams |
| `price`, `currency`, `priceRequiresLogin` | Price only when Stuller shows it publicly; otherwise `null` and `priceRequiresLogin: true` |
| `attributes` | The selected attribute values, keyed by Stuller's labels |
| `availableOptions` | The choices offered on the page for each attribute, such as other metal qualities |
| `specifications` | The specification table, for example ring fit, plating, carat weight, diamond color and clarity, dimensions |
| `imageUrls` | Product image URLs |
| `additionalDetails`, `comesSetWith`, `canBeSetWith` | Extra page text, including the stones the item comes set with |
| `scrapedAt` | Collection time (ISO 8601) |

The run summary is saved as `OUTPUT` in the key-value store: outcome, records delivered, requests used, warnings, stop reason and charged event counts. Problems are reported there and never written as fake products.

### Which Stuller URLs can I scrape?

Exact product pages and public `/browse/` landing pages on `www.stuller.com`, up to 100 URLs per run.

```json
{
  "startUrls": [
    { "url": "https://www.stuller.com/products/124090/16184912/?groupId=202200" },
    { "url": "https://www.stuller.com/products/87184/17353634/?groupId=205032" },
    { "url": "https://www.stuller.com/products/details/?iid=199048" }
  ],
  "maxResults": 10
}
```

Product URLs look like `/products/124090/16184912/?groupId=202200`, `/products/2255/?groupId=14156` or `/products/details/?iid=199048`. Remove tracking parameters; only numeric `groupId`, `iid`, `gid` and `categoryId` are accepted, and anything else is rejected before any request. A browse landing page is accepted and adds the product links it shows; on 2026-10-27, `/browse/jewelry/` exposed 14 product links and a cloud run saved 2 products from it. The Actor does not search by keyword, page through the interactive catalog, follow subcategories, or list every variant of a product, so supply the exact URLs you want.

### Does it return Stuller wholesale prices?

No. Stuller shows prices only to signed-in jewelry businesses, and the Actor never logs in. When a price is hidden, the record has `price: null`, `currency: null` and `priceRequiresLogin: true`. Everything else on the public page, including weight, specifications and availability, is returned.

### How long does a run take?

About 10 seconds per page or more; the default one-product run finished in under a minute on 2026-10-26. The Actor reads Stuller's robots.txt at the start of every run, refuses disallowed paths, and waits at least 10 seconds between requests, or longer if robots.txt asks for it. A 100-product run therefore takes 17 minutes or more. Runs stop early after 60 seconds without a new product, after three failures or three missing pages in a row, at `maxRequests`, or at the 29-minute runtime limit.

### What happens when Stuller blocks a request?

The run stops cleanly and tells you why. In the visible cloud runs from 2026-10-08 and 2026-10-26, 13 of 14 runs with valid product URLs delivered products and one was blocked. Verification challenges are not retried or bypassed, and no browser or proxy fallback is used. A blocked or failed run with no products ends with a failed status and `OUTPUT.outcome` set to `BLOCKED` or `FAILED`. A product ID that does not exist, which Stuller redirects to its inactive-product page, ends successfully as `EMPTY` with no products charged. Products saved before the problem stay in the dataset as a `PARTIAL` result. You pay only the start event plus the products actually saved.

### When should I use it, and when not?

**Use it when** you have a list of Stuller product pages and need their attributes, specifications and images in a spreadsheet or database, for example to build product pages for mountings and bands you sell, to compare metal and stone options, or to check availability notes.

**Use another Actor when:**

- You need wholesale prices: they require a Stuller account and are not available here.
- You want a whole category without URLs: keyword search and catalog paging are not supported.
- You need another wholesale jewelry catalog with prices: [ITI NYC Jewelry Scraper](https://apify.com/muhammadafzal/iti-nyc-scraper).
- You need jewelry brands that sell on their own Shopify store: [Shopify Product Scraper](https://apify.com/muhammadafzal/shopify-product-scraper).

### How do I run it from code?

JavaScript with `apify-client`:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('muhammadafzal/stuller-jewelry-product-scraper').call({
    startUrls: [{ url: 'https://www.stuller.com/products/124090/16184912/?groupId=202200' }],
    maxResults: 1,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const p of items) console.log(p.itemNumber, p.title, p.metalQuality, p.weightGrams);
```

Python with `apify-client`:

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("muhammadafzal/stuller-jewelry-product-scraper").call(run_input={
    "startUrls": [{"url": "https://www.stuller.com/products/124090/16184912/?groupId=202200"}],
    "maxResults": 1,
})
for p in client.dataset(run.default_dataset_id).iterate_items():
    print(p["itemNumber"], p["title"], p["availability"], p["specifications"].get("Diamond CTW"))
```

### Use it from an AI assistant

Stuller Jewelry Product Scraper works from Claude, ChatGPT, Cursor or any MCP client through Apify's MCP server. Add the single-tool URL `https://mcp.apify.com/?tools=muhammadafzal/stuller-jewelry-product-scraper` to your client and ask, for example: "Get the metal, stone, weight and specifications for this Stuller product: https://www.stuller.com/products/124090/16184912/?groupId=202200." Paste exact product URLs, because the Actor does not search.

### What does the output look like?

The default product from the 2026-10-26 cloud run (long fields shortened):

```json
{
  "productId": "16184912",
  "itemNumber": "124090:600:P",
  "series": "124090",
  "groupId": "202200",
  "title": "14K White Gold 7/8 CTW Natural Diamond Anniversary Band",
  "url": "https://www.stuller.com/products/124090/16184912/?groupId=202200",
  "productType": "Rings",
  "metalQuality": "14K White Gold",
  "primaryStoneType": "Natural Diamond",
  "primaryStoneShape": "Round",
  "primaryStoneSize": "3.8 mm",
  "jewelryState": "Set",
  "finishState": "Polished",
  "availability": "Made To Order",
  "isMadeToOrder": true,
  "weightGrams": 2.97,
  "soldBy": "Each",
  "price": null,
  "currency": null,
  "priceRequiresLogin": true,
  "imageUrls": ["https://meteor.stullercloud.com/das/73468133?obj=metals&obj=stones/diamonds/g_accent&obj=metals&obj.recipe=white"],
  "availableOptions": {
    "Quality": ["14K Yellow Gold", "14K White Gold", "14K Rose Gold", "Platinum"],
    "Primary Stone Type": ["Lab-Grown Diamond", "Natural Diamond"]
  },
  "specifications": {
    "Plating Type": "Rhodium-Plated",
    "Diamond CTW": "7/8 CTW",
    "Diamond Clarity": "SI2-SI3",
    "Diamond Color": "G-H",
    "Approx. Finger Size": "7"
  },
  "scrapedAt": "2026-10-26T07:24:06.715Z"
}
```

### How much does Stuller product data cost?

The Actor uses pay-per-event pricing, and platform usage is included in the event prices. Each product saved to the dataset is one charged event.

| Event | FREE | BRONZE | SILVER | GOLD | PLATINUM / DIAMOND |
|---|---:|---:|---:|---:|---:|
| Stuller product (one dataset row) | USD 0.005 | USD 0.004875 | USD 0.00475 | USD 0.004 | USD 0.004 |
| Actor start (per started GB of allocated memory) | USD 0.00625 | USD 0.00609375 | USD 0.0059375 | USD 0.005 | USD 0.005 |

The Actor runs with 256 MB of memory, so each run has one start event. Worked totals on the FREE tier:

- 1 product (the default input): USD 0.005 + USD 0.00625 = **USD 0.01125**
- 100 products: 100 × USD 0.005 + USD 0.00625 = **USD 0.50625** (USD 0.405 on GOLD)

A run that delivers nothing costs only the start event.

### FAQ

**Do I need a Stuller account or API access?** No. The Actor uses no account, login or private API; it reads the public product pages any visitor can open, which is also why wholesale prices are not included.

**Can it scrape the whole Stuller catalog?** No. It scrapes the product URLs you give it, up to 100 products per run.

**Why are some text fields long or repeated?** `additionalDetails` and `comesSetWith` copy the page's tab text as one string, and on some products the same block appears several times. Use `specifications` and `attributes` for clean values.

**Does `availableOptions` mean every option is in stock?** No. It lists the choices the page offers, not stock levels. `availability` is a snapshot of what the page shows at run time.

**Why did my run fail with no products?** Usually Stuller blocked the page. An unknown or retired product ID is not a failure: the run succeeds with `OUTPUT.outcome` set to `EMPTY`. A URL with tracking or other unsupported parameters is rejected before any request. Check `OUTPUT.warnings` for the reason; nothing is fabricated, and only the start event is charged.

**Can I run it on a schedule?** Yes. Schedule the same URL list to track availability or option changes over time.

### Related Actors

- [ITI NYC Jewelry Scraper — Product Prices & SKUs](https://apify.com/muhammadafzal/iti-nyc-scraper)
- [Shopify Product Scraper — Prices, Variants & CSV Export](https://apify.com/muhammadafzal/shopify-product-scraper)
- [Industrial Hardware & Components Catalog Scraper](https://apify.com/muhammadafzal/industrial-hardware-components-catalog-scraper)

### Legal and data use

The Actor reads public product pages, follows Stuller's robots.txt, and does not sign in or bypass verification. Product text and images belong to Stuller; check your rights before republishing them. This independent Actor is not affiliated with or endorsed by Stuller, Inc.

Last verified: 2026-10-27

# Actor input Schema

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

Use exact HTTPS Stuller product URLs, for example https://www.stuller.com/products/124090/16184912/?groupId=202200, or public /browse/ landing pages such as https://www.stuller.com/browse/jewelry/. Up to 100 entries; default is one anniversary band. Strip tracking parameters. Interactive category search and pagination are unsupported.

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

Use to cap unique delivered products. Default 10, range 1–100. URL-selected variants count individually.

## `maxRequests` (type: `integer`):

Use to bound product and browse requests, redirects and retries. Default 30, range 1–120. robots.txt verification is additional. Crawling waits at least 10 seconds between requests.

## `requestTimeoutSecs` (type: `integer`):

Use to bound one HTTP request. Default 30 seconds, range 5–60. At most one retry; no browser or proxy fallback.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.stuller.com/products/124090/16184912/?groupId=202200"
    }
  ],
  "maxResults": 10,
  "maxRequests": 30,
  "requestTimeoutSecs": 30
}
```

# Actor output Schema

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

Deduplicated Stuller product records.

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

Outcome, limits, warnings and event counts.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.stuller.com/products/124090/16184912/?groupId=202200"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/stuller-jewelry-product-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 = { "startUrls": [{ "url": "https://www.stuller.com/products/124090/16184912/?groupId=202200" }] }

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/stuller-jewelry-product-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 '{
  "startUrls": [
    {
      "url": "https://www.stuller.com/products/124090/16184912/?groupId=202200"
    }
  ]
}' |
apify call muhammadafzal/stuller-jewelry-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/stuller-jewelry-product-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/wBD1AABTJG5bhFKmg/builds/mPnzEPwkHbhhBHe6d/openapi.json
