1. 2scraper
  2. Finance & markets
  3. OpenSea
Open source · MITRuns with no key, proxy or account

OpenSea Scraper

NFT items, collection rankings and activity feeds from opensea.io, with no account, key or proxy.

  • Playwright
  • Selenium
  • Puppeteer
  • Scraping Browser API
  • JSON
  • CSV
opensea-scraper
# Collection items
$ python3 playwright_scraper.py --collection boredapeyachtclub --pages 3
✓ 25 sample rows · 34 columns in sample_output.json
3modes: items, collections, activity
350items in a 4-page run, complete (Sep 2026)
4networks returning identical rows (Sep 2026)
0accounts, keys or proxies needed
Available OpenSea scrapers

What the OpenSea scraper collects

Scrapes opensea.io in three modes: a collection's items with listing prices, best offers, last sales, traits, rarity ranks and owners; OpenSea's own collection ranking with floors, volume and supply; and a collection's activity feed of sales, listings, offers, transfers and mints. Page 1 is read from the state OpenSea inlines into the page, later pages from the site's own GraphQL endpoint called from inside the open page. Output is JSON or CSV.

Collection items

Input: A collection slug

One row per NFT: listing price in tokens and USD, best offer, last sale, chain, token id, rarity rank, traits and owner. Cheapest first by default.

Collection ranking

Input: A ranking timeframe

One row per collection from OpenSea's own ranking, with floor price, volume and supply for the chosen window.

Activity feed

Input: A collection slug and an event type

One row per event: sales, listings, offers, transfers or mints, priced and timestamped.

Single item

Input: An item URL

One row for one NFT with the same columns as the items mode.

Quick start

From zero to OpenSea data in 3 steps

  1. Install

    Clone the repository and install one browser engine. Python 3.9+.

    $ git clone https://github.com/2scraper/opensea-scraper
    $ cd opensea-scraper
    $ python3 -m venv .venv && source .venv/bin/activate
    $ pip install -r requirements.txt -r requirements-playwright.txt
    $ playwright install chromium
  2. Run a scraper

    Pick what you need and run it. Every flag is documented in the README.

    $ python3 playwright_scraper.py --collection boredapeyachtclub --pages 3
  3. Get structured data

    Rows land in JSON or CSV (--format), with a .meta.json sidecar recording status, pages fetched and why the run stopped.

Output

OpenSea data fields

34 columns per row in a predictable schema. The most useful ones:

FieldWhat it holds
skuchain/contract/token_id, or chain/mint on Solana
titleItem name
priceListing price as a token amount
currencyThe token the price is in, e.g. ETH
price_usdOpenSea's own USD conversion
best_offerBest offer amount
last_saleLast sale amount
last_sale_currencyToken the last sale settled in; null when OpenSea does not say
last_sale_atTime of the last sale
listing_marketplaceWhere the listing lives (OpenSea aggregates others, e.g. blur)
chainBlockchain
contract_addressContract, or the mint on Solana
token_idToken id; null on Solana
rarity_rankRarity rank within the collection
traitsList of trait: value pairs
owner_addressOwner wallet address
[
  {
    "source": "opensea.io",
    "scraped_at": "2026-09-17T08:22:50.208548+00:00",
    "url": "https://opensea.io/item/ethereum/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d/1774",
    "sku": "ethereum/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d/1774",
    "title": "#1774",
    "price": 6.8497666,
    "currency": "ETH",
    "price_usd": 16707.950690719998,
    "best_offer": 6.51,
    "best_offer_currency": "WETH",
    "best_offer_usd": 15886.2228,
    "last_sale": 6.75,
    "last_sale_currency": "WETH",
    "last_sale_usd": 16926.57,
    "last_sale_at": "2026-09-06T21:56:59.000Z",
    "listing_marketplace": "blur",
    "listing_expires_at": "2026-09-17T19:37:25.000Z",
    "listing_quantity": "1",
    "chain": "ethereum",
    "contract_address": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d",
    "token_id": "1774",
    "token_standard": "ERC721",
    "collection_slug": "boredapeyachtclub",
    "collection_name": "Bored Ape Yacht Club",
    "rarity_rank": 2412,
    "traits": [
      "Background: Orange",
      "Clothes: Toga",
      "Earring: Silver Hoop",
      "… 4 more"
    ],
    "image_url": "https://i2c.seadn.io/base/0x7e72abdf47bd21bf0ed6ea8cb8dad60579f3fb50/58d5cc3fc342034b39…",
    "owner_address": "0xff53e1da7b67ae676d7742f858aab5bd4bc937f6",
    "owner_username": "Check_my-bio",
    "is_delisted": false,
    "is_compromised": false,
    "data_source": "ssr",
    "page": 1,
    "position": 1
  },
  {
    "source": "opensea.io",
    "scraped_at": "2026-09-17T08:22:50.208587+00:00",
    "url": "https://opensea.io/item/ethereum/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d/1474",
    "sku": "ethereum/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d/1474",
    "title": "#1474",
    "price": 6.84979,
    "currency": "ETH",
    "price_usd": 16708.007768,
    "best_offer": 6.49,
    "best_offer_currency": "WETH",
    "best_offer_usd": 15837.4172,
    "last_sale": 6.5,
    "last_sale_currency": "ETH",
    "last_sale_usd": 16276.52,
    "last_sale_at": "2026-09-14T14:57:23.000Z",
    "listing_marketplace": "blur",
    "listing_expires_at": "2026-09-17T10:42:08.000Z",
    "listing_quantity": "1",
    "chain": "ethereum",
    "contract_address": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d",
    "token_id": "1474",
    "token_standard": "ERC721",
    "collection_slug": "boredapeyachtclub",
    "collection_name": "Bored Ape Yacht Club",
    "rarity_rank": 7044,
    "traits": [
      "Background: Blue",
      "Clothes: Tanktop",
      "Eyes: Bloodshot",
      "… 3 more"
    ],
    "image_url": "https://i2c.seadn.io/base/0x7e72abdf47bd21bf0ed6ea8cb8dad60579f3fb50/73cfbf303c84af133f…",
    "owner_address": "0xba40917080746543702c90a75d2fd36c7f333395",
    "owner_username": "Tritonwarmer",
    "is_delisted": false,
    "is_compromised": false,
    "data_source": "ssr",
    "page": 1,
    "position": 2
  }
]

