DexScreener Pair Price & Liquidity Scraper
Pricing
from $1.40 / 1,000 pair scrapeds
DexScreener Pair Price & Liquidity Scraper
One row per DEX trading pair: price in USD and in the quote token, pool liquidity, 24h volume, price change and trade counts. Every row carries the timestamp the source itself put on the figures.
Pricing
from $1.40 / 1,000 pair scrapeds
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Search by symbol, paste a token address or paste a pool address, and get one row per trading pair: price in USD and in the quote token, how much liquidity the pool holds, 24-hour volume, price change over five minutes to 24 hours, and the buy and sell counts. Public market data, read straight from a public API. No wallet, no API key, no browser.
- Every row carries
snapshotAtandsourceAgeSeconds: when the source produced the figures, and how old they already were when the run read them. Market data with no timestamp on it is not worth much. - Ask for a specific pool and the address that comes back is checked against the address you asked for. A mismatch is dropped and not charged.
- A query that matches nothing is a normal answer, not an error. You get a row saying so, free, and the run still finishes clean.
- Token addresses are read in batches of thirty, so a hundred tokens is four requests rather than a hundred.
- One run can cover every chain the source indexes. Solana, Ethereum, Base, BSC, Arbitrum, all of them together.
Price
$1.40 per 1,000 pairs, plus a $0.0007 start fee per run.
This is a flat rate on every plan, free or paid. There are no volume tiers, no minimum spend, no subscription and no add-on fees. What you read here is what you pay on day one and on day four hundred.
| Pairs | Total cost |
|---|---|
| 30 | $0.0427 |
| 100 | $0.1407 |
| 500 | $0.7007 |
| 3,000 | $4.2007 |
One run can return up to 3,000 pairs, so every line in that table is a single run and a single start fee.
What is actually charged
- One
pair-scrapedevent per pair row written to the dataset. Nothing else is metered per row. - Free: the sample row an empty run returns, and every diagnostic row: a blocked target, a dead URL, a search that matched nothing. Those rows all carry
"charged": false. - Pools you filtered out with
minLiquidityUsdare dropped before they are written, so you are not billed for dust. - A pair that shows up twice in one run, when two search terms find the same pool, is written and charged once.
- A run that finds nothing costs the start fee and nothing more.
- Rows never leave the dataset without a charge, and are never charged without a row.
Input
{"searchTerms": ["SOL/USDC","PEPE"],"tokenAddresses": ["solana:So11111111111111111111111111111111111111112"],"pairAddresses": ["base:0x1131DB5977242a03eBeaD1aCD18F80A9A29e5922"],"minLiquidityUsd": 10000,"maxItems": 50}
| Field | What it does |
|---|---|
searchTerms | Free text: a symbol, a name, a pair like SOL/USDC, or a contract address. At most 30 pairs come back per term and there is no second page, so a broad symbol gives you the top of the list. Up to 100 terms. |
tokenAddresses | Token contracts as chain:address, or a pasted dexscreener.com URL. One row per token by default: the pool holding the most liquidity. Up to 100. |
pairAddresses | Pool addresses as chain:address, or a pasted pair URL. One row each, and the answer is checked against what you asked for. Up to 100. |
chainId | Only needed when you paste bare addresses with no chain in front of them. Anything written as chain:address ignores it. |
allPoolsPerToken | Off by default. Turn it on to get every pool listed for each token instead of just the deepest one. Useful for comparing the same token across venues, and it multiplies what you pay by the number of pools. |
minLiquidityUsd | Pools holding less than this are skipped before they are written. A popular symbol returns a lot of near-empty pools; 10000 is a reasonable floor if you only want real markets. |
maxItems | Total rows across everything you asked for. Default 50, hard ceiling 3,000. Keep it low while testing, because you pay per row. |
proxyUrls | Leave empty. Fill it in only if you want the traffic to leave through proxy servers you already pay for, as http://user:pass@host:port. |
Run it with empty input and you get one clearly labelled sample row, free, so you can see the output shape before you spend anything.
Output
One row per pair. A real row from a real run:
{"ok": true,"charged": true,"recordType": "pair","query": "SOL/USDC","chainId": "base","dexId": "aerodrome","baseSymbol": "SOL","quoteSymbol": "USDC","priceUsd": 108.62,"liquidityUsd": 626266.5,"volumeH24": 5661030.39,"priceChangeH24": -2.98,"marketCapUsd": 25578137,"snapshotAt": "2026-09-20T08:14:11.000Z","sourceAgeSeconds": 54,"pairUrl": "https://dexscreener.com/base/0x1131db5977242a03ebead1acd18f80a9a29e5922","pairAddress": "0x1131DB5977242a03eBeaD1aCD18F80A9A29e5922","baseAddress": "0x311935Cd80B76769bF2ecC9D8Ab7635b2139cf82","quoteAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913","priceNative": 108.6201,"liquidityBase": 2717.3217,"liquidityQuote": 331110,"fdvUsd": 25578137,"volumeH6": 1899577.03,"volumeH1": 253048.23,"volumeM5": 18637.38,"priceChangeH6": -1.62,"priceChangeH1": -0.1,"priceChangeM5": 0.12,"buysH24": 3688,"sellsH24": 3785,"labels": [],"pairCreatedAt": "2024-08-21T17:22:29.000Z","retrievedAt": "2026-09-20T08:15:05.125Z"}
Field notes
snapshotAt: when the source produced these figures, worked out from what it told us about its own cache. This is the timestamp to trust, not the one on your clock.sourceAgeSeconds: how many seconds old the figures already were when the run read them. It sits between 0 and about 60. If that matters for what you are doing, read this field before you use the price.retrievedAt: when the run read it. Always later thansnapshotAt, and it is the less useful of the two.priceUsd: the source publishes this as text and it is parsed to a number here. Sub-cent tokens come back in full precision, so expect values like0.00000412.priceNative: price in units of the quote token. For a SOL/USDC pool that is the price in USDC.liquidityUsd: total value sitting in the pool. It is the field that tells you whether a price is real or whether ten dollars of trade would move it.marketCapUsd: the source's own figure, based on circulating supply where it knows it. It is often equal tofdvUsd, and it is null when the source has no supply figure.labels: venue-specific tags the source attaches, like a fee tier or a pool version. Empty for most pairs.pairCreatedAt: when the pool was deployed. Missing on older pairs the source never recorded a creation time for.query: the term or address that produced this row, so you can join the output back to your input.
Every real row carries "charged": true. Sample rows carry "_sample": true and diagnostic rows carry "_diagnostic": true with an errorCode you can filter on, and neither is ever billed.
How it works
- It reads the public market-data API the site publishes, using the documented search, token and pair routes. There is no page rendering, no login and no key.
- The API answers from a cache with a one-minute lifetime and says how old each answer is. That number is carried onto every row rather than thrown away, so you always know how fresh a price is.
- Requests are paced under the published rate limit, and a throttle is retried automatically rather than by hammering the same endpoint.
- Token addresses are grouped by chain and sent thirty at a time, which is the batch size the API documents.
- Every call has an explicit timeout. A server hiccup is retried with a growing, jittered pause; a bad chain or a dead address is not retried at all, because no amount of asking again will change the answer.
What people use it for
- Watching the pools for one token across several chains and venues at once, to see where it actually trades and where the price differs.
- Keeping a spreadsheet or database of current prices and pool depth for a basket of tokens, refreshed on a schedule.
- Checking whether a token that looks liquid on one chart has any real depth behind it.
liquidityUsdandvolumeH24next to each other answer that in one glance. - Feeding a dashboard or a bot with a flat, typed table instead of parsing a rendered page.
- Research on new pools:
pairCreatedAt, first volume and starting liquidity, pulled for a list of addresses in one run.
What this is not
This returns market data. It does not tell you what to buy, hold or sell, it makes no prediction, and it scores nothing. There is no signal, no rating and no recommendation anywhere in the output. Just the numbers the source published, and the time it published them.
It is also not a live feed. The source answers from a cache that lives for about a minute, so a price can already be up to sixty seconds old when it reaches you. That is why every row carries sourceAgeSeconds. If your use needs sub-second prices, this is the wrong tool and you want a venue websocket instead.
Reading the output
Every run writes three kinds of row, and they are easy to tell apart:
- Real rows carry
"charged": trueand"recordType": "pair". One billed event each. - The sample row carries
"_sample": trueand"charged": false. There is exactly one, it only appears when you ran with nothing filled in, and it exists so you can look at the shape before spending anything. - Diagnostic rows carry
"_diagnostic": true,"charged": falseand anerrorCodeyou can switch on.
errorCode | What happened |
|---|---|
NO_RESULTS | The API answered and matched nothing. A real answer, not a failure. |
NOT_FOUND | No pool exists at that address on that chain. |
WRONG_TARGET | The API returned something other than what was asked for, so the row was dropped. |
RESULT_TRUNCATED | The API returned its maximum of 30 and there are more it will not hand over. Your answer is the top of the list, not all of it. |
BAD_INPUT | The chain or address was not one the API recognises. |
RATE_LIMITED | The API throttled the run. Split the work across two runs. |
TIME_BUDGET | The run ran out of time before reaching that target. |
NOTHING_MATCHED | 25 targets in a row came back empty with no rows anywhere, so the run stopped rather than reading the rest. Almost always the wrong chain. It says how many targets went unread. |
If you only want the data, filter on charged == true. The count of those rows always equals the number of events you were billed for, so the dataset is its own invoice.
Address formats it accepts
All four of these mean the same thing, so paste whichever you already have:
solana:So11111111111111111111111111111111111111112solana/So11111111111111111111111111111111111111112https://dexscreener.com/solana/So11111111111111111111111111111111111111112So11111111111111111111111111111111111111112 (with chainId set to "solana")
Chain names are the source's own: solana, ethereum, base, bsc, arbitrum, polygon, avalanche, pulsechain and so on. Get the chain wrong and you get a BAD_INPUT or NOT_FOUND row, free. The same address usually exists on several chains, so this is the easiest thing to get wrong.
Limitations
- Prices come from a cache with a one-minute life.
sourceAgeSecondstells you how old each one is; it is normally under a minute and it is never zero-latency. This is not a tick feed. - Any single request returns at most 30 pairs and there is no pagination.
limit,pageandoffsetare all ignored by the API. A search for a popular symbol gives you the top 30 and aRESULT_TRUNCATEDrow telling you so. - Search is fuzzy by design. A term can return pairs you did not have in mind, so every row carries the
querythat produced it. Only the token and pair routes check the answer against the request. - The API allows roughly 300 requests a minute per address and the limit is shared across all of its routes. The run paces itself under that, but a very large job is better split across runs.
- No historical data. There are no candles, no OHLC and no time series. Only the current snapshot, plus the change percentages the source publishes for 5 minutes, 1 hour, 6 hours and 24 hours.
- No holder lists, no wallet activity, no individual trades and no top-trader tables.
- Coverage is whatever the source lists. A brand-new pool can take a few minutes to appear, and a chain the source does not index is not reachable here.
marketCapUsd,fdvUsdandpairCreatedAtare null wherever the source has no figure. Nothing is estimated to fill a gap.- Token names and symbols are written by whoever deployed the contract. Two different tokens can share a symbol, which is exactly why the address fields are in every row.
- If 25 targets in a row come back empty and the run has produced no rows at all, it stops and says so instead of reading the remaining ones. That is nearly always the wrong chain on a list of addresses, and the run tells you how many it skipped.
- Hard ceilings: 3,000 rows and 100 targets per run. For more than that, split the work.
Questions
How fresh is the price?
Between zero and about sixty seconds old. The source serves from a one-minute cache and tells us how long each answer has been sitting there, and that number lands on the row as sourceAgeSeconds, with snapshotAt giving the moment the figures were actually true. Nothing here is dressed up as a live tick.
What happens if my search matches nothing?
You get one free row with errorCode: "NO_RESULTS" and the run carries on to your other targets. Finding nothing is a real answer and it is never charged. It is deliberately a different code from NOT_FOUND and BAD_INPUT, so you can tell "there is nothing there" apart from "I could not look".
Can I get every pool for a token instead of just the biggest?
Yes. Turn on allPoolsPerToken. You will get up to 30 pools per token instead of one, and you pay for each of them, so it is off by default.
Which chains work?
All of the ones the source indexes, in the same run. Write the chain in front of the address and you can mix Solana, Ethereum, Base and anything else in a single input list.
Is this financial advice?
No. It returns published market data and nothing else. No score, no rating, no recommendation, no prediction. What you do with the numbers is yours.
Will the run fail if something goes wrong?
No. A throttle, a dead address or a chain the API does not know produces a free row explaining what happened, and the run still finishes as succeeded. A failed run would still bill you the start fee, which would mean paying to be told something went wrong.
Can I run this on a schedule?
Yes. Nothing is held between runs, so the same input on a schedule is safe. Join on pairAddress to diff one run against the last.
How do I get exactly the rows I paid for?
Filter the dataset on "charged": true. Sample and diagnostic rows are always false, and the number of charged rows always equals the number of billed events.