--- name: dexscreener-pairs-scraper description: Read decentralised-exchange pool data from DexScreener via the Apify Actor arman-bd/dexscreener-pairs-scraper. Returns one record per pool with chain, DEX, pair address, both token objects, price in USD and in the quote token, pooled liquidity, 24-hour volume, 24-hour price change, buy and sell counts, FDV, market cap, pool creation time and the DexScreener link. Use when a task needs token discovery by symbol, liquidity depth comparison across chains and venues, volume or buy-sell anomaly screening, or scheduled monitoring of a fixed pool list. Not for historical candles, wallet holdings, order books, on-chain transaction detail or centralised-exchange markets. --- # DexScreener Pairs Scraper Apify Actor `arman-bd/dexscreener-pairs-scraper`. Give it token search terms, pool addresses, or both, get one dataset record per decentralised-exchange pool. No credentials and no proxy configuration are involved. ## When to use it - Discovery: what pools exist for a symbol or a contract address, across every chain. - Depth comparison: the same token on Ethereum, Base and Arbitrum, ranked by `liquidityUsd`, to see where the real market is. - Anomaly screening: `volume24h` divided by `liquidityUsd`, or `txns24hBuys` against `txns24hSells`, over a fixed watchlist. - Scheduled monitoring of pools you already know, passed as chain-qualified addresses so every run returns the same rows in the same shape. - Filtering out dust: one `minLiquidityUsd` threshold removes abandoned and honeypot pools before they reach your dataset. ## When not to use it - Historical price series or candles. Every record is a single point in time; build history by scheduling runs and keeping each `scrapedAt`. - Order books, individual swaps, wallet balances or holder lists. None are returned. - Centralised-exchange markets. This covers on-chain pools only. - Exhaustive enumeration of every pool for a token. A search returns up to 30 pools per query and there is no deeper paging, so treat it as a ranked sample. ## Call it ```js import { ApifyClient } from 'apify-client'; const client = new ApifyClient({ token: process.env.APIFY_TOKEN }); const run = await client.actor('arman-bd/dexscreener-pairs-scraper').call({ searchQueries: ['WETH', 'USDC'], chains: ['ethereum', 'solana', 'base'], minLiquidityUsd: 100000, maxResults: 100, }); const { items } = await client.dataset(run.defaultDatasetId).listItems(); const { value: summary } = await client .keyValueStore(run.defaultKeyValueStoreId) .getRecord('RUN_SUMMARY'); ``` One-shot over HTTP, when you want the rows back in the same request: ```bash curl -X POST "https://api.apify.com/v2/acts/arman-bd~dexscreener-pairs-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \ -H "Content-Type: application/json" \ -d '{"searchQueries":["WETH"],"chains":["ethereum","base"],"minLiquidityUsd":100000,"maxResults":50}' ``` The Actor is also exposed through Apify's MCP server as `arman-bd/dexscreener-pairs-scraper`, so an MCP-capable agent can call it with no extra wiring. ## Input At least one of `searchQueries` or `pairAddresses` must be non-empty, otherwise the run throws immediately. | Field | Type | Required | Default | Notes | |---|---|---|---|---| | `searchQueries` | string[] | one of the two | `[]` | Token symbols, token names, contract addresses or a `SOL/USDC` style pair. One request each, up to 30 pools back per query, spanning every chain. Blanks and duplicates are dropped. | | `pairAddresses` | string[] | one of the two | `[]` | Pool addresses. `ethereum:0x88e6…` (or `ethereum/0x88e6…`, or a pasted DexScreener pair URL) is a direct lookup. A bare address with no chain prefix is resolved through search instead. | | `chains` | string[] | no | `[]` | Keep only pools on these chain slugs, lowercased for you. Applied after the response arrives, since search is chain-agnostic. Empty means every chain. | | `minLiquidityUsd` | integer | no | `0` | Drop pools with less pooled liquidity than this. `50000` removes most abandoned and honeypot pools. `0` keeps everything. | | `maxResults` | integer | no | `500` | Total pools saved across every request. `0` means no cap. Maximum 100000. | **`searchQueries` is discovery, `pairAddresses` is monitoring.** Use search when you do not know the pools yet and want whatever the symbol turns up, then pin the winners as chain-qualified `pairAddresses` for every run after that. Combining both is fine, since results are de-duplicated on chain plus pool address. The two filters exist to make search output usable: a bare symbol can return pools on a dozen chains, most of them dust, and `chains` plus `minLiquidityUsd` is what cuts that down. Neither filter adds anything to chain-qualified address lookups, which are already exact. ## Output One record per pool, de-duplicated on `chainId` plus `pairAddress`. | Field | Type | Notes | |---|---|---| | `chainId` | string | Chain slug, for example `ethereum`, `solana`, `base`. | | `dexId` | string | The DEX the pool lives on, for example `uniswap`, `orca`. | | `pairAddress` | string | Pool contract address. Case is the source's, so compare case-insensitively. | | `pairSymbol` | string | `BASE/QUOTE` shorthand built from both token symbols. A missing symbol becomes `?`, so `?/SOL` is possible. | | `baseToken` | object \| null | `{ address, name, symbol }` for the base side. | | `quoteToken` | object \| null | `{ address, name, symbol }` for the quote side. | | `priceUsd` | number \| null | Base-token price in USD, cast from a decimal string so it sorts numerically. | | `priceNative` | number \| null | Base-token price denominated in the quote token. | | `liquidityUsd` | number \| null | Total pooled liquidity in USD. | | `volume24h` | number \| null | Traded volume over 24 hours, in USD. | | `priceChange24h` | number \| null | 24-hour price change in percent, so `2.02` means +2.02%. | | `txns24hBuys` | number \| null | Buy transactions over 24 hours. | | `txns24hSells` | number \| null | Sell transactions over 24 hours. | | `fdv` | number \| null | Fully diluted valuation in USD. | | `marketCap` | number \| null | Market cap in USD. Equal to `fdv` for tokens with no locked or unvested supply. | | `pairCreatedAt` | string \| null | Pool creation time, ISO 8601. `null` for roughly one pool in six. | | `url` | string | DexScreener page for the pool. | | `scrapedAt` | string | Run timestamp, ISO 8601 UTC. | A real record: ```json { "chainId": "solana", "dexId": "orca", "pairAddress": "HktfL7iwGKT5QHjywQkcDnZXScoh811k7akrMZJkCcEF", "pairSymbol": "WETH/SOL", "baseToken": { "address": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", "name": "Wrapped Ether (Wormhole)", "symbol": "WETH" }, "quoteToken": { "address": "So11111111111111111111111111111111111111112", "name": "Wrapped SOL", "symbol": "SOL" }, "priceUsd": 1907.6, "priceNative": 25.9643, "liquidityUsd": 3934516.33, "volume24h": 2885291.23, "priceChange24h": 2.02, "txns24hBuys": 4668, "txns24hSells": 3268, "fdv": 166094986, "marketCap": 166094986, "pairCreatedAt": "2022-11-28T02:25:41.000Z", "url": "https://dexscreener.com/solana/hktfl7iwgkt5qhjywqkcdnzxscoh811k7akrmzjkccef", "scrapedAt": "2026-08-06T11:37:40.563Z" } ``` ## RUN_SUMMARY Written to the run's key-value store under the key `RUN_SUMMARY`. **Read it.** It is where a partial run admits that it was partial. ```json { "requestsIssued": 4, "requestsFailed": 0, "failures": [], "pairsSaved": 10, "filters": { "searchQueries": ["WETH"], "pairAddresses": ["ethereum:0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"], "chains": ["ethereum", "solana", "base"], "minLiquidityUsd": 100000, "maxResults": 12 }, "finishedAt": "2026-08-06T11:37:46.409Z" } ``` `requestsIssued` is the number of requests the run *planned*, so when `maxResults` is reached early the remaining ones are never sent and the count overstates the work done. `pairsSaved` equal to `filters.maxResults` means the cap bound the run. Each entry in `failures` names the request in `source` and the reason in `error`; an address lookup that matched nothing appears there as `no pairs returned`, while a search that matched nothing does not appear at all, because an empty search is a valid answer. ## Behaviour to plan around - **An empty search is not a failure, an empty address lookup is.** A symbol nobody trades returns zero rows silently. A pool address that is not indexed on the chain you named is recorded in `failures`, which is how you tell a wrong chain prefix from a genuinely quiet token. - **A bare address is a search, not a lookup.** Without a chain prefix the address is resolved by search, which can return more than one match, or the wrong one. Prefix it whenever you know the chain. - **`maxResults` is consumed in request order:** searches first, then chain-qualified address batches, then bare addresses. Put the query you care most about first, or the cap will spend itself on the wrong one. - **`minLiquidityUsd` above zero also drops pools with no liquidity figure**, since a missing value cannot clear the threshold. Set it to `0` if you want those rows. - **A search returns up to 30 pools and does not page.** To go wider, pass a more specific query such as a contract address rather than expecting more depth. - **Address lookups are batched 30 at a time per chain**, so a 300-pool watchlist on one chain costs ten requests rather than 300. Group your watchlist by chain and it stays cheap. - **Requests are deliberately paced** with a fixed gap between them, so a run's wall time scales with the number of requests, not with the number of pools. - **The data carries a short cache upstream**, around 30 seconds. Polling faster than that returns the same numbers. - **`fdv` and `marketCap` matching is normal**, not duplication. Both are passed through unchanged. - **The run only throws when every request failed.** Any surviving request makes the run succeed with a non-empty `failures` list. ## Recipes **Discover pools for a new token.** Search wide, then cut the dust. ```json { "searchQueries": ["PEPE", "WIF", "BONK"], "minLiquidityUsd": 50000, "maxResults": 200 } ``` Sort by `liquidityUsd` and keep the top pool per `chainId` plus `dexId`. Those addresses become the watchlist for the next recipe. **Monitor a fixed watchlist.** Chain-qualified, so every lookup is exact and batched. ```json { "pairAddresses": [ "ethereum:0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640", "solana:HktfL7iwGKT5QHjywQkcDnZXScoh811k7akrMZJkCcEF" ] } ``` Schedule it and store each run. Alert when `volume24h` over `liquidityUsd` spikes, or when `txns24hBuys` runs far ahead of `txns24hSells`. **Track liquidity migration between chains.** One token, several chains, deep pools only. ```json { "searchQueries": ["USDC"], "chains": ["ethereum", "base", "arbitrum"], "minLiquidityUsd": 250000 } ``` Sum `liquidityUsd` per `chainId` and per `dexId`, then diff those totals between runs to watch depth move between venues.