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
<script>
(async () => {
const bon = Bonnard.createClient({ apiKey: 'bon_pk_...' });
try {
const { data } = await bon.query({
measures: ['orders.revenue'],
});
renderDashboard(data);
} catch (err) {
document.getElementById('error').textContent = err.message;
document.getElementById('error').style.display = 'block';
}
})();
</script>Common errors:
"Unauthorized"— invalid or expired API key"Query failed"— invalid measure/dimension names or query structure- Network errors — API unreachable (CORS, connectivity)
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) |
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
- Authentication — Auth patterns for multi-tenant apps