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

Scrape OfferUp listings by keyword, category, or ZIP code, or look up specific listing IDs/URLs directly, with optional full detail, seller, and photo data.

- **URL**: https://apify.com/parsebird/offerup-scraper.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.99 / 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### OfferUp Scraper

Scrape [OfferUp](https://offerup.com/) listings by keyword, category, and ZIP code, or look up specific listing IDs and URLs directly — no login or app required.

<table><tr>
<td style="border-left:4px solid #1C1917;padding:12px 16px;font-weight:600">
Search any U.S. ZIP code by keyword or category, filter by price and condition, and optionally pull full listing detail — seller profile, photos, category, and fulfillment options — for every result.
</td>
</tr></table>

<br>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this OfferUp scraper: `parsebird/offerup-scraper` on Apify. Call it with the `ApifyClient` (Python: `ApifyClient(token).actor("parsebird/offerup-scraper").call(run_input={"query": "playstation", "zipCode": "94102", "maxItems": 50, "fetchDetails": True})`) or the equivalent JS client. Key inputs: `query` (keyword, default "iphone"), `zipCode` (U.S. ZIP, default "10001"), `category` (id like "1.5", parent.child format), `minPrice`/`maxPrice`, `conditions` (new, openBox, reconditioned, used, forParts, other), `sortBy` (bestMatch, recent, closest, lowPrice, highPrice), `fetchDetails` (default false, adds a `_details` object per item), `maxAge` (hours, with sortBy=recent + fetchDetails), `maxItems` (default 10, 0 = unlimited), and `listingIds` (listing IDs or item URLs — when set, search is skipped and these are looked up directly with full details). Output is one JSON object per listing: `listingId`, `title`, `price`, `formattedPrice`, `locationName`, `image`, `flags`, `url`, plus `_details` and `_detailsStatus` (`success`/`not-found`/`error`) when details were requested. Full API reference: https://apify.com/parsebird/offerup-scraper/api. Get an API token at https://console.apify.com/account/integrations.

### What does OfferUp Scraper do?

This OfferUp scraper extracts structured listing data from offerup.com without an official API. It supports two input modes:

- 🔍 **Search mode** — search by keyword, category, or both, centered on any U.S. ZIP code. Filter by price range and condition, and sort by best match, recency, distance, or price.
- 🔗 **Direct lookup mode** — paste specific listing IDs or `offerup.com/item/detail/...` URLs to fetch exactly those listings, always with full detail.
- 🏷️ **Category browsing** — pick from OfferUp's full category tree (all 14 top-level departments and their subcategories) using the same `parent.child` ids the site itself uses (e.g. `1.5` for Video games & Consoles).
- 🧾 **Full listing detail** — condition, description, seller profile and rating, all photos, shipping/pickup options, and category hierarchy, when `fetchDetails` is on.
- ⏱️ **Freshness filter** — cap results to ads posted within the last N hours when sorting by recency.
- 🔁 **Resilient to blocks** — runs over a residential U.S. proxy so it isn't limited to whatever a single IP can see.

Because it runs on the [Apify platform](https://apify.com), you also get scheduling (track new listings daily), instant API and webhook access, and one-click export to JSON, CSV, Excel, HTML, or XML.

### What data can you extract from OfferUp?

| Field | Description |
|-------|-------------|
| `listingId`, `url` | OfferUp's internal listing UUID and the public item URL |
| `title`, `price`, `formattedPrice` | Listing title and price (raw and formatted, e.g. `"$60"`) |
| `conditionText`, `flags` | Condition label and flags like `LOCAL_PICKUP` |
| `locationName` | City/state the listing is posted in |
| `image` | Thumbnail `{url, width, height}` |
| `isFirmPrice`, `priceDropPercentage`, `formattedOriginalPrice` | Pricing context |
| `_details.description`, `_details.condition` | Full description and numeric condition score (needs `fetchDetails`) |
| `_details.photos` | Every photo, in multiple sizes up to full resolution |
| `_details.owner.profile` | Seller name, join date, rating average/count, response time |
| `_details.listingCategory.categoryV2` | Category hierarchy (`l1Name`, `l2Name`) |
| `_details.fulfillmentDetails` | Local pickup / shipping availability and pricing |
| `_details.locationDetails` | Latitude, longitude, ZIP code, distance |
| `_detailsStatus` | `success`, `not-found`, or `error` for the detail request |

### How to scrape OfferUp listings

1. Click **Try for free** on the [OfferUp Scraper](https://apify.com/parsebird/offerup-scraper) page (no credit card needed to start).
2. Enter a search keyword (e.g. `iphone 15`), a ZIP code, and optionally a category and price range — or switch to direct lookup by pasting listing URLs into `listingIds`.
3. Turn on `fetchDetails` to get seller info, photos, and category data for every result.
4. Click **Start** and watch results land in the dataset in real time.
5. Export the finished dataset as JSON, CSV, Excel, HTML, or XML, or pull it via the [API](https://apify.com/parsebird/offerup-scraper/api) / [integrations](https://docs.apify.com/platform/integrations).

### Input / Output

Example input:

```json
{
  "maxItems": 50,
  "query": "playstation",
  "zipCode": "94102",
  "category": "1.5",
  "minPrice": 50,
  "maxPrice": 500,
  "conditions": ["new", "used"],
  "fetchDetails": true
}
```

Direct item lookup (skips search entirely):

```json
{
  "maxItems": 2,
  "listingIds": [
    "50f175dd-7dfd-35ea-875e-2349b92554d5",
    "https://offerup.com/item/detail/ac5f8f61-a479-3a3b-bd0b-6dbcea95ea9d"
  ]
}
```

Output example (truncated):

```json
{
  "listingId": "ac5f8f61-a479-3a3b-bd0b-6dbcea95ea9d",
  "title": "Backbone PlayStation",
  "price": "60",
  "formattedPrice": "$60",
  "locationName": "Newark, CA",
  "image": { "url": "https://images.offerup.com/...", "width": 250, "height": 250 },
  "url": "https://offerup.com/item/detail/ac5f8f61-a479-3a3b-bd0b-6dbcea95ea9d",
  "_detailsStatus": "success",
  "_details": {
    "condition": 100,
    "conditionDisplayText": "New",
    "owner": { "profile": { "name": "Michael", "ratingSummary": { "average": 5, "count": 7 } } }
  }
}
```

Download results as **JSON, CSV, Excel, HTML, or XML** from the Console, or via the [Apify API](https://docs.apify.com/api/v2).

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("parsebird/offerup-scraper").call(run_input={
    "query": "playstation",
    "zipCode": "94102",
    "maxItems": 50,
    "fetchDetails": True,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["formattedPrice"])
```

#### JavaScript

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('parsebird/offerup-scraper').call({
    query: 'playstation',
    zipCode: '94102',
    maxItems: 50,
    fetchDetails: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Categories

The `category` input accepts any id from OfferUp's own category tree, in `parent.child` format (e.g. `1.5` for Video games & Consoles, `5.1` for Cars & Trucks). Pick one from the dropdown in the Input tab, which lists all 14 top-level departments (Electronics & Media, Home & Garden, Vehicles, Toys/Games/Hobbies, Sports & Outdoors, Collectibles & Art, Pet supplies, Health & Beauty, Wedding, Business equipment, Tickets, and more) and their subcategories. Leave it blank to search across all categories.

### Use cases

- **Deal hunting** — search a category or keyword across a ZIP code and sort by price to find the cheapest listings.
- **Local market research** — track how many listings, and at what price, exist for a product in a given area.
- **Lead generation** — pull seller contact/profile data for a product category to build outreach lists.
- **Price trend monitoring** — schedule daily runs with `sortBy: "recent"` and `maxAge` to catch new listings as they're posted.
- **Arbitrage / resale tools** — compare `price` across ZIP codes or categories to spot underpriced listings.

### How it works

1. The Actor opens a residential U.S. session against offerup.com and calls the same internal GraphQL API the website itself uses.
2. In search mode, your ZIP code is resolved to coordinates, then the Actor pages through the results feed (using OfferUp's own cursor-based pagination) applying your price, condition, and category filters.
3. In direct lookup mode, listing IDs are extracted from bare UUIDs or full item URLs, deduplicated, and fetched directly.
4. When `fetchDetails` is on (or always, for direct lookups), each kept listing gets one extra request for its full detail: description, seller profile, photos, and category.
5. Every result is pushed to the dataset as soon as it's ready.

### How much does it cost to scrape OfferUp?

This Actor uses the [Pay-Per-Event](https://docs.apify.com/platform/actors/publishing/monetize#pay-per-event-pricing-model) pricing model — you only pay for what you get, with no separate compute charge.

| Event | Free | Bronze | Silver | Gold |
|-------|------|--------|--------|------|
| Listing (per 1,000) | $1.49 | $1.29 | $1.09 | $0.99 |
| Detail (per 1,000, when fetchDetails is on) | $1.49 | $1.29 | $1.09 | $0.99 |

A search for 1,000 listings with `fetchDetails` on costs roughly $2.98 (Free plan) down to $1.98 (Gold plan). Leaving `fetchDetails` off (title/price/location only) roughly halves the cost. Apify's monthly platform usage credits apply to any plan.

### Is it legal to scrape OfferUp?

Yes — scraping publicly available data is generally legal, as confirmed in cases like *hiQ Labs v. LinkedIn*. This Actor only collects listing information that's publicly visible on offerup.com to anyone browsing the site. You are responsible for how you use the collected data — always check the target site's terms of service and applicable law before reusing scraped data commercially. See Apify's [blog post on web scraping legality](https://blog.apify.com/is-web-scraping-legal/) for more detail.

### FAQ

**Does this use the official OfferUp API?**
No — OfferUp does not offer a public listings API. This Actor reads the same GraphQL data the offerup.com website itself loads, structured into clean JSON.

**Why is `_details` sometimes missing?**
`_details` is only added when `fetchDetails` is on (search mode) or always (direct `listingIds` lookups) and the request succeeds. Check `_detailsStatus`: `not-found` means the listing no longer exists or was removed; `error` means the detail request failed and can be retried.

**What does `category` accept?**
An id in `parent.child` format from OfferUp's own category tree, e.g. `1.5` for Video games & Consoles. Pick one from the dropdown in the Input tab — see [Categories](#categories) above for the full list.

**Can I search outside the U.S.?**
No — OfferUp is a U.S.-only marketplace, and `zipCode` must be a valid U.S. ZIP code.

**Can I schedule this to run automatically?**
Yes. Use Apify's [Scheduler](https://docs.apify.com/platform/schedules) to run it daily, weekly, or at any interval, and combine it with [Apify's storage integrations](https://docs.apify.com/platform/integrations) (Google Sheets, Slack, Make, Zapier, webhooks) to get notified of new listings.

**I found a bug or missing field — where do I report it?**
Open an issue on the Actor's **Issues** tab in Apify Console, or use the [API](https://apify.com/parsebird/offerup-scraper/api) directly for programmatic access.

# Actor input Schema

## `query` (type: `string`):

Search keyword, e.g. "iphone 15", "sofa", "PS5". Leave empty for direct listingIds lookups, or to browse a category with no keyword.

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

U.S. ZIP code to search around. Not needed for direct listingIds lookups.

## `category` (type: `string`):

Restrict results to one OfferUp category.

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

Minimum price filter. 0 to disable.

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

Maximum price filter. 0 to disable.

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

Filter by item condition.

## `sortBy` (type: `string`):

Order results are returned in.

## `listingIds` (type: `array`):

Optional OfferUp listing IDs or item URLs. When present, search is skipped entirely and these listings are looked up directly (always with full details).

## `fetchDetails` (type: `boolean`):

For search results, perform one extra request per item to add condition, seller, photos, and category data as \_details. Direct listingIds lookups always include \_details regardless of this setting.

## `maxAge` (type: `integer`):

Drop ads older than this many hours. Only applies when Sort by is "Recent first" and Fetch details is on. 0 disables the filter.

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

Maximum number of items to scrape. 0 = unlimited.

## `proxy` (type: `object`):

OfferUp blocks datacenter IPs, so Residential proxy is used by default.

## Actor input object example

```json
{
  "query": "iphone",
  "zipCode": "10001",
  "category": "",
  "minPrice": 0,
  "maxPrice": 0,
  "conditions": [],
  "sortBy": "bestMatch",
  "listingIds": [],
  "fetchDetails": false,
  "maxAge": 0,
  "maxItems": 10,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

No description

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

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

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parsebird/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/05ckhy6uorLI4VSjT/builds/82NzbVutR7XJtVrYX/openapi.json
