DexScreener Token Scraper - DEX Pool Prices, Liquidity, Volume avatar

DexScreener Token Scraper - DEX Pool Prices, Liquidity, Volume

Pricing

$0.75 / 1,000 pools

Go to Apify Store
DexScreener Token Scraper - DEX Pool Prices, Liquidity, Volume

DexScreener Token Scraper - DEX Pool Prices, Liquidity, Volume

228 networks in one run, 95 fields per pool, 40 of 40 pools merged from both sources. DexScreener scraper plus GeckoTerminal API for crypto token price, liquidity, FDV, buys, sells and unique buyers. Trending and new pools, monitor mode for price moves. No API key.

Pricing

$0.75 / 1,000 pools

Rating

0.0

(0)

Developer

Snow Leo Data

Snow Leo Data

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

24 days ago

Last modified

Share

DexScreener & GeckoTerminal Scraper — DEX pools across 228 networks

Live prices, liquidity, volume, trade counts and unique wallet counts for decentralised-exchange token pools, assembled from two open APIs into one row: GeckoTerminal for the pool listing and DexScreener for the token profile. No API key, no proxy, no browser.

One run covers 228 networks, not one chain per run. A run that only wants to know what moved since the previous run is one checkbox away.

mode: trending -> the 50 hottest pools right now, every network
mode: pairs -> a fixed watchlist of pool addresses, priced
onlyChanged: true -> only the pools whose price actually moved

What exactly does this Actor return?

Every row is one pool (a trading pair on one DEX on one network), carrying 95 fields. A compact 23-field shape is available for agents and spreadsheets.

GroupFields
Identitypool_id, chain, network, network_name, dex_id, dex_name, pool_name, pool_address
Base tokenbase_token_address, base_token_name, base_token_symbol, base_token_decimals, base_token_image, base_token_coingecko_id
Quote tokenquote_token_address, quote_token_name, quote_token_symbol
Priceprice_usd, price_native, quote_token_price_usd
Price windowsprice_change_m5, price_change_m15, price_change_m30, price_change_h1, price_change_h6, price_change_h24
Volume windowsvolume_m5, volume_m15, volume_m30, volume_h1, volume_h6, volume_h24
Tradestxns_m5_buys … txns_h24_sells for six windows, plus txns_h24_total and buy_sell_ratio_h24
Walletsbuyers_m5, sellers_m5 … buyers_h24, sellers_h24 — unique addresses, six windows
Moneyliquidity_usd, liquidity_base, liquidity_quote, market_cap_usd, fdv_usd
Agepool_created_at, pool_age_hours
Linkswebsite_url, twitter_url, telegram_url, discord_url, github_url, medium_url, reddit_url, tiktok_url, youtube_url, instagram_url, facebook_url, plus the raw websites and socials lists
Presentationdescription, image_url, header_image_url, open_graph_url, labels, boosts_active
Change trackingchange_type, price_usd_previous, price_change_since_last_run_pct, liquidity_usd_previous, liquidity_change_since_last_run_pct, last_seen_at
Provenancesources, discovery_mode, scraped_at, dexscreener_url, geckoterminal_url

An empty field means neither source published the value. Nothing is inferred, nothing is filled in by a model.


Why merge two sources instead of scraping one?

Because each one is missing something the other has, and the gap is not cosmetic. Measured on a live trending run of 20 pools (python3 tools/measure_sources.py):

FieldGeckoTerminalDexScreenerFilled in a 40-pool run
price_change_m15, price_change_m30yesno38 of 40
buyers_h24 / sellers_h24 (unique wallets)yesno40 of 40
socials, websites, image_urlnoyes35 of 40
labels (v3, DLMM, …), boosts_activenoyes38 of 40
Pool listing with paginationyesnoboth used

In that same run 40 of 40 pools (100%) carried data from both sources, and the rows spanned four networks at once.

Unique wallets matter more than they look. By trade count a pool worked by one bot and a pool traded by a thousand people are indistinguishable. By buyers_h24 they are not. The minBuyers24h filter exists for exactly that.

