OfferUp Scraper - Listings, Prices, Sellers & Location Data avatar

OfferUp Scraper - Listings, Prices, Sellers & Location Data

Pricing

from $1.00 / 1,000 listing results

Go to Apify Store
OfferUp Scraper - Listings, Prices, Sellers & Location Data

OfferUp Scraper - Listings, Prices, Sellers & Location Data

Scrape OfferUp listings by keyword, location and radius. Returns 40+ fields per item: price, condition, GPS, full photo set, category tree and rich seller profiles (rating, items sold, join date, verification). Search and URL modes, 5 sort orders, price and condition filters.

Pricing

from $1.00 / 1,000 listing results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

5

Total users

1

Monthly active users

5 days ago

Last modified

Share

OfferUp Scraper: Listings, Sellers, Prices & Category Data

OfferUp Scraper turns OfferUp, the US mobile-first local marketplace, into structured JSON. Search by keyword and location, or paste OfferUp search and item links, and get price, condition, geo coordinates, a full photo set, a three-level category tree and a complete seller profile per listing. Five native sort orders, price and condition filters, genuine price-drop detection, resumable runs and Incremental mode for recurring monitoring are all built in, ready to export to JSON, CSV or Excel, or pull through the API.

Why This Scraper?

  • Two ways in. Keyword search with location, radius, price and condition filters, or paste OfferUp search and item URLs directly.
  • 40+ fields when Fetch full details is on, including GPS coordinates, the full photo set, a three-level category tree and a complete seller profile (rating, items sold, join date, response time, verification).
  • Five native sort orders, plus price range and multi-condition filtering, applied at the source rather than filtered after the fact.
  • Genuine price-drop detection. Compares OfferUp's own recorded original price against the current price, not just a low asking price.
  • Walks the whole catalogue by default. Max pages defaults to unlimited: the run walks every result page per query/URL until Max items, OfferUp's own last page, or a repeat-page guard stops it.
  • Resumable, delta-friendly runs. Point Resume from a previous run at an earlier run or dataset to collect only what it doesn't already have, and Incremental mode tracks a recurring search itself and tags what changed.
  • Checkpointed automatically. A platform migration or a manual restart of an interrupted run picks up where it left off instead of re-collecting and re-charging listings already pushed.

Use Cases

  • Resale and arbitrage: monitor a category or keyword for genuine seller price drops to spot flip opportunities before they're gone.
  • Local market research: track pricing and condition mix for a product category across cities, ZIP codes or radii.
  • Recurring seller/category watch: schedule a search with Incremental mode on and review only new, updated or disappeared listings.
  • Lead generation for local services: pull listings in categories like furniture, electronics or vehicles alongside seller responsiveness and verification signals.
  • Marketplace data science: build a dataset of local pricing behavior over time using scheduled Incremental runs.

Data You Get

Sample shape: values are illustrative placeholders, not from a live listing.

FieldExample
listingId00000000-0000-0000-0000-000000000000
titleSample Listing Title
price799
priceText"$799"
isFirmPricefalse
conditionTextUsed
locationNameMiami, FL
urlhttps://offerup.com/item/detail/00000000-0000-0000-0000-000000000000
imageUrlhttps://images.offerup.com/000000000-254x250.jpg
flags["LOCAL_PICKUP"]
description (when Fetch full details is on)Full item description text.
latitude / longitude (when enabled)25.0000 / -80.0000
distanceMiles (when enabled)4.9
categoryL1Name / categoryL2Name / categoryL3Name (when enabled)Electronics & Media / Cell phones & Accessories / Smartphones
photos (when enabled)[{ "uuid": "0000", "url": "https://images.offerup.com/000-1440x1920.jpg" }]
postDate (when enabled)2026-01-01T00:00:00.000Z
originalPrice / isOnSpecial (when enabled)899 / true
savingsAmount / discountPercent (when enabled)100 / 11
localPickupEnabled / shippingEnabled (when enabled)true / false
sellerName (when enabled)Jane Seller
sellerRating / sellerReviewCount (when enabled)5 / 89
sellerItemsSold / sellerDateJoined (when enabled)564 / 2016-01-01T00:00:00Z
sellerResponseTime (when enabled)Responds in a few minutes
sellerIsTruYou (when enabled)true