First 2 of 25 rows from a real run — sample_output.json. Long values shortened here.

Built for OpenSea

Handles what breaks naive OpenSea scrapers

Cursor pagination from inside the page

OpenSea publishes no address for page 2. The engines call the site's own GraphQL endpoint from the open page, with the same cookies, TLS session and exit, and parse it with the same code as page 1.

The end of the order book is detected

Under the default price sort the cursor goes null where listed items end. The run stops there as complete, and the sidecar records OpenSea's own listed and total item counts beside the rows read.

Solana items done right

On Solana the mint is the token. token_id is null and contract_address carries the mint, instead of writing an address the site does not serve on every row.

Sort is treated as the sample

--sort decides which rows you get, not just their order. The sort is recorded, and diff_runs.py refuses to compare runs taken under different sorts.

Everything built in

Scraping infrastructure included

The same tested core runs every 2scraper repository, so the hard parts work the same way on every site.

CAPTCHA handling

Detects the challenge a page really serves and, with a 2Captcha key, solves it only when it blocks the data — a capped number of solves per page.

Proxy rotation

Single proxy or a pool from a file, rotated on blocks with a fresh browser per exit. Credentials stay out of argv and logs.

Fingerprints

Optional complete device identity from the 2Captcha Fingerprint API — user agent, client hints, locale and timezone that agree with each other.

Scraping Browser API

Point --cdp-endpoint at a managed Chromium with its own exit country — no browser infrastructure to run yourself.

Honest run metadata

Every run writes a .meta.json sidecar and distinct exit codes: complete, blocked, empty and partial are never confused, and a failed run never overwrites good data.

Diff two runs

diff_runs.py compares two complete OpenSea snapshots by id — new, removed and changed rows for monitoring.

Use cases

What teams do with OpenSea data

Floor and order-book tracking

Walk a collection cheapest-first to the end of its listed items and watch the floor move run to run.

Rarity versus price analysis

Join listing prices with rarity ranks and traits to find mispriced items.

Sales history

Collect a collection's sales feed with prices and timestamps for volume and price-trend analysis.

Collection screening

Pull OpenSea's ranking by timeframe with floors, volume and supply to compare collections.

Access & pricing

Free to run. Pay only for what the site requires.

Runs with no key, proxy or account

No account, key or proxy: every mode returned HTTP 200 from a datacentre address, and a daily canary runs the full scrape from a GitHub runner with no secrets (measured Sep 2026). Avoid the Python-urllib user agent, which Cloudflare refuses. The paid products buy volume from many addresses, a browser you do not run (Scraping Browser API, measured identical rows), a one-request Scraper API path, and a solver for the day Cloudflare issues a managed challenge; none was met in testing.

Optional 2Captcha services — captcha solving, the Scraping Browser API, residential proxies and fingerprints — work behind one key.

Good to know

  • --concurrency above 1 is refused because pagination is cursor-based.
  • The Scraper API path reads one page only.
  • Most of a collection has no listing price; null price is correct for unlisted items.

2scraper vs. hosted scraper APIs

2scraperTypical hosted API
CodeOpen source, MIT — read and patch itClosed
CostFree; optional services billed only when usedSubscription or per request / per result
Runs onYour machine, server or CIThe vendor's infrastructure
OutputJSON/CSV files + run metadataAPI responses
When the site changesFix it yourself or open an issue / PRWait for the vendor
FAQ

OpenSea scraper FAQ

Do I need an OpenSea account or API key?

No. The scraper reads the public pages and the site's own front-end endpoint anonymously.

Why did my run stop before the collection's total?

Under the default --sort price the walk ends at the last listed item, which is complete for the order book. Use --sort created to walk the whole collection.

Can I run pages in parallel?

No. Pages are cursor-linked, so page 5's request does not exist until page 4 is read, and --concurrency above 1 is refused. Run several collections in separate processes instead.

Are prices in USD?

price is a token amount with the token named in currency; price_usd is OpenSea's own conversion, which moves with the market.

What output formats are there?

JSON or CSV, one row class per mode, plus a .meta.json sidecar with status, stop_reason, the sort used and the collection's own totals.

Is scraping OpenSea legal?

It reads public pages at a polite rate. Follow the site's terms and the law where you operate.