# Sysco Food Service Scraper (`muhammadafzal/sysco-food-service-scraper`) Actor

Extract public Sysco Foodie catalog products with SUPC codes, names, brands, pack sizes, descriptions, images, and source URLs. Customer-only Sysco Shop prices are not accessed.

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

## Pricing

from $11.99 / 1,000 sysco product records

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

## Sysco Food Service Scraper

**Free plan limit:** Free-plan users can receive up to **5 result records per run**. Paid-plan and local/unknown runs retain the Actor's existing limits.

Extract publicly visible Sysco catalog products from Sysco Foodie into a structured Apify dataset. The Actor returns product names, SUPC codes, brands, package sizes, descriptions, images, and canonical product URLs for catalog analysis, sourcing research, and data pipelines.

The scraper reads Sysco’s public Foodie catalog. It does **not** sign in to Sysco Shop, access customer order guides, or fabricate customer-specific pricing and availability. Those values depend on a customer account and distribution market and are outside this Actor’s public-data contract.

### What you can extract

Each dataset item has a stable shape:

| Field | Meaning |
|---|---|
| `supc` | SUPC exactly as displayed; some records contain multiple plus-separated codes |
| `supcCodes` | Individual SUPCs split into an array |
| `title` | Public Sysco Foodie product title |
| `displayName` | Detail-page display name, when enriched |
| `description` | Public detail-page description, when exposed |
| `brandCode` | Detail-page brand code, when exposed |
| `brand` | Public brand description |
| `pack` | Pack count from the detail page |
| `size` | Package or unit size |
| `imageUrl` | Public Sysco image URL |
| `productUrl` | Canonical Sysco Foodie detail URL |
| `sourceListingUrl` | Listing page where the record was found |
| `detailEnriched` | Whether the individual product page was parsed |
| `scrapedAt` | UTC extraction timestamp |

Use this Actor when you need a reproducible public Sysco product dataset, want to match product codes with names and brands, or need product references for market research. Do not use it for live customer pricing, inventory, ordering, invoices, private catalogs, or authenticated Sysco Shop workflows.

### Input

| Property | Default | Description |
|---|---:|---|
| `startUrls` | first catalog page | One or more public Sysco Foodie catalog listing, numbered page, or product URLs |
| `searchTerms` | `[]` | Optional title, SUPC, brand, size, or description filters; a record passes when any term matches |
| `maxResults` | `20` | Maximum dataset records and result events, from 1 to 1,000 |
| `maxPages` | `3` | Maximum catalog listing pages to follow, from 1 to 200 |
| `includeDetails` | `false` | Visit product pages to add description, display name, brand code, and pack count |
| `proxyConfiguration` | direct access | Optional owner-authorized Apify proxy configuration |

Fast listing-only example:

