Tutorial: stream Trinity data into Grafana
You will plug the Trinity Insights REST API into a Grafana dashboard via the open-source Infinity datasource plugin. Refresh is scheduled, authentication runs server-side, and payloads never leave your infrastructure boundary.
Prerequisites
- A Grafana 10+ instance (Cloud, self-hosted or Grafana OSS).
- The Infinity datasource plugin installed. On Grafana Cloud:
Plugins → Infinity → Install. Self-hosted:grafana-cli plugins install yesoreyeram-infinity-datasource. - A Trinity Insights API key (Pro tier or above recommended).
Step 1 — Provision the datasource
Add the following file to the Grafana provisioning configuration:
# Grafana provisioning — datasources/trinity-insights.yaml
apiVersion: 1
datasources:
- name: Trinity Insights
type: yesoreyeram-infinity-datasource
access: proxy
isDefault: false
jsonData:
auth_method: bearerToken
global_queries: []
url: https://api.trinityinsights.io
url_options:
params:
- key: format
value: json
secureJsonData:
bearerToken: ${TRINITY_API_KEY}
The TRINITY_API_KEY environment variable is injected by your orchestrator (Helm, docker-compose, Terraform). On Grafana Cloud, create the datasource via the UI: Settings → Data sources → Add → Infinity, then set Authentication = Bearer token.
Note: the Trinity API accepts both the X-API-Key header and a Clerk Bearer JWT. Infinity uses Bearer by default, which keeps the configuration simple.
Step 2 — Create a panel
Add a Time series panel and paste the following query (example on MVRV Classic over 365 days):
{
"datasource": "Trinity Insights",
"url": "/api/v1/scores/mvrv-classic/history?days=365",
"type": "json",
"format": "table",
"root_selector": "data",
"columns": [
{ "selector": "date", "text": "time", "type": "timestamp" },
{ "selector": "value", "text": "value", "type": "number" }
],
"filters": []
}To stack several metrics on the same panel, add another Infinity query with a different metric identifier (for example nupl-classic, sopr-classic). No combination limit on the Trinity side as long as you stay within your tier quota.
Step 3 — Refresh policy
- Daily on-chain metrics are comfortable with a 5 or 10 minute refresh (matches Trinity's pipeline cron). No need to go below one minute.
- Trinity composites are recomputed daily; an hourly refresh is enough.
- Enable the Grafana panel cache (
Query options → Cache timeout) to save API calls in shared view.
Step 4 — Alerting
Grafana Unified Alerting can periodically evaluate the value returned by an endpoint and trigger a notification (Slack, Discord, PagerDuty, email). Example: alert when TCI flips into the advanced distribution zone.
{
"title": "Trinity TCI distribution zone",
"condition": "A",
"data": [
{
"refId": "A",
"queryType": "json",
"datasourceUid": "trinity-insights",
"model": {
"url": "/api/v1/scores/trinity-composite-index/latest",
"root_selector": "$",
"columns": [
{ "selector": "value", "type": "number" }
]
}
}
],
"noDataState": "OK",
"execErrState": "Error",
"for": "10m",
"annotations": {
"summary": "TCI crossed into distribution zone"
}
}The threshold and condition are defined in Grafana — Trinity exposes only the value. No personal recommendation is implied: this is a technical review trigger.
Step 5 — Prometheus variant
If your internal stack already standardises on Prometheus + Grafana, you can push Trinity values into a Pushgateway rather than querying the API from every panel.
# Optional: push Trinity values directly into Prometheus pushgateway
# for shops that already standardise on a Prometheus + Grafana stack.
import os
import time
import requests
from prometheus_client import CollectorRegistry, Gauge, push_to_gateway
BASE = "https://api.trinityinsights.io"
HEADERS = {"X-API-Key": os.environ["TRINITY_API_KEY"]}
METRICS = [
("onchain", "mvrv-classic"),
("onchain", "sopr-classic"),
("macro-intelligence", "macro-v2-tlbi-trinity-leading-business-indicator"),
]
while True:
registry = CollectorRegistry()
gauges = {}
for rubric, metric_id in METRICS:
gauges[metric_id] = Gauge(
f"trinity_{metric_id.replace('-', '_')}",
f"Trinity Insights {metric_id} (educational, not investment advice).",
registry=registry,
)
response = requests.get(
f"{BASE}/api/v1/{rubric}/{metric_id}/latest",
headers=HEADERS, timeout=10,
)
response.raise_for_status()
gauges[metric_id].set(response.json()["value"])
push_to_gateway(
os.environ["PROM_PUSHGATEWAY_URL"],
job="trinity-insights",
registry=registry,
)
time.sleep(900) # 15 minutes
The benefit is decoupling panel latency from your Trinity quota and aligning these metrics with the same observability mechanism as the rest of your infrastructure.
Best practices
- Put the institutional annotation directly into the panel (Grafana Panel Description): MiCA disclaimer + link to the Trinity metric sheet. Avoids misinterpretation in internal reviews.
- Keep a separate panel per rubric (cycle, macro, narrative). Visually mixing different scales (z-score vs 0-100 vs USD) blurs the read.
- Version-control your Grafana provisioning file in Git for auditability.
Related resources
Institutional disclaimer
Values returned by the Trinity Insights API are strictly educational and analytical. Panels and alerts do not constitute investment advice. Trinity Insights is not a Crypto-Asset Service Provider (CASP) registered under MiCA Regulation (EU) 2023/1114. See the full disclaimer.