Dune Analytics Crypto API: A Trader's Complete Guide
Learn how to access on-chain blockchain data via the Dune Analytics API, from authentication to parsing live DeFi and trading metrics in Python.
Learn how to access on-chain blockchain data via the Dune Analytics API, from authentication to parsing live DeFi and trading metrics in Python.
Raw price feeds from Binance or OKX tell you what the market is doing right now. Dune Analytics tells you why — who's moving funds, which wallets are accumulating, how much liquidity is sitting in a DEX pool, and whether smart money is fleeing or entering a protocol. The Dune Analytics API gives you programmatic access to all of that on-chain intelligence, letting you build it directly into your trading workflows instead of clicking around dashboards.
Dune Analytics is a blockchain data platform that lets analysts query raw on-chain data using SQL. The community has published tens of thousands of dashboards tracking everything from Uniswap volume to Ethereum validator flows. The API layer, introduced with Dune's v1 REST API and expanded significantly since, gives developers a way to execute those queries and retrieve results programmatically — no browser required.
For a trader, this opens up a completely different information layer. While centralized exchanges like Binance, Bybit, and Coinbase give you order book data and trade history for their own platforms, Dune gives you visibility into what's happening on-chain: large wallet movements, protocol TVL changes, token concentration metrics, and DEX arbitrage flows. These signals often precede price moves by hours.
Dune's API uses a simple API key authentication model. You'll need at least a free account to get a key, though free tier queries are rate-limited and you can't execute new queries on demand — you can only fetch results from already-executed queries. The paid plans (Plus and Premium) unlock execution credits, higher rate limits, and faster query performance. For serious trading automation, the Plus plan is the minimum viable tier.
Once you have your API key from the Dune settings page, authentication is just an HTTP header. Here's how to set up a reusable client in Python with proper session handling and retry logic:
import requests
import time
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
DUNE_API_KEY = "your_api_key_here" # store in env var, never hardcode
BASE_URL = "https://api.dune.com/api/v1"
def create_dune_session():
"""Create a requests session with retry logic for Dune API."""
session = requests.Session()
session.headers.update({
"X-Dune-API-Key": DUNE_API_KEY,
"Content-Type": "application/json"
})
# Retry on 429 (rate limit) and 5xx errors
retry_strategy = Retry(
total=3,
backoff_factor=2,
status_forcelist=[429, 500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)
return session
session = create_dune_session()
print("Dune session ready")
Never hardcode your API key in source code. Store it in an environment variable (DUNE_API_KEY) and load it with os.environ.get('DUNE_API_KEY'). If you accidentally commit a key to GitHub, rotate it immediately in your Dune account settings.
The Dune API has two main patterns: fetching the latest results of a pre-executed query (fast, uses no credits), and triggering a fresh execution of a query (costs credits, returns up-to-date data). For real-time trading signals you usually want fresh executions. The flow is: POST to execute, poll for completion, GET the results.
Every public Dune dashboard query has a numeric query ID visible in the URL. For example, query 3306935 tracks Ethereum CEX inflows — a useful bearish signal when you see large spikes before a major exchange like Coinbase or Binance processes deposits.
import os
import time
import requests
DUNE_API_KEY = os.environ.get("DUNE_API_KEY")
BASE_URL = "https://api.dune.com/api/v1"
HEADERS = {"X-Dune-API-Key": DUNE_API_KEY}
def execute_query(query_id: int, parameters: dict = None) -> str:
"""Trigger a fresh query execution. Returns execution_id."""
url = f"{BASE_URL}/query/{query_id}/execute"
payload = {"query_parameters": parameters or {}}
resp = requests.post(url, headers=HEADERS, json=payload)
resp.raise_for_status()
return resp.json()["execution_id"]
def poll_execution(execution_id: str, timeout: int = 120) -> dict:
"""Poll until query finishes or timeout. Returns result rows."""
url = f"{BASE_URL}/execution/{execution_id}/status"
deadline = time.time() + timeout
while time.time() < deadline:
resp = requests.get(url, headers=HEADERS)
resp.raise_for_status()
data = resp.json()
state = data.get("state")
if state == "QUERY_STATE_COMPLETED":
return fetch_results(execution_id)
elif state in ("QUERY_STATE_FAILED", "QUERY_STATE_CANCELLED"):
raise RuntimeError(f"Query {execution_id} failed: {state}")
time.sleep(3) # Dune recommends polling every 3s
raise TimeoutError(f"Query {execution_id} timed out after {timeout}s")
def fetch_results(execution_id: str) -> list:
"""Fetch paginated results for a completed execution."""
url = f"{BASE_URL}/execution/{execution_id}/results"
resp = requests.get(url, headers=HEADERS)
resp.raise_for_status()
return resp.json().get("result", {}).get("rows", [])
# Usage example — ETH exchange inflow query
QUERY_ID = 3306935
try:
exec_id = execute_query(QUERY_ID)
print(f"Execution started: {exec_id}")
rows = poll_execution(exec_id)
print(f"Got {len(rows)} rows")
except Exception as e:
print(f"Error: {e}")
Raw rows from Dune queries need to be parsed and normalized before they're useful in a trading workflow. Numeric values often come back as strings, timestamps are in various formats, and token amounts need decimal adjustments. Here's a practical parsing layer that converts Dune output into a pandas DataFrame you can work with directly:
import pandas as pd
from datetime import datetime
def parse_dune_rows(rows: list, numeric_cols: list = None,
date_cols: list = None) -> pd.DataFrame:
"""
Convert raw Dune rows to a clean DataFrame.
numeric_cols: column names to cast to float
date_cols: column names to parse as datetime
"""
if not rows:
return pd.DataFrame()
df = pd.DataFrame(rows)
# Cast numeric columns (Dune returns large numbers as strings)
for col in (numeric_cols or []):
if col in df.columns:
df[col] = pd.to_numeric(df[col], errors="coerce")
# Parse datetime columns
for col in (date_cols or []):
if col in df.columns:
df[col] = pd.to_datetime(df[col], utc=True, errors="coerce")
return df.sort_values(date_cols[0] if date_cols else df.columns[0])
# Example: parse exchange inflow results
if rows:
df = parse_dune_rows(
rows,
numeric_cols=["amount_usd", "token_amount"],
date_cols=["block_time"]
)
# Flag large inflows (>$1M USD) as bearish signal
large_inflows = df[df["amount_usd"] > 1_000_000]
if not large_inflows.empty:
print("ALERT: Large CEX inflows detected")
print(large_inflows[["block_time", "symbol", "amount_usd"]].tail(5))
else:
print("No large inflows in current window")
Token amounts on Ethereum are stored as raw integers without decimals. ETH has 18 decimal places, USDC has 6. Always divide by 10**decimals before displaying or comparing token amounts, or use Dune's human_readable_amount columns where available.
The most immediately useful applications pull Dune data as a complement to exchange signals. Platforms like Bybit and OKX give you derivatives data — funding rates, open interest, liquidations. Dune gives you the on-chain counterpart. Combining both layers produces significantly stronger signals than either source alone.
| Trader Type | Dune Signal | How to Use It |
|---|---|---|
| Spot / Swing | Exchange inflow spikes | Reduce exposure when large BTC/ETH moves to Binance/Coinbase wallets |
| DeFi Yield | Protocol TVL changes | Exit positions when TVL drops >15% in 24h — signals capital flight |
| Altcoin | Token holder concentration | Avoid tokens where top 10 wallets hold >60% of supply |
| Arb / Quant | DEX liquidity depth | Find pools with sufficient depth for size on Gate.io / Uniswap arb routes |
| Long-term | Stablecoin supply growth | Rising USDT/USDC on-chain supply = more dry powder = bullish macro |
VoiceOfChain integrates on-chain data signals alongside real-time price action alerts. While the platform surfaces pre-processed signals directly — so you don't need to run your own Dune queries for every trade — understanding how the underlying data is sourced helps you evaluate signal quality and build your own supplementary alerts for assets or protocols VoiceOfChain doesn't yet cover.
Dune's free tier allows fetching cached results but won't let you trigger fresh executions reliably. For trading automation, you need execution credits. The Plus plan (~$349/month as of early 2026) includes 2,500 execution credits per month — each query execution costs between 1-10 credits depending on complexity. Most simple on-chain metrics queries cost 1-2 credits, so you can run hundreds of executions daily.
The Dune Analytics API bridges the gap between raw blockchain data and actionable trading intelligence. Setting it up takes less than an hour — authentication is a single header, query execution is two API calls, and parsing results is straightforward with any standard data library. The real investment is identifying which on-chain metrics are actually predictive for the assets you trade and building reliable pipelines around them.
Start with exchange inflow/outflow monitoring for your top holdings — it's the highest signal-to-noise ratio use case and immediately validates whether on-chain data adds edge to your specific strategy. From there, layer in protocol-specific metrics, wallet tracking, and DEX liquidity monitoring as you develop conviction in the approach. Platforms like VoiceOfChain can complement this by surfacing processed signals in real time while your own Dune pipelines handle the custom analytics that fit your exact trading style.