```json
{
  "startUrls": [{ "url": "https://foodie.sysco.com/sysco-products/" }],
  "searchTerms": ["chicken"],
  "maxResults": 10,
  "maxPages": 10,
  "includeDetails": false,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

Enriched direct-product example:

```json
{
  "startUrls": [
    { "url": "https://foodie.sysco.com/sysco-products/2-in-1-detergent-and-presoak-7217343/" }
  ],
  "maxResults": 1,
  "maxPages": 1,
  "includeDetails": true
}
```

When a product URL is supplied directly, its detail fields are extracted even if `includeDetails` is false. `maxPages` controls listing pagination only.

### Example output

```json
{
  "recordType": "product",
  "supc": "7217343",
  "supcCodes": ["7217343"],
  "title": "2-in-1 Detergent and Presoak",
  "displayName": "2-in-1 Detergent and Presoak",
  "description": "DETERGENT LIQ PRESOAK 2-IN-1",
  "brandCode": "Keystone",
  "brand": "Keystone",
  "pack": "4",
  "size": "1 GAL",
  "imageUrl": "https://image.sysco.com/image-server/product/image/7217343/web/3.jpg",
  "productUrl": "https://foodie.sysco.com/sysco-products/2-in-1-detergent-and-presoak-7217343/",
  "sourceListingUrl": "https://foodie.sysco.com/sysco-products/",
  "detailEnriched": true,
  "scrapedAt": "2026-08-28T12:00:00.000Z"
}
```

The default dataset contains product records only. Run diagnostics are written separately to the `OUTPUT` key-value-store record, including result count, finished and failed request counts, warnings, and runtime.

### Pay per event pricing

Current Apify event prices and platform-usage treatment are listed in the dedicated [Pricing section](#pricing) below.

A run returning 20 products costs $0.3198 in event charges. A one-product run costs $0.01599. `maxResults` is the direct cap on result events. Platform behavior may also enforce the maximum total charge configured for the run. The Actor never manually charges either synthetic event, preventing duplicate result billing.

### Reliability and limits

The Actor uses static HTTP extraction because the public catalog renders the needed fields in HTML. This is faster and less expensive than running a browser. Requests use bounded concurrency, a per-minute limit, two retries, strict Sysco URL validation, and deduplication by SUPC.

If a valid filter matches nothing within `maxPages`, the run returns an empty dataset and an explanatory warning. Invalid or non-Sysco URLs are rejected before crawling. If every request is blocked or fails, the run reports a blocked outcome with zero product records rather than generating placeholder data. You can retry later or configure an owner-authorized Apify proxy if public access is restricted in your region.

Search filtering is performed against pages the Actor actually visits. A narrow term may require a larger `maxPages` value because the source’s public catalog is paginated. Enabling `includeDetails` adds one request per discovered product and can increase runtime, but it does not add a second result charge.

### Legal and responsible use

Scrape only public data you are permitted to collect, follow applicable law and website terms, and use reasonable request limits. Product information and images remain the property of their respective owners. This Actor does not bypass authentication, CAPTCHAs, paywalls, or other access controls, and it does not collect customer accounts or personal data.

### Local development

```bash
npm ci
npm run typecheck
npm test
apify run --purge
```

For support, include the run ID, redacted input, expected outcome, and the affected public URL. Never include credentials or private account data in a support request.

### Pricing

This Actor uses **pay-per-event** pricing. These are the current Apify Store event prices:

| Event | Price (USD) | When it is charged |
|---|---:|---|
| `apify-default-dataset-item` | FREE: $0.01599; BRONZE: $0.01499; SILVER: $0.01399; GOLD: $0.01199; PLATINUM: $0.01199; DIAMOND: $0.01199 | Sysco product record — One schema-valid public Sysco catalog product written to the default dataset. |
| `apify-actor-start` | $0.005 | Actor Start — Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). — Charged once per run. |

Apify platform usage for this Actor run is included alongside the event prices above; no separate per-run platform-usage fee is passed to users.

This covers Apify platform usage for this Actor run. Other Apify products or usage outside this Actor run may still follow your account plan.

# Changelog

This Actor's version history is a separate document: https://apify.com/muhammadafzal/sysco-food-service-scraper/changelog.md

# Actor input Schema

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

Use this for a Sysco Foodie catalog listing, numbered page, or individual product page. Add URL objects under https://foodie.sysco.com/sysco-products/ only. The default starts at the first public catalog page; customer-only Sysco Shop URLs are not supported.

## `searchTerms` (type: `array`):

Use this to return records containing at least one keyword or SUPC, for example `chicken` or `7217343`. Matching covers title, SUPC, brand, size, and enriched descriptions. Leave empty to return every product encountered within the page and result limits.

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

Use this to cap delivered and billable dataset records. Default 20; accepted range 1–1,000. This is a result limit, not a page limit.

## `maxPages` (type: `integer`):

Use this to bound catalog pagination when starting from a listing. Default 3; accepted range 1–200. Individual product detail requests do not consume additional listing-page depth.

## `includeDetails` (type: `boolean`):

Use this when you need description, display name, brand code, and pack count from each product page. Default false for faster, lower-compute listing extraction; it does not reveal account prices or private ordering data.

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

Use this only when direct public access is restricted in your region. Configure an owner-authorized Apify proxy; the default makes direct requests without a proxy. This is not a place for raw proxy credentials.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://foodie.sysco.com/sysco-products/"
    }
  ],
  "searchTerms": [],
  "maxResults": 20,
  "maxPages": 3,
  "includeDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Schema-validated public product records.

## `dataset` (type: `string`):

Default dataset storage page.

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

Counts, warnings, and runtime diagnostics.

# 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://foodie.sysco.com/sysco-products/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/sysco-food-service-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://foodie.sysco.com/sysco-products/" }] }

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/sysco-food-service-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://foodie.sysco.com/sysco-products/"
    }
  ]
}' |
apify call muhammadafzal/sysco-food-service-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/sysco-food-service-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/HVxT9eRwpJob368N8/builds/KejdNeD8n17fVni2J/openapi.json