The remaining fields cover secondary detail: conditionCode (numeric), quantity, photoCount, badges, discussionCount, isLocal, isMerchantItem, canShipToBuyer, shippingPrice, categoryL1Id/categoryL2Id/categoryL3Id, sellerId, sellerAvatar, sellerPrimaryBadge/sellerSecondaryBadge, sellerItemsPurchased, sellerPublicLocation, sellerIsAutosDealer, sellerIsBusinessAccount, sellerIsPremium, sellerWebsiteLink, and sellerPhone when OfferUp exposes it on the seller's profile. All of these "when enabled" fields need Fetch full details on (search mode) or come from the detail page automatically (a pasted item URL, or Price drops only). vehicleMiles (vehicle listings only) comes from the search-result card instead, so it's populated in search mode without needing Fetch full details, and is null on a pasted item URL. One more distinction worth knowing: a pasted single item URL always reads the detail page itself, so priceText, imageUrl, imageWidth, imageHeight and vehicleMiles come back null and flags comes back [], since those fields exist only on search-result cards, which a direct item-page fetch never produces.

How to Use

  1. Pick a mode: search (keyword + location) or url (paste OfferUp search or item links).
  2. Fill in the fields for that mode, and switch on Fetch full details if you need description, GPS, category and seller data.
  3. Set Max items to control run size and cost, then click Start.
  4. Download the dataset as JSON, CSV or Excel, or read it through the API.

Search a city with filters:

{
"mode": "search",
"searchQueries": ["iphone 14"],
"location": "Miami, FL",
"radiusMiles": 30,
"priceMin": 200,
"priceMax": 600,
"condition": ["USED", "REFURBISHED"],
"sortBy": "-price",
"maxItems": 50
}

Paste OfferUp URLs (a search page and an item page), with full details:

{
"mode": "url",
"urls": [
"https://offerup.com/search?q=sofa&radius=20",
"https://offerup.com/item/detail/00000000-0000-0000-0000-000000000000"
],
"fetchDetails": true,
"maxItems": 30
}

Genuine price drops only (detail fetch is auto-enabled for this):

{
"mode": "search",
"searchQueries": ["couch"],
"location": "Miami, FL",
"priceDropOnly": true,
"maxItems": 40
}

Recurring monitoring of the same search (Incremental mode), including EXPIRED detection:

