Dune Analytics API Integration: On-Chain Analytics in Your Product

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

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1452
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1310
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1005
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1270
  • image_logo-advance_0.webp
    B2B Advance company logo design
    719
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1012

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.