Integration with Dune Analytics API
Dune has long ceased to be just a tool for manual analysis in the browser. With the release of the Dune API, it became possible to embed on-chain analytics directly into your product: dashboards, reports, alerts — without setting up your own indexer and without writing SQL from scratch. As an engineering team with experience integrating over 10 projects, we constantly encounter clients who bring raw transaction dumps and want to quickly get a working analytics module. The Dune API offers a production-ready solution with minimal infrastructure costs.
What Dune API actually does
The API provides two main scenarios: executing a query by its ID (POST /execute/{queryId}) and fetching results of the last execution (GET /results/{queryId}). The second option is significantly cheaper in credits — if the data is fresh enough, there's no need to launch a new execution.
import requests, time DUNE_API_KEY = "your_api_key" QUERY_ID = 3540604 # example: Uniswap V3 pool stats def get_query_results(query_id: int, params: dict = None) -> list[dict]: headers = {"X-Dune-API-Key": DUNE_API_KEY} # Launch execution with parameters execute_resp = requests.post( f"https://api.dune.com/api/v1/query/{query_id}/execute", headers=headers, json={"query_parameters": params or {}} ) execution_id = execute_resp.json()["execution_id"] # Wait for completion while True: status_resp = requests.get( f"https://api.dune.com/api/v1/execution/{execution_id}/status", headers=headers ) state = status_resp.json()["state"] if state == "QUERY_STATE_COMPLETED": break if state == "QUERY_STATE_FAILED": raise RuntimeError(f"Query failed: {status_resp.json()}") time.sleep(2) results = requests.get( f"https://api.dune.com/api/v1/execution/{execution_id}/results", headers=headers ) return results.json()["result"]["rows"] Typical query execution time: from 5 seconds to several minutes. For production systems, this is unacceptable as a synchronous call — cached results or background updates are needed.
Why caching Dune API results matters
Credits are consumed for each query execution, not for reading cached data. We use a three-tier scheme:
- Data from the last 24 hours is updated every hour via cron.
- Historical data (older than 7 days) is updated once a day.
- Results are stored in Redis or PostgreSQL with a TTL equal to the update interval.
Dune also returns result_metadata.execution_started_at — we use this as a cache timestamp to show the user data freshness. This approach ensures your dashboard doesn't lag and doesn't burn through your quota.
Parameterized queries: using one SQL for thousands of tokens
A strong feature of the Dune API is parameterization. A query in the browser can be made universal using {{param}} syntax, and values can be passed via the API. This allows one SQL to cover, for example, any ERC-20 address:
SELECT date_trunc('day', block_time) AS day, sum(amount / 1e18) AS volume FROM erc20_ethereum.evt_Transfer WHERE contract_address = {{token_address}} AND block_time >= now() - interval '{{days}}' day GROUP BY 1 ORDER BY 1 DESC Call with parameters:
results = get_query_results( query_id=MY_QUERY_ID, params={"token_address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "days": "30"} ) We often encounter situations where a client wants to see analytics for hundreds of tokens. Parameterization reduces the number of queries to Dune to a single template — you simply substitute addresses on your side.
Dune API plan comparison
| Plan | Queries per month | Recommendation |
|---|---|---|
| Free | 40 | Prototyping only |
| Plus | 2000 | Small production (up to 5 dashboards) |
| Premium | 15000+ | High-load projects requiring data freshness |
For a typical project with a dashboard of 10–20 widgets, Plus suffices, but we always advise clients to start with Premium during active development to avoid being blocked by limits at a critical moment.
How we speed up integration
Our experience shows that the biggest pain points are rate limits and latency. We configure the dune-client library with a connection pool and retries. In production, we use an asynchronous call through a task queue (Celery / RabbitMQ): a new query is queued, and the user sees the last cached slice. A background task periodically checks if an update is needed.
We also keep an eye on API versions — Dune occasionally introduces breaking changes (e.g., migration from v1 to v2). In our integrations, we include an adapter layer that allows switching between versions without modifying the dashboard code.
What's included in Dune API integration work
- Analysis of dashboard requirements and metric selection
- Writing and optimizing SQL queries for the API (taking into account limits, pagination)
- Implementing caching with configurable TTL
- Integration with backend (REST/gRPC/WebSocket) and frontend (React/Vue)
- Setting up automatic updates via cron or task queue
- Documentation of the API layer for the team
- Training your developers on working with the Dune API (1–2 sessions)
- 30-day support guarantee after delivery
Limitations and workarounds
Rate limits: on the free plan — 40 queries per month, on Plus — 2000, on Premium — 15000+. For production with multiple users, Plus is the minimum.
Response size: by default, up to 25,000 rows are returned. For larger datasets — use pagination via offset and limit parameters in the request to results.
Latency: GET /results/{queryId} without re-execution (cached results) returns instantly. Use this endpoint for read-heavy integrations and launch a new execution only on a schedule.
Integration from scratch to a working dashboard with caching — 1–2 days. If you have specific requirements (e.g., real-time data via WebSocket), the timeline may increase, but we always provide an accurate estimate after a free audit of your project. Contact us to discuss the details.







