# DexScreener Scraper - DEX Pairs, Prices & Liquidity (`scrapyx/dexscreener-pairs-scraper`) Actor

Scrapes DEX pairs and token profiles from DexScreener: price, liquidity, FDV, market cap, volume and buy/sell counts per window, socials and boosts. Parses the string prices, keeps FDV and market cap apart, and states the 30-pair search cap that has no paging.

- **URL**: https://apify.com/scrapyx/dexscreener-pairs-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** Business, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## DexScreener Scraper — DEX Pairs, Prices & Liquidity

Reads DexScreener's public API: DEX trading pairs across every indexed chain,
plus the token-profile and boosted-token discovery feeds. No key, no auth.

### What you get

| `recordType` | One per | Carries |
| --- | --- | --- |
| `PAIR` | trading pair | chain, DEX, pair address, base/quote token, price (parsed **and** raw), FDV, market cap, liquidity in USD/base/quote, volume and price change for 5m/1h/6h/24h, buy and sell counts, creation date, socials, websites, boost state |
| `TOKEN_PROFILE` | profiled or boosted token | chain, address, description, icon, links, boost amounts, rank |
| `SEARCH_SUMMARY` | query | pairs returned, the 30-pair cap, whether paging is supported, and how many rows this actor filtered out locally |
| `ERROR` | failed input | a named reason — every input maps to at least one row |

Four ways in, combinable in one run: `searchQueries`, `tokenAddresses`,
`pairs`, and the discovery feeds.

### Search returns 30 pairs and there is no way past it

Nothing in the payload says how many pairs actually matched — **no total, no
count, no `more` flag**. USDC has thousands of pairs; you get thirty.

And the three obvious paging parameters are accepted and **silently ignored**:

```
?q=USDC&limit=100   ->  30 pairs, first pair 0x6c9A33E3...
?q=USDC&page=2      ->  30 pairs, first pair 0x6c9A33E3...   identical
?q=USDC&offset=30   ->  30 pairs, first pair 0x6c9A33E3...   identical
```

HTTP 200 every time. A scraper that pages by incrementing `page` collects the
same thirty rows over and over and reports them as growing coverage.

So this actor **does not paginate search at all** — one request per query, and
`pagingSupported: false` on every summary. To get real breadth, use more
queries, or address tokens directly: **`tokenAddresses` is the surface that
returns a token's full pair set**, and addresses on the same chain are batched
30 per request, so thirty tokens cost one call.

### FDV and market cap are different numbers

They differ on **17 of 30 pairs** in a single measured response, and not
subtly:

```
USDC    fdv  6,338,247,859     marketCap 60,893,794,316     9.6x apart
```

Note the direction — FDV is the *smaller* one, backwards from the usual "fully
diluted ≥ current" intuition, so substituting either for the other is wrong in
a way that also defies the sanity check. Both are emitted verbatim, neither is
derived from the other, and `fdvEqualsMarketCap` records which pairs happen to
agree.

### Prices are strings; everything else numeric is not

In the same object: `priceUsd` `"105.96"` (string), `fdv` `23434953` (int),
`liquidity.usd` `435995.74` (float).

Sorting `priceUsd` as delivered is a **lexicographic** sort, where `"9.5"`
ranks above `"105.96"`. Both forms are emitted — `priceUsd` parsed to a float
for arithmetic, `priceUsdRaw` exactly as sent, because a very small token price
carries significant digits a float rounds away.

### Optional fields are absent, not null

Measured on one 30-pair response: `boosts` missing on **30/30**, `info` on
**28/30**, `labels` on **20/30**, `pairCreatedAt` on **4/30**. So
`pair["info"]` raises where `pair.get("info")` returns None, and a consumer
assuming a stable schema breaks on the majority of rows.

Every row here has the same shape, with `hasInfo` and `hasBoosts` recorded
explicitly so "absent" stays distinguishable from "present but empty".

### Filtering happens here, not upstream