{
"mode": "search",
"searchQueries": ["iphone 14"],
"location": "Miami, FL",
"incrementalMode": true,
"emitExpired": true,
"maxItems": 0
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/offerup-scraper").call(run_input={
"mode": "search",
"searchQueries": ["iphone 14"],
"location": "Miami, FL",
})
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
print(listing["title"], listing["price"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/offerup-scraper').call({
mode: 'search',
searchQueries: ['iphone 14'],
location: 'Miami, FL',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Max items is the real cap, Max pages is just a safety bound

maxItems is the single stopping point for a run (across every query/URL); set it to 0 for unlimited. maxPages (also 0 by default) is only an optional per-query ceiling on how many result pages get walked; it never raises the cap set by maxItems, it can only lower it. Leave maxPages at 0 to walk an entire query to its natural end.

Resume and recurring updates

  • Resume (resumeFromRunId) continues one interrupted or earlier run: paste its run or dataset id and this run skips every listing it already holds, so you don't pay twice. Progress is also checkpointed automatically during a run, so a platform migration or a restart of an interrupted run resumes exactly where it stopped.
  • Incremental mode (incrementalMode) is for scheduled runs over the same search. Each listing is classified NEW, UPDATED (with changedFields), or UNCHANGED (suppressed and not billed unless emitUnchanged is on) by default. A listing is only marked gone (and an EXPIRED row emitted) when emitExpired is on and the run completed a full, uncapped scan of the tracked search, never on a Resume, a Max items cap, or a run stopped by an error; REAPPEARED therefore requires a prior run like that, and never happens with emitExpired off. stateKey names or shares the stored baseline; leave it empty to auto-derive one from your search/URLs and filters. Five fields (discussionCount, sellerLastActive, sellerResponseTime, distanceMiles, isLocal) are excluded from change detection because they drift on their own between runs, independent of the listing itself; their real current values are still returned in every row. With Incremental mode off, output is exactly as before.

Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each listing, not the full JSON. Each item becomes one entry with a title and its key fields (price, condition, location, category, seller, URL) flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch (keyword + location) or url (paste OfferUp URLs); filter fields below are ignored in url mode.
searchQueriesarray["iphone"]Keywords to search (search mode). Each query is scraped independently.
locationstringno default (prefill: Miami, FL)City ('Miami, FL'), ZIP ('33101'), or raw 'lat,lon'. Empty searches near the connection's own location.
radiusMilesinteger50Radius in miles around the location (1 to 500).
priceMinintegerno defaultOnly return listings priced at or above this amount (USD).
priceMaxintegerno defaultOnly return listings priced at or below this amount (USD).
conditionarrayno defaultFilter by condition: NEW, OPEN_BOX, REFURBISHED, USED, BROKEN, OTHER. Leave empty for any condition.
priceDropOnlybooleanfalseKeep only listings with a genuine seller price drop (search mode). Auto-enables fetchDetails (and its per-item charge) even if left off, since price-drop data only lives on the detail page.
sortBystringbest_matchbest_match, -posted (newest), distance (closest), price (low to high), -price (high to low).
urlsarrayno default (prefill: sample search URL)OfferUp search or item detail URLs (url mode). Search URLs page forward automatically.
fetchDetailsbooleanfalseVisit each listing page for description, GPS, full photo set, category tree, fulfillment details and the complete seller profile. Adds a per-item charge. Always on when priceDropOnly is set.
maxItemsinteger20Stop after this many listings total (across all queries/URLs). 0 = unlimited.
maxPagesinteger0Optional safety cap on result pages walked per query/URL. 0 walks the whole catalogue until maxItems, the site's own last page, or a repeat-page guard stops it.
resumeFromRunIdstringno defaultID of a previous run (or dataset) of this actor. Listings already in that dataset are skipped, so this run returns only new ones.
incrementalModebooleanfalseFor a search you run on a schedule: tracks this search's own listings between runs and tags each row's changeType as NEW / UPDATED / UNCHANGED / REAPPEARED / EXPIRED.
stateKeystringno defaultOptional label naming the tracked Incremental mode baseline. Leave empty to auto-derive one from your search/URLs and filters.
emitUnchangedbooleanfalseIncremental mode: also return and bill listings with no change since the last run.
emitExpiredbooleanfalseIncremental mode: also return and bill a row for each previously tracked listing no longer found, only once a run completes a full scan (never on Resume, a Max items cap, or an error-stopped scan).
proxyobjectResidential USConnection settings. OfferUp geo-blocks non-US and datacenter connections; Residential proxy with country US is required for reliable results.
mcpConnectorsarrayno defaultOptional: send a summary of each listing to apps you authorized under Integrations.
notionParentPageUrlstringno defaultNotion connector only: page under which item pages are created.
maxNotifyListingsinteger50Cap on items exported to each connector per run. Does not affect the dataset.

Output Example

Sample shape: values are illustrative placeholders, not from a live listing.

{
"listingId": "00000000-0000-0000-0000-000000000000",
"url": "https://offerup.com/item/detail/00000000-0000-0000-0000-000000000000",
"title": "Sample Listing Title",
"price": 799,
"priceText": "$799",
"isFirmPrice": false,
"conditionText": "Used",
"conditionCode": 40,
"locationName": "Miami, FL",
"latitude": 25.0000,
"longitude": -80.0000,
"distanceMiles": 4.9,
"flags": ["LOCAL_PICKUP"],
"categoryL1Name": "Electronics & Media",
"categoryL2Name": "Cell phones & Accessories",
"categoryL3Name": "Smartphones",
"description": "Full item description text.",
"originalPrice": 899,
"isOnSpecial": true,
"savingsAmount": 100,
"discountPercent": 11,
"photos": [{ "uuid": "0000", "url": "https://images.offerup.com/000-1440x1920.jpg", "width": 1440, "height": 1920 }],
"photoCount": 1,
"postDate": "2026-01-01T00:00:00.000Z",
"localPickupEnabled": true,
"shippingEnabled": false,
"sellerName": "Jane Seller",
"sellerRating": 5,
"sellerReviewCount": 89,
"sellerItemsSold": 564,
"sellerDateJoined": "2016-01-01T00:00:00Z",
"sellerResponseTime": "Responds in a few minutes",
"sellerIsTruYou": true
}

With incrementalMode on, every row also carries changeType (NEW / UPDATED / UNCHANGED / REAPPEARED / EXPIRED), changedFields, firstSeenAt and lastSeenAt.

Plan Requirement

OfferUp only serves US connections and geo-blocks datacenter and non-US traffic. Use Apify Residential proxy with country US, which is the default proxy configuration for this actor, for reliable results.

FAQ

How much does it cost?

You pay per listing returned, plus a small per-item surcharge when Fetch full details (or Price drops only, which turns it on automatically) is active. The Pricing tab shows the current rates. Use Max items to cap the cost of any run.

This actor collects only publicly available marketplace listings. You are responsible for how you use the data: follow OfferUp's terms and the laws that apply to you, get legal advice before any commercial use, and never use seller names, locations or contact details in ways a seller didn't invite (for example unsolicited outreach).

Can I get only new or changed listings on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only NEW and UPDATED rows for that search by default; unchanged listings are skipped unless Emit unchanged listings is on, and turning on Emit expired listings also gets you EXPIRED rows once a run completes a full scan, plus REAPPEARED rows on a later run for a listing that was marked gone that way.

Why does pasting one item URL cost more than a plain search listing?

A pasted item URL can only be read from its own detail page, so that fetch always happens and is always billed the detail-enrichment surcharge, even though Fetch full details defaults to off for search mode. A search-mode listing only gets that fetch (and charge) when Fetch full details or Price drops only is turned on. A pasted item URL record also never carries priceText, imageUrl, the image dimension fields or vehicleMiles, and its flags comes back empty, because those only ever come from a search-result card, not the detail page.

Why did my run return an empty dataset instead of failing?

OfferUp only serves US residential connections; a datacenter or non-US connection is geo-blocked and returns 0 listings with a clear log warning and status message, so you can fix the connection and rerun rather than parse a generic error. The run does fail outright, with a clear message, when Resume from a previous run points at an id that can't be read, or when Incremental mode already has saved state for a search and you also set Resume from a previous run against it.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push listing summaries into Notion, Linear or Airtable.

🔗 Want more e-commerce data?

Pair this actor with these related scrapers from the same team:

🛒 Depop Scraper
From $1/1K. Scrape Depop search results, listings, shops, and reviews to JSON, CSV, or...
💼 Jobsite UK
From $1/1K. Collect UK job listings from Jobsite.co.uk at scale. Search by keyword...
💼 Reed.co.uk Scraper
Scrape Reed.co.uk jobs, companies, courses, and reviews. Search by keyword, location...
🏷️ ThredUp Scraper
Scrape ThredUp resale listings by keyword, department, brand, size, condition, price or...
🏠 Auction.com Scraper
From $1/1K. Extract foreclosure, REO, short-sale, and auction listings from Auction.com...
🛒 Mercari Japan Scraper
From $0.80/1K. Scrape Mercari Japan listings, sellers and reviews at scale. Extract...

👉 Browse all abotapi scrapers

💬 Support & custom scrapers

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • 🛠️ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.