Search shows the same effect from the other side. DexScreener's search endpoint returns at most 30 pairs no matter how many match. GeckoTerminal's pool search is paginated. Running both and merging them returned 58 pools for PEPE, 66 for USDC and 47 for BONK against the 30 DexScreener returns for each, whatever happens.


What are the real limits of these APIs, and how are they handled?

All four were found by live probing, and all four are handled in code rather than mentioned in passing. Reproduce every one with python3 tools/measure_sources.py.

GeckoTerminal stops at page 10. Page 11 of /networks/<net>/pools answers HTTP 401 — Your request exceeds the allowed max number for page (10). That is 20 pools per page × 10 pages = 200 pools per network and sort order, a hard ceiling. The Actor gets past it the only honest way: by fanning out across networks, across DEXes inside a network, and across both server-side sorts.

The network list ends with an error, not with silence. /networks?page=4 answers HTTP 400. A crawler that waits for an empty page retries a hard error three times per page and reports nothing. This Actor treats 400 and 401 as "stop here" and never retries them.

DexScreener silently truncates address lists at 30. Send 40 token addresses and you get HTTP 200 with exactly 30 records. The other ten vanish — no error, no warning, no count. Everything here is cut into batches of 30 before the request leaves, so a 40-address request returns records for all 40. Measured directly: raw call with 40 addresses → 30 rows; the same 40 through this Actor → more than 30.

Only two sort orders are open. h24_volume_usd_desc and h24_tx_count_desc are accepted; fdv_usd_desc, pool_created_at_desc and trending_score_desc all answer HTTP 400 with the list of allowed values. Sorting by market cap, FDV, price change, unique buyers or pool age therefore happens after collection, on what this run collected — the input field says so, and so does this sentence.

Rate limit. GeckoTerminal's open tier allows roughly 30 requests per minute per address, and answers HTTP 429 above it. The HTTP layer here holds a per-host brake shared by every thread, doubles the pause on each 429 and releases it gradually, so a burst does not turn into a wall of failures. DexScreener allows far more — 300 requests per minute on the pair endpoints.


How does the change-tracking mode work?

Turn on "Only what changed since the last run". The Actor keeps a record of every pool it has already delivered — the pool id, the price and the liquidity you were last charged for — in a named key-value store that survives runs (dexscreener-pool-state). On the next run every pool is tagged:

  • NEW — never delivered before;
  • UPDATED — delivered before and the price moved;
  • UNCHANGED — delivered before and the price did not move enough.

UNCHANGED rows are not written to the dataset, so a scheduled monitor stops paying for the same pools every hour.

DEX prices never stand still, so a bare change detector would call every pool updated on every run and save nothing. That is what "Report a pool only if its price moved by at least (%)" is for. Set it to 5 and you are told only about pools that moved 5% or more against the price you were last billed for. Each such row carries price_usd_previous, price_change_since_last_run_pct and last_seen_at, so the move is visible in the row rather than something you have to compute.

The memory holds 50 000 pools; when it overflows the oldest keys are dropped first. That record measures 2.9 MB against the platform's 9 MB per-record limit, which is checked by a test rather than assumed.

Order of operations matters here and is enforced by a test that deliberately kills a run mid-export: each batch is delivered first and only then marked as delivered. A run interrupted after 3 530 of 9 000 rows remembered exactly 3 530 — not 9 000, which would have made the missing 5 470 rows unreachable forever.


Which collection modes are there?

ModeWhat it doesNeeds
Trending poolsThe trending ranking, globally or per network, over a 5m / 1h / 6h / 24h windownothing
New poolsPools created most recently — the launch feednothing
Top pools of a networkHighest 24h volume or 24h transactionsa network
Pools of one DEXEverything on Raydium, Uniswap v3, PancakeSwap …a network + a DEX id
SearchName, symbol, token address or pool address, across both sourcesa search term
Given token addressesPrice a watchlist of contractsa network + addresses
Given pool addressesPrice a watchlist of exact pools — the cheapest monitora network + addresses
Newly listed token profilesDexScreener's freshest token cards, expanded into priced poolsnothing
Boosted tokensPaid promotions, latest or largest, expanded into priced poolsnothing