DexScreener's API has **no filter parameters at all**. `chainFilter` and
`minLiquidityUsd` are applied by this actor after fetching, and the summary
reports `filteredOutLocally` so a small result set is explained rather than
mysterious. A pair with no liquidity figure is dropped by the floor rather than
treated as zero.

### Honest failures

Rare enough to be worth stating: nothing on this API silently widens.

- unknown chain or token address → HTTP 200 with an **empty list** (raised here
  as `no_pairs`, never a silent zero-row success)
- nonsense search term → zero pairs, not an unfiltered baseline
- unknown pair → zero pairs, not a 404
- one-character search term → a real HTTP 400 (refused up front here)

### Notes

- `api.dexscreener.com/robots.txt` is HTTP 404, which RFC 9309 §2.3.1.3 treats
  as no restrictions. No WAF: 6 of 6 TLS profiles returned identical JSON.
- **DexScreener sends no rate-limit headers on any endpoint.** Its published
  limits (300/minute for pairs, search and tokens; 60/minute for profiles and
  boosts) are real but invisible, so pacing is the only defence. The two tiers
  are paced separately.
- Boosted tokens are a *promotion* signal, not a quality one.

# Actor input Schema

## `searchQueries` (type: `array`):

Token symbols, names or addresses to search. Each term returns at most 30 pairs and DexScreener publishes no total and supports no paging — limit, page and offset are accepted and silently ignored. Use several narrower terms rather than expecting one to go deeper.

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

Tokens as '<chain>/<tokenAddress>', e.g. 'solana/So11111111111111111111111111111111111111112'. Addresses on the same chain are batched 30 per request, so 30 tokens cost one call. This is the way to get complete pair coverage for a token — search will not.

## `pairs` (type: `array`):

Pairs as '<chain>/<pairAddress>' or a dexscreener.com URL.

## `includeTokenProfiles` (type: `boolean`):

The newest tokens to publish a DexScreener profile — description, icon and links. A discovery feed, not tied to your search terms.

## `includeBoostedTokens` (type: `boolean`):

Tokens with active paid boosts, both the newest and the highest-boosted. Useful as a promotion signal; it is not a quality signal.

## `chainFilter` (type: `string`):

Keep only pairs on one chain, e.g. 'solana', 'base', 'ethereum'. Applied by this actor AFTER fetching — DexScreener's API has no filter parameters at all, so the rows it drops are reported as filteredOutLocally.

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

Drop pairs below this liquidity. Also applied locally; pairs with no liquidity figure at all are dropped rather than assumed to be zero.

## `maxConcurrency` (type: `integer`):

Requests in flight at once.

## `minRequestInterval` (type: `integer`):

Pacing for pair/search/token calls, whose published limit is 300 a minute. The profile and boost feeds are paced separately and more slowly, because their limit is 60 a minute. DexScreener sends no rate-limit headers, so pacing is the only defence.

## `proxyConfiguration` (type: `object`):

Optional and OFF by default. No WAF was observed (6 of 6 TLS profiles returned identical JSON).

## Actor input object example

```json
{
  "searchQueries": [
    "SOL",
    "PEPE"
  ],
  "tokenAddresses": [
    "solana/So11111111111111111111111111111111111111112"
  ],
  "pairs": [
    "base/0x1131DB5977242a03eBeaD1aCD18F80A9A29e5922"
  ],
  "includeTokenProfiles": false,
  "includeBoostedTokens": false,
  "chainFilter": "solana",
  "maxConcurrency": 4,
  "minRequestInterval": 0,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {
    "searchQueries": [
        "SOL"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/dexscreener-pairs-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 = { "searchQueries": ["SOL"] }

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/dexscreener-pairs-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 '{
  "searchQueries": [
    "SOL"
  ]
}' |
apify call scrapyx/dexscreener-pairs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/dexscreener-pairs-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/5zIQeiN4CcOxfoRXE/builds/YdaVo8P08VoPOdkPT/openapi.json
