# DexScreener Token Scraper - DEX Pool Prices, Liquidity, Volume (`snow_leo_data/dexscreener-scraper`) Actor

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.

- **URL**: https://apify.com/snow_leo_data/dexscreener-scraper.md
- **Developed by:** [Snow Leo Data](https://apify.com/snow_leo_data) (community)
- **Categories:** Integrations, MCP servers, Developer tools
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.75 / 1,000 pools

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## 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.

| Group | Fields |
|---|---|
| Identity | `pool_id`, `chain`, `network`, `network_name`, `dex_id`, `dex_name`, `pool_name`, `pool_address` |
| Base token | `base_token_address`, `base_token_name`, `base_token_symbol`, `base_token_decimals`, `base_token_image`, `base_token_coingecko_id` |
| Quote token | `quote_token_address`, `quote_token_name`, `quote_token_symbol` |
| Price | `price_usd`, `price_native`, `quote_token_price_usd` |
| Price windows | `price_change_m5`, `price_change_m15`, `price_change_m30`, `price_change_h1`, `price_change_h6`, `price_change_h24` |
| Volume windows | `volume_m5`, `volume_m15`, `volume_m30`, `volume_h1`, `volume_h6`, `volume_h24` |
| Trades | `txns_m5_buys` … `txns_h24_sells` for six windows, plus `txns_h24_total` and `buy_sell_ratio_h24` |
| Wallets | `buyers_m5`, `sellers_m5` … `buyers_h24`, `sellers_h24` — unique addresses, six windows |
| Money | `liquidity_usd`, `liquidity_base`, `liquidity_quote`, `market_cap_usd`, `fdv_usd` |
| Age | `pool_created_at`, `pool_age_hours` |
| Links | `website_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 |
| Presentation | `description`, `image_url`, `header_image_url`, `open_graph_url`, `labels`, `boosts_active` |
| Change tracking | `change_type`, `price_usd_previous`, `price_change_since_last_run_pct`, `liquidity_usd_previous`, `liquidity_change_since_last_run_pct`, `last_seen_at` |
| Provenance | `sources`, `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`):

| Field | GeckoTerminal | DexScreener | Filled in a 40-pool run |
|---|---|---|---|
| `price_change_m15`, `price_change_m30` | yes | **no** | 38 of 40 |
| `buyers_h24` / `sellers_h24` (unique wallets) | yes | **no** | **40 of 40** |
| `socials`, `websites`, `image_url` | **no** | yes | 35 of 40 |
| `labels` (`v3`, `DLMM`, …), `boosts_active` | **no** | yes | 38 of 40 |
| Pool listing with pagination | yes | **no** | both 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?

| Mode | What it does | Needs |
|---|---|---|
| **Trending pools** | The trending ranking, globally or per network, over a 5m / 1h / 6h / 24h window | nothing |
| **New pools** | Pools created most recently — the launch feed | nothing |
| **Top pools of a network** | Highest 24h volume or 24h transactions | a network |
| **Pools of one DEX** | Everything on Raydium, Uniswap v3, PancakeSwap … | a network + a DEX id |
| **Search** | Name, symbol, token address or pool address, across both sources | a search term |
| **Given token addresses** | Price a watchlist of contracts | a network + addresses |
| **Given pool addresses** | Price a watchlist of exact pools — the cheapest monitor | a network + addresses |
| **Newly listed token profiles** | DexScreener's freshest token cards, expanded into priced pools | nothing |
| **Boosted tokens** | Paid promotions, latest or largest, expanded into priced pools | nothing |

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:

| Capability | Strongest competitor | This Actor |
|---|---|---|
| Chains per run | **one** (`chainName` is required) | **228**, several in one run |
| Sources | DexScreener only | DexScreener **and** GeckoTerminal, merged |
| Fields per row | 15 base + optional extras | **95** (23 in compact mode) |
| Price windows | 4 (5m, 1h, 6h, 24h) | **6** (adds 15m and 30m) |
| Unique buyers / sellers | maker count only | **buyers and sellers separately, six windows** |
| Socials and websites | extra paid page visit per token | included in the base row |
| Incremental / change mode | **none** | NEW / UPDATED / UNCHANGED with a price threshold |
| Previous price in the row | no | `price_usd_previous`, `price_change_since_last_run_pct` |
| Compact output for agents | no | yes |
| Drop empty fields | no | yes |
| New-pool feed | via sort | dedicated mode |
| Boosted / promoted tokens | via sort | dedicated mode with boost counts |
| Token profile feed | no | dedicated mode |
| Run report of what was filtered | no | yes, per filter, per reason |
| Requests a proxy | yes | no |
| Memory requested | 2 048 MB | 1 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:

| Run | Rows | Time | Compute units |
|---|---:|---:|---:|
| Trending, 1 page | 20 | 5.2 s | 0.00143 |
| Trending, 3 pages, first ever run | 50 | 92.0 s | 0.02556 |
| Trending, 3 pages, later runs | 50 | **8.5 s** | 0.00237 |
| Token profiles | 23 | 4.8 s | 0.00133 |
| Top pools, 4 networks × 10 pages | **800** | 545.4 s | 0.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

```bash
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](https://docs.dexscreener.com/api/reference) and
[GeckoTerminal](https://www.geckoterminal.com/dex-api). 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.

# Actor input Schema

## `mode` (type: `string`):

Trending, brand-new, top-by-volume, one DEX, a search term, or an explicit list of tokens or pools.

## `networks` (type: `array`):

GeckoTerminal network ids — `solana`, `eth`, `bsc`, `base`, `arbitrum`, `polygon_pos`, `avax`, `ton`, `sui-network`, `hyperevm`. 228 are available; leave empty for the cross-network trending and new-pool feeds. Required for Top pools, Pools of one DEX, Given token addresses and Given pool addresses.

## `query` (type: `string`):

Token name, symbol, token address or pool address. Used by the Search mode, which queries both sources and merges the results.

## `dexes` (type: `array`):

Only for the "Pools of one DEX" mode — `raydium`, `uniswap_v3`, `pancakeswap-v3-bsc`, `aerodrome-base`. One network must be set as well.

## `duration` (type: `string`):

Which window the trending ranking uses.

## `sort` (type: `string`):

The open GeckoTerminal endpoint accepts exactly these two. Everything else is sorted on our side after collection — see "Sort collected pools by".

## `pagesPerNetwork` (type: `integer`):

20 pools per page. The source refuses page 11 with HTTP 401, so 10 pages (200 pools) per network and sort is the hard ceiling.

## `fromPage` (type: `integer`):

First page to read, 1-10. Use it to continue where a previous run stopped instead of collecting the same pools again.

## `tokenAddresses` (type: `array`):

Contract addresses to price. Cut into batches of 30 for you — a longer list sent straight to DexScreener comes back truncated with no error.

## `pairAddresses` (type: `array`):

Exact pool addresses to watch. The cheapest way to run a price monitor on a fixed list.

## `boostsKind` (type: `string`):

Latest promotions or the biggest ones.

## `enrich` (type: `boolean`):

On: every pool is looked up in the other source too, adding websites, socials, images, pool labels and boost counts (DexScreener) or the m15/m30 windows and unique buyer/seller counts (GeckoTerminal). Off: fewer requests, fewer fields.

## `maxItems` (type: `integer`):

0 means no limit. Left empty, a run stops at 100 pools so a trial cannot turn into a large bill.

## `onlyChanged` (type: `boolean`):

Remembers every pool it has already delivered, in a named key-value store that survives runs, and tags each row NEW, UPDATED or UNCHANGED. Unchanged pools are not written to the dataset, so a scheduled monitor stops paying for the same pools every hour.

## `priceChangeThresholdPercent` (type: `integer`):

DEX prices never stand still, so without a threshold every pool counts as updated. Set 5 to be told only about pools that moved 5% or more since the price you were last charged for.

## `emitUnchanged` (type: `boolean`):

Writes UNCHANGED rows too. You pay for them, so it is off by default.

## `minLiquidityUsd` (type: `integer`):

Pools with no liquidity figure at all are dropped by this filter rather than passed through.

## `maxLiquidityUsd` (type: `integer`):

Upper bound on pool liquidity in USD. Leave empty for no upper bound.

## `minMarketCapUsd` (type: `integer`):

Lower bound on market capitalisation in USD.

## `maxMarketCapUsd` (type: `integer`):

Upper bound on market capitalisation in USD.

## `minFdvUsd` (type: `integer`):

Lower bound on fully diluted valuation in USD.

## `maxFdvUsd` (type: `integer`):

Upper bound on fully diluted valuation in USD.

## `minVolume24hUsd` (type: `integer`):

Lower bound on 24-hour trading volume in USD.

## `maxVolume24hUsd` (type: `integer`):

Upper bound on 24-hour trading volume in USD.

## `minTxns24h` (type: `integer`):

Lower bound on buys plus sells over 24 hours.

## `maxTxns24h` (type: `integer`):

Upper bound on buys plus sells over 24 hours.

## `minBuys24h` (type: `integer`):

Lower bound on buy transactions over 24 hours.

## `minSells24h` (type: `integer`):

Lower bound on sell transactions over 24 hours.

## `minBuyers24h` (type: `integer`):

Unique wallets, not trades. A pool worked by one bot and a pool traded by a thousand people look identical by transaction count and different here.

## `minPriceChange24hPercent` (type: `integer`):

Negative values allowed.

## `maxPriceChange24hPercent` (type: `integer`):

Negative values allowed.

## `minPoolAgeHours` (type: `integer`):

Lower bound on pool age in hours. Use it to skip brand-new pools.

## `maxPoolAgeHours` (type: `integer`):

Upper bound on pool age in hours. Use 24 to keep only pools created today.

## `minPriceUsd` (type: `string`):

Accepts fractions such as 0.000001.

## `maxPriceUsd` (type: `string`):

Accepts fractions such as 0.000001.

## `quoteSymbols` (type: `array`):

For example SOL, WETH, USDC. Case is ignored.

## `excludeQuoteSymbols` (type: `array`):

Quote tokens to drop, for example stablecoins you do not want. Case is ignored.

## `baseSymbols` (type: `array`):

Base token symbols to keep. Case is ignored.

## `nameContains` (type: `array`):

Keep a pool if its pool name, token name or token symbol contains any of these words.

## `withSocialsOnly` (type: `boolean`):

Needs the merge switch on, because links come from DexScreener.

## `sortBy` (type: `string`):

Applied to what this run collected, after collection — the open endpoint only sorts by 24h volume and 24h transactions. Leave empty to keep source order and stream results as they arrive.

## `sortDescending` (type: `boolean`):

On: highest value first. Off: lowest first. Pools with no value for the chosen field always go last.

## `compactOutput` (type: `boolean`):

23 fields instead of 95 — the ones an agent or a spreadsheet usually needs.

## `excludeEmptyFields` (type: `boolean`):

Leaves out keys whose value is empty. Smaller payloads for LLM pipelines.

## Actor input object example

```json
{
  "mode": "trending",
  "networks": [],
  "dexes": [],
  "duration": "24h",
  "sort": "h24_volume_usd_desc",
  "pagesPerNetwork": 3,
  "fromPage": 1,
  "tokenAddresses": [],
  "pairAddresses": [],
  "boostsKind": "latest",
  "enrich": true,
  "maxItems": 50,
  "onlyChanged": false,
  "priceChangeThresholdPercent": 0,
  "emitUnchanged": false,
  "quoteSymbols": [],
  "excludeQuoteSymbols": [],
  "baseSymbols": [],
  "nameContains": [],
  "withSocialsOnly": false,
  "sortBy": "",
  "sortDescending": true,
  "compactOutput": false,
  "excludeEmptyFields": false
}
```

# Actor output Schema

## `results` (type: `string`):

All collected rows

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "trending",
    "networks": [],
    "query": "",
    "dexes": [],
    "pagesPerNetwork": 3,
    "tokenAddresses": [],
    "pairAddresses": [],
    "maxItems": 50,
    "quoteSymbols": [],
    "excludeQuoteSymbols": [],
    "baseSymbols": [],
    "nameContains": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("snow_leo_data/dexscreener-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "trending",
    "networks": [],
    "query": "",
    "dexes": [],
    "pagesPerNetwork": 3,
    "tokenAddresses": [],
    "pairAddresses": [],
    "maxItems": 50,
    "quoteSymbols": [],
    "excludeQuoteSymbols": [],
    "baseSymbols": [],
    "nameContains": [],
}

# Run the Actor and wait for it to finish
run = client.actor("snow_leo_data/dexscreener-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "trending",
  "networks": [],
  "query": "",
  "dexes": [],
  "pagesPerNetwork": 3,
  "tokenAddresses": [],
  "pairAddresses": [],
  "maxItems": 50,
  "quoteSymbols": [],
  "excludeQuoteSymbols": [],
  "baseSymbols": [],
  "nameContains": []
}' |
apify call snow_leo_data/dexscreener-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,snow_leo_data/dexscreener-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/bN5aOTdalTsd2jo1d/builds/5QjjUtanKQ2hDXk86/openapi.json