The two DexScreener feeds return tokens, not pools, and carry no price at all — only artwork, a description and links. This Actor expands each of them into real pools with real numbers in the same run, because a row without a single figure in it is not a result.


What can I filter on, and when is the filter applied?

Before anything is written to the dataset, so filtered-out pools are never billed. The run report lists how many each filter removed.

Numeric ranges: liquidity, market cap, fully diluted valuation, 24h volume, 24h transactions (both bounds), 24h buys, 24h sells, 24h unique buyers, 24h price change, pool age in hours and price in USD. Text filters: keep or drop by quote symbol, keep by base symbol, match a word in the pool or token name, and "only tokens that published a website or a social link".

One deliberate choice: a pool whose liquidity is missing does not pass a minimum-liquidity filter. A missing figure means the source did not say, not that the value is zero, and quietly letting it through would be a lie about the result set. The report counts those separately, as minLiquidityUsd:missing.


How is this different from the other DexScreener scrapers on Apify?

The strongest competing Actor scrapes the DexScreener website with a browser and rotating proxies, and asks for 2 048 MB of memory. This one reads the public APIs of both sources with the standard library, and asks for 1 024 MB. Line by line against its published input and output:

CapabilityStrongest competitorThis Actor
Chains per runone (chainName is required)228, several in one run
SourcesDexScreener onlyDexScreener and GeckoTerminal, merged
Fields per row15 base + optional extras95 (23 in compact mode)
Price windows4 (5m, 1h, 6h, 24h)6 (adds 15m and 30m)
Unique buyers / sellersmaker count onlybuyers and sellers separately, six windows
Socials and websitesextra paid page visit per tokenincluded in the base row
Incremental / change modenoneNEW / UPDATED / UNCHANGED with a price threshold
Previous price in the rownoprice_usd_previous, price_change_since_last_run_pct
Compact output for agentsnoyes
Drop empty fieldsnoyes
New-pool feedvia sortdedicated mode
Boosted / promoted tokensvia sortdedicated mode with boost counts
Token profile feednodedicated mode
Run report of what was filterednoyes, per filter, per reason
Requests a proxyyesno
Memory requested2 048 MB1 024 MB

Where the competitor is ahead, stated plainly. Two things it offers cannot be reproduced from the open APIs, and they are not reproduced here:

  • Top trader wallets per token. Its addTopTraders option reads a page the public API does not expose. This Actor has no equivalent and does not pretend to.
  • Launchpad bonding-curve progress (launchpadProgress for Solana launchpads). Same reason.

Three smaller gaps, also honest:

  • its rankBy offers sixteen server-side sort orders because the website accepts them, while the open API accepts two — the rest are applied here after collection, over the pools this run gathered;
  • its raw filterArgs escape hatch replays any DexScreener URL. The equivalent here is a mode plus filters, which covers the documented cases but not an arbitrary URL;
  • it reports a single makerCount. This Actor reports buyers_h24 and sellers_h24 separately, which is more information but not the same number — a wallet that both bought and sold is counted in each.

Every other input it has is matched: chain and DEX targeting, the 5m/1h/6h/24h window, sort direction, all the liquidity / market cap / FDV / age / volume / transaction / buys / sells / price-change bounds, the page range (fromPage plus pages per network), result caps, and the token-detail enrichment — which is on by default here rather than billed as an extra page visit.


How much does a run cost me in platform credits?

Requests, not pages, drive the cost, and the open GeckoTerminal tier answers roughly 30 requests per minute, so wide runs spend most of their time waiting rather than working. Measured on the platform with memory pinned to 1 024 MB:

RunRowsTimeCompute units
Trending, 1 page205.2 s0.00143
Trending, 3 pages, first ever run5092.0 s0.02556
Trending, 3 pages, later runs508.5 s0.00237
Token profiles234.8 s0.00133
Top pools, 4 networks × 10 pages800545.4 s0.15150

The gap between the first run and later ones is the network directory: naming 228 networks costs three requests to a rate-limited API, so it is cached in the same named store for seven days and only the first run pays for it.

Two practical consequences. Watchlist modes — Given pool addresses and Given token addresses — lean on DexScreener, which allows 300 requests per minute, and finish in seconds. Wide multi-network sweeps are slow by nature; set pagesPerNetwork to what you actually need.

