Browser / CDN Quickstart
Load the Bonnard SDK via a `<script>` tag and query your semantic layer from any HTML page.
Setup
Add the SDK script tag to your HTML. It exposes window.Bonnard.
<script src="https://cdn.jsdelivr.net/npm/@bonnard/sdk/dist/bonnard.iife.js"></script>Alternative CDN:
<script src="https://unpkg.com/@bonnard/sdk/dist/bonnard.iife.js"></script>Pin a specific version:
<script src="https://cdn.jsdelivr.net/npm/@bonnard/sdk@latest/dist/bonnard.iife.js"></script>First query
<script src="https://cdn.jsdelivr.net/npm/@bonnard/sdk/dist/bonnard.iife.js"></script>
<script>
const bon = Bonnard.createClient({
apiKey: "bon_pk_YOUR_KEY_HERE",
});
(async () => {
const { data } = await bon.query({
measures: ["orders.revenue", "orders.count"],
dimensions: ["orders.city"],
orderBy: { "orders.revenue": "desc" },
limit: 10,
});
console.log(data);
// [{ "orders.revenue": 125000, "orders.count": 340, "orders.city": "Berlin" }, ...]
})();
</script>Note: the IIFE bundle uses a regular <script> tag (not type="module"), so top-level await is not available. Wrap async code in an IIFE or use .then().
Async patterns
IIFE wrapper (recommended)
<script>
(async () => {
const bon = Bonnard.createClient({ apiKey: "bon_pk_..." });
const { data } = await bon.query({ measures: ["orders.revenue"] });
document.getElementById("revenue").textContent = data[0]["orders.revenue"];
})();
</script>Promise chain
<script>
const bon = Bonnard.createClient({ apiKey: "bon_pk_..." });
bon
.query({ measures: ["orders.revenue"] })
.then(({ data }) => {
document.getElementById("revenue").textContent = data[0]["orders.revenue"];
})
.catch((err) => {
console.error("Query failed:", err.message);
});
</script>Parallel queries
<script>
(async () => {
const bon = Bonnard.createClient({ apiKey: "bon_pk_..." });
const [kpis, byCity] = await Promise.all([
bon.query({ measures: ["orders.revenue", "orders.count"] }),
bon.query({
measures: ["orders.revenue"],
dimensions: ["orders.city"],
orderBy: { "orders.revenue": "desc" },
}),
]);
// Render KPIs
document.getElementById("revenue").textContent = kpis.data[0]["orders.revenue"];
document.getElementById("count").textContent = kpis.data[0]["orders.count"];
// Render chart with byCity.data...
})();
</script>Error handling
Errors from the API are instances of Bonnard.BonnardError, which includes the HTTP status code:
<script>
(async () => {
const bon = Bonnard.createClient({ apiKey: "bon_pk_..." });
try {
const { data } = await bon.query({
measures: ["orders.revenue"],
});
renderDashboard(data);
} catch (err) {
if (err instanceof Bonnard.BonnardError) {
// API error — check status code
document.getElementById("error").textContent = `Error ${err.statusCode}: ${err.message}`;
} else {
// Network error — no response received
document.getElementById("error").textContent = "Network error";
}
document.getElementById("error").style.display = "block";
}
})();
</script>Common errors:
statusCode: 401— invalid or expired API keystatusCode: 400— invalid measure/dimension names or query structureTypeError(not BonnardError) — network failure, CORS, or connectivity issue
See Errors for the full error reference and retry patterns.
Custom base URL
By default the SDK points to https://app.bonnard.dev. Override for self-hosted or preview deployments:
<script>
const bon = Bonnard.createClient({
apiKey: "bon_pk_...",
baseUrl: "https://your-deployment.vercel.app",
});
</script>What's on window.Bonnard
The IIFE bundle exposes two exports:
| Export | Purpose |
|---|---|
Bonnard.createClient(config) | Create an SDK client instance |
Bonnard.toCubeQuery(options) | Convert QueryOptions to a Cube-native query object (useful for debugging) |
Bonnard.BonnardError | Error class with statusCode and retryable — use with instanceof for error handling |
Field naming
All field names must be fully qualified with the view name:
// Correct
bon.query({ measures: ["orders.revenue"], dimensions: ["orders.city"] });
// Wrong — will fail
bon.query({ measures: ["revenue"], dimensions: ["city"] });Discovering available fields
Use explore() to discover what views, measures, and dimensions are available:
const meta = await bon.explore();
for (const view of meta.cubes) {
console.log(view.name);
console.log(
" Measures:",
view.measures.map((m) => m.name),
);
console.log(
" Dimensions:",
view.dimensions.map((d) => d.name),
);
}Next steps
- Chartjs — Build a dashboard with Chart.js
- Echarts — Build a dashboard with ECharts
- Apexcharts — Build a dashboard with ApexCharts
- Query Reference — Full query API reference
- Errors — Error handling and retry patterns
- Authentication — Auth patterns for multi-tenant apps