# OfferUp Scraper (`crawloop/offerup-scraper`) Actor

Scrape OfferUp listings by keyword, ZIP, and price filters. Each row has the asking price, condition, city, and photo from the public search. Monitor mode saves only new listings and price changes.

- **URL**: https://apify.com/crawloop/offerup-scraper.md
- **Developed by:** [Andrej Kiva](https://apify.com/crawloop) (community)
- **Categories:** E-commerce, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 listings

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

## OfferUp Scraper

> **Disclaimer:** Unofficial tool — not affiliated with, sponsored by, or endorsed by OfferUp Inc. or its affiliates. Data is read from publicly accessible search results only. No login. You are responsible for complying with applicable law (including GDPR where personal data appears) and the site’s terms. No warranty on accuracy or availability. Provided for informational and research use.

**OfferUp scraper** for US local listings. Each row is one search card: asking price in USD, condition, city, and photo. Search by keyword and ZIP, or paste a results URL. Use it as an **OfferUp API alternative** from **Python**, **Node.js**, **cURL**, or **Apify MCP**.

**Best for:** phone and furniture comps in one ZIP, price-filtered leads, and a scheduled run that saves only new listings and price changes.

| Actor | Role |
| :--- | :--- |
| OfferUp Scraper ◄── you are here | US classifieds: price, condition, city, new-listing monitor |
| [Facebook Marketplace Scraper](https://apify.com/crawloop/facebook-marketplace-scraper) | US marketplace listings |
| [eBay Sold Listings Scraper](https://apify.com/crawloop/ebay-sold-listings-scraper) | Sold comps for the same goods |
| [Leboncoin Scraper](https://apify.com/crawloop/leboncoin-scraper) | France classifieds |
| [Vinted Monitor](https://apify.com/crawloop/vinted-monitor) | Fashion resale alerts |
| [Depop Monitor](https://apify.com/crawloop/depop-monitor) | Depop new listings |
| [Poshmark Sold Listings Scraper](https://apify.com/crawloop/poshmark-sold-listings-scraper) | Poshmark sold comps |

### When to use this Actor

- **A keyword in a ZIP** — Set Keyword to iphone and ZIP to 10001. Leave Search URLs empty.
- **A price band** — Set a minimum or maximum. Add a condition such as Used when you want that filter.
- **A results page you already opened** — Paste the search URL. Keyword and ZIP are ignored when Search URLs is set.
- **New ads and price cuts** — Turn on monitor mode and schedule the same search. The first run stores a baseline and saves nothing. Later runs save new listing ids and price changes.

### When not to use this Actor

- **A single listing page** — Item pages are not requested. The row is the search card.
- **Seller phone numbers or a full seller profile** — Those are not on the search card.
- **A national dump in one run** — Cap `maxItems` (150). Split by ZIP.

### Key features

- **Search cards** — Title, USD price, condition, city, photo, delivery flags, and vehicle miles when the card includes them. Default **256 MB**. No browser.
- **Keyword, ZIP, radius, price, and condition** — Recent, closest, or price sort.
- **Pasted search URL** — a results link. Listing URLs are skipped.
- **Promoted tiles** — A seller promotion is still one listing. `promoted` is true on that row. Display ads are dropped.
- **Monitor** — Named key-value store of listing id and last price for that search. The seed run saves nothing.

### Input

| Field | Required | Default | What it does |
| :--- | :--- | :--- | :--- |
| Search URLs | No | — | Wins over the filters below. |
| Keyword | No | iphone when the form is empty | Search text when URLs are empty. |
| ZIP code | No | 10001 | US ZIP the search is centered on. |
| Radius | No | 30 miles | Distance from the ZIP. 50 miles is the widest step. |
| Minimum / maximum price | No | — | Asking-price band in USD. |
| Condition | No | any | New, open box, reconditioned, used, for parts, other. |
| Sort | No | Recent first | Applied when the Actor builds the search. |
| Maximum listings | No | 30 | Cards to examine, up to 150. |
| Monitor mode | No | off | Baseline first, then new ids and price changes. |
| Monitor state store | No | offerup-monitor | Named store for the baseline. |
| Proxy | No | off | Turn on US residential only if a run is blocked. |

```json
{
  "keyword": "iphone",
  "zipCode": "10001",
  "radius": "30",
  "sort": "-posted",
  "maxItems": 30,
  "monitorMode": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

### Output

| Field | Meaning |
| :--- | :--- |
| `id` | Listing id |
| `url` | Public listing path built from the id |
| `title` | Listing title |
| `price` | Asking price in USD |
| `condition` | Condition text from the card |
| `location` | City and state |
| `image` | Photo URL |
| `isFirmPrice` | True when the card marks the price as firm |
| `vehicleMiles` | Odometer when the card includes it |
| `flags` | Delivery flags such as `LOCAL_PICKUP` |
| `promoted` | True on a promoted seller tile |
| `changeType` | `new` or `price_change` on monitor runs |
| `previousPrice` | Prior asking price when `changeType` is `price_change` |
| `scrapedAt` | UTC timestamp |

```json
{
  "id": "11111111-1111-1111-1111-111111111111",
  "url": "https://offerup.com/item/detail/11111111-1111-1111-1111-111111111111",
  "title": "iPhone 13 128GB",
  "price": 400,
  "currency": "USD",
  "condition": "Used",
  "location": "Yonkers, NY",
  "image": "https://images.offerup.com/example.jpg",
  "isFirmPrice": false,
  "flags": ["LOCAL_PICKUP"],
  "scrapedAt": "2026-09-29T12:00:00Z"
}
```

### Use cases

- Compare asking prices for one phone model inside a ZIP and keep condition and pickup flags.
- Pull sofas under a price cap and export city plus photo for a lead list.
- Schedule monitor mode each morning and export only listings whose price moved.
- For sold comps on the same goods, run [eBay Sold Listings Scraper](https://apify.com/crawloop/ebay-sold-listings-scraper). For other US marketplace posts, run [Facebook Marketplace Scraper](https://apify.com/crawloop/facebook-marketplace-scraper).

### Integration examples

Replace `APIFY_TOKEN`. The slug below is the Store name.

#### Node.js

```javascript
import { ApifyClient } from "apify-client";

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor("crawloop/offerup-scraper").call({
  keyword: "iphone",
  zipCode: "10001",
  maxItems: 30,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("crawloop/offerup-scraper").call(run_input={
    "keyword": "sofa",
    "zipCode": "90210",
    "maxPrice": 200,
    "maxItems": 30,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(len(items))
```

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/crawloop~offerup-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keyword":"iphone","zipCode":"10001","maxItems":30}'
```

### MCP and AI assistants

Use this Actor from AI tools via [Apify MCP](https://docs.apify.com/platform/integrations/mcp).
Connect your Apify account, then call this Actor by its Store name `crawloop/offerup-scraper`.

Example prompts:

- "Run OfferUp Scraper for iphone in ZIP 10001 and return price, condition, and location as JSON"
- "Scrape OfferUp sofas in 90210 under 200 dollars and list title, price, and city"
- "Run OfferUp Scraper in monitor mode for honda civic in 10001, then use eBay Sold Listings Scraper for sold comps"

### Suite next step

This Actor covers US local classifieds. For sold prices on the same goods, run [eBay Sold Listings Scraper](https://apify.com/crawloop/ebay-sold-listings-scraper). For other US marketplace posts, run [Facebook Marketplace Scraper](https://apify.com/crawloop/facebook-marketplace-scraper).

### FAQ

**Does this open every listing page?**
No. Each row is the public search card. Description and seller profile are not requested.

**Which country is included?**
United States searches by ZIP. Other countries are not requested.

**What if the run is blocked?**
Retry once with the proxy off. If the run still fails, turn on a US residential proxy.

**What does monitor mode skip?**
Listing ids already stored for that same search, unless the asking price changed. A quiet tick writes zero rows. The first run only fills the baseline.

**Are phone numbers included?**
No. The row has the public price, city, condition, and photo from the search card.

# Actor input Schema

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

offerup.com/search URLs. When this list is set, keyword, ZIP, and filters below are ignored. Listing pages are not fetched.

## `keyword` (type: `string`):

Search text used when Search URLs is empty. Example: iphone, sofa, honda civic.

## `zipCode` (type: `string`):

US ZIP the search is centered on. Example: 10001.

## `radius` (type: `string`):

Miles from the ZIP. 50 is the widest step on the search slider.

## `minPrice` (type: `integer`):

Drop listings under this asking price. Leave empty for no minimum.

## `maxPrice` (type: `integer`):

Drop listings over this asking price. Leave empty for no maximum.

## `conditions` (type: `array`):

Keep these conditions. Leave empty for any condition.

## `sort` (type: `string`):

Sort used when the Actor builds the search. Pasted URLs keep their own sort.

## `maxItems` (type: `integer`):

How many listings to examine. Monitor mode saves only new ids and price changes from this many cards.

## `monitorMode` (type: `boolean`):

The first run for a search stores a baseline and saves nothing. Later runs save new listings and price changes only.

## `monitorStateStore` (type: `string`):

Named key-value store that keeps the baseline between scheduled runs.

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

Off by default. Turn on a US residential proxy only if a run is blocked.

## Actor input object example

```json
{
  "keyword": "iphone",
  "zipCode": "10001",
  "radius": "30",
  "sort": "-posted",
  "maxItems": 30,
  "monitorMode": false,
  "monitorStateStore": "offerup-monitor",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Default dataset items — one listing per row.

# 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 = {
    "keyword": "iphone",
    "zipCode": "10001"
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawloop/offerup-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 = {
    "keyword": "iphone",
    "zipCode": "10001",
}

# Run the Actor and wait for it to finish
run = client.actor("crawloop/offerup-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 '{
  "keyword": "iphone",
  "zipCode": "10001"
}' |
apify call crawloop/offerup-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawloop/offerup-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/IB3W89NyuABSfEIir/builds/M2Uohb4mH2eAL3FvA/openapi.json