A run that is about to hit its platform timeout stops collecting 45 seconds early on its own, delivers what it has and writes the report with stopped_by_timeout: true, instead of being killed with no report at all.

How do I run this on a schedule?

  1. Pick the mode. For a watchlist use Given pool addresses; for market-wide watching use Trending pools or New pools.
  2. Turn on Only what changed since the last run.
  3. Set Report a pool only if its price moved by at least (%) — 5 is a sensible start, 1 for tight watching, 0 to be told about every move.
  4. Schedule the Actor hourly or every 15 minutes.
  5. Read the dataset, or point a webhook at it. Every row tells you whether it is NEW or UPDATED and by how much it moved.

The run report in the key-value store (REPORT) records the mode, the networks used, how many pools were collected, how many the second source enriched, where the source cut the listing short and why, what each filter removed, and the NEW / UPDATED / UNCHANGED counts.


Frequently asked questions

Do I need a DexScreener or CoinGecko API key? No. Both endpoints used here are open and were verified with a plain HTTP request from the standard library — no key, no proxy, no browser.

Which networks can I use? Any of the 228 that GeckoTerminal lists, by its id: solana, eth, bsc, base, arbitrum, polygon_pos, avax, ton, sui-network, hyperevm and the rest. python3 tools/measure_sources.py prints the live count.

Why do some rows have fewer fields filled in? Because only one source knew that pool. Rows enriched by both list both in sources. On a measured trending run, 20 of 20 pools carried both sources; the DexScreener-only feeds (token profiles, boosted tokens) carry one.

Is market_cap_usd the same as fdv_usd? Not always, and they are kept apart on purpose. GeckoTerminal publishes them as two different figures; DexScreener frequently reports the same number for both. Whichever source filled the row, you get what that source actually said.

Why is price_usd a number and not a string? Both APIs publish the price as a string. A string in a numeric column breaks Excel, BigQuery and pandas alike, so every numeric field is converted in one place, and an unparseable value becomes null rather than "".

Why is pool_age_hours sometimes empty? Because the source did not publish a creation time for that pool. DexScreener's pairCreatedAt is in milliseconds; read as seconds it lands in the year 54 852 and makes the age negative. It is read as milliseconds here, which a test pins down.

Can I get the top traders of a token? No. That data is not in the open API. See the comparison table above.

Does the free Apify plan cover this? A default 50-pool run is small enough that the free platform credit covers many of them. Wide multi-network runs and long schedules will need a paid plan for platform usage, as with any Actor.

A run succeeded but the dataset is empty — is that a failure? Not necessarily, and the Actor always says which case it is. The run report carries empty_reason, and the log carries a warning naming it: nothing-changed (the change mode working as asked — every pool was already delivered at this price, so nothing was written and nothing was charged), filtered-out (your filters removed everything that was collected), or source-returned-nothing (the sources had no pools for that mode and network). The default input cannot produce an empty dataset — a test asserts it.

What happens if a run is interrupted? Delivered rows stay delivered and are remembered; undelivered rows are not marked and come back on the next run. This is tested by killing a run mid-export on purpose.

Can I limit what I spend? Yes. Set the Apify spending limit on the run; the Actor reads it at start and stops at that many rows instead of continuing to scrape for free.


Running the checks yourself

python3 tests/run_all.py # logic and lifecycle, no network
python3 tests/run_all.py --live # adds live source checks
python3 tools/measure_sources.py # every number in this README
python3 tools/verify_readme.py # README, input schema and code must agree

tools/verify_readme.py fails if a number in this file stops matching the code — field counts, source ceilings, batch sizes and the store card. It has been proven to fail by breaking it on purpose.


Data, sources and fair use

Data comes from the public endpoints of DexScreener and GeckoTerminal. Both are read at a polite rate with an identifying User-Agent, and neither is scraped through a browser or a proxy. Market data belongs to the venues that publish it; this Actor collects and normalises it, nothing more. Nothing here is investment advice, and no personal data of private individuals is collected — only public on-chain pool and token records.