DEV Community

Cover image for How to Embed Interactive Charts in Confluence with HTML Macro
Yamuno for Yamuno Software

Posted on • Originally published at yamuno.com

How to Embed Interactive Charts in Confluence with HTML Macro

How to Embed Interactive Charts in Confluence with HTML Macro

Confluence is where a lot of teams track project status, document KPIs, and share team metrics. But when it comes to actually visualizing that data, the options are limited. You can paste a static image (which goes stale), use a third-party integration (which requires a separate subscription), or accept that your Confluence page just won't have charts.

HTML Macro for Confluence opens a fourth option: embed Chart.js directly inside a Confluence page. The charts are interactive (hover for tooltips, click to toggle series), render instantly, and live alongside your documentation — no external service required.

This guide covers four chart types with copy-paste code for each.


Before You Start

Install HTML Macro for Confluence from the Atlassian Marketplace. It's free and runs on Atlassian Forge.

Security note: The examples below load Chart.js from a CDN (cdn.jsdelivr.net). Your Confluence admin needs to add that domain to the HTML Macro whitelist. Go to Confluence Settings → HTML Macro → Security Settings and add https://cdn.jsdelivr.net to the allowed domains.

Once that's done, add the macro to any Confluence page (Insert → Macro → HTML Macro), paste the code, and use the live preview to verify it before saving.


Bar Chart — Team Metrics or Sprint Data

Good for: comparing values across categories — issues by status, story points per sprint, bugs per team member.

<canvas id="barChart" width="700" height="350"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
  new Chart(document.getElementById('barChart'), {
    type: 'bar',
    data: {
      labels: ['To Do', 'In Progress', 'In Review', 'Done'],
      datasets: [{
        label: 'Issues',
        data: [12, 8, 5, 34],
        backgroundColor: ['#94a3b8', '#3b82f6', '#f59e0b', '#22c55e'],
        borderRadius: 6,
      }]
    },
    options: {
      responsive: false,
      plugins: {
        legend: { display: false },
        title: {
          display: true,
          text: 'Issue Status — Sprint 42',
          font: { size: 15, weight: '600' },
          color: '#1e293b',
        }
      },
      scales: {
        y: {
          beginAtZero: true,
          grid: { color: '#f1f5f9' },
          ticks: { color: '#64748b' }
        },
        x: {
          grid: { display: false },
          ticks: { color: '#64748b' }
        }
      }
    }
  });
</script>
Enter fullscreen mode Exit fullscreen mode

Replace the labels and data arrays with your actual values. Each label maps to the corresponding data value by index.


Line Chart — Velocity Trend or Weekly Progress

Good for: showing trends over time — sprint velocity, bug discovery rate, weekly active users, anything with a time axis.

<canvas id="lineChart" width="700" height="350"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
  new Chart(document.getElementById('lineChart'), {
    type: 'line',
    data: {
      labels: ['Sprint 37', 'Sprint 38', 'Sprint 39', 'Sprint 40', 'Sprint 41', 'Sprint 42'],
      datasets: [{
        label: 'Story Points Completed',
        data: [41, 38, 45, 52, 49, 55],
        borderColor: '#6366f1',
        backgroundColor: 'rgba(99, 102, 241, 0.08)',
        borderWidth: 2,
        pointBackgroundColor: '#6366f1',
        pointRadius: 4,
        fill: true,
        tension: 0.3,
      }]
    },
    options: {
      responsive: false,
      plugins: {
        legend: { position: 'top' },
        title: {
          display: true,
          text: 'Sprint Velocity — Last 6 Sprints',
          font: { size: 15, weight: '600' },
          color: '#1e293b',
        }
      },
      scales: {
        y: {
          beginAtZero: false,
          grid: { color: '#f1f5f9' },
          ticks: { color: '#64748b' }
        },
        x: {
          grid: { display: false },
          ticks: { color: '#64748b' }
        }
      }
    }
  });
</script>
Enter fullscreen mode Exit fullscreen mode

Pie Chart — Issue Type or Priority Distribution

Good for: showing how a total is distributed — issue types, budget allocation, time spent by category. Keep it to five segments or fewer.

<canvas id="pieChart" width="500" height="400"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
  new Chart(document.getElementById('pieChart'), {
    type: 'pie',
    data: {
      labels: ['Bug', 'Feature', 'Task', 'Tech Debt', 'Spike'],
      datasets: [{
        data: [18, 32, 25, 14, 11],
        backgroundColor: [
          '#ef4444',
          '#6366f1',
          '#3b82f6',
          '#f59e0b',
          '#94a3b8',
        ],
        borderWidth: 2,
        borderColor: '#fff',
      }]
    },
    options: {
      responsive: false,
      plugins: {
        legend: { position: 'right' },
        title: {
          display: true,
          text: 'Open Issues by Type',
          font: { size: 15, weight: '600' },
          color: '#1e293b',
        }
      }
    }
  });
</script>
Enter fullscreen mode Exit fullscreen mode

Doughnut Chart — Goal Progress or Completion Status

Good for: showing a single metric against a target — sprint completion, budget consumed, onboarding progress.

<div style="position:relative; width:400px; margin:0 auto;">
  <canvas id="doughnutChart" width="400" height="400"></canvas>
  <div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); text-align:center; font-family:sans-serif;">
    <div style="font-size:36px; font-weight:700; color:#1e293b;">72%</div>
    <div style="font-size:13px; color:#64748b;">Complete</div>
  </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
  new Chart(document.getElementById('doughnutChart'), {
    type: 'doughnut',
    data: {
      datasets: [{
        data: [72, 28],
        backgroundColor: ['#6366f1', '#f1f5f9'],
        borderWidth: 0,
        cutout: '78%',
      }]
    },
    options: {
      responsive: false,
      plugins: {
        legend: { display: false },
        tooltip: { enabled: false },
      }
    }
  });
</script>
Enter fullscreen mode Exit fullscreen mode

Change the 72 and 28 values (they must add to 100) and update the center label to match.


Multi-Dataset Line Chart — Compare Two Teams or Products

When you want to compare two data series on the same time axis:

<canvas id="multiLineChart" width="700" height="350"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
  new Chart(document.getElementById('multiLineChart'), {
    type: 'line',
    data: {
      labels: ['Week 1', 'Week 2', 'Week 3', 'Week 4', 'Week 5', 'Week 6'],
      datasets: [
        {
          label: 'Team Alpha',
          data: [12, 19, 15, 22, 18, 25],
          borderColor: '#6366f1',
          backgroundColor: 'transparent',
          borderWidth: 2,
          pointRadius: 4,
          tension: 0.3,
        },
        {
          label: 'Team Beta',
          data: [8, 14, 20, 17, 24, 21],
          borderColor: '#22c55e',
          backgroundColor: 'transparent',
          borderWidth: 2,
          pointRadius: 4,
          tension: 0.3,
        }
      ]
    },
    options: {
      responsive: false,
      plugins: {
        legend: { position: 'top' },
        title: {
          display: true,
          text: 'Weekly Issues Resolved',
          font: { size: 15, weight: '600' },
          color: '#1e293b',
        }
      },
      scales: {
        y: { beginAtZero: true, grid: { color: '#f1f5f9' } },
        x: { grid: { display: false } }
      }
    }
  });
</script>
Enter fullscreen mode Exit fullscreen mode

Tips for Production Use

Hard-code the data for now. Chart.js in Confluence can't call your Jira API or database — the data lives in the HTML. If your metrics change weekly, treat the Confluence page as a weekly snapshot: update the arrays when you update the commentary.

Use width and height attributes directly on <canvas>. Don't rely on responsive: true inside Confluence — the macro iframe has fixed dimensions and responsive sizing can behave unexpectedly.

Each chart needs a unique id. If you put multiple charts on the same page, give each canvas a different id (barChart, lineChart, etc.) to avoid conflicts.

Test in the live preview before saving. HTML Macro's side-by-side preview shows you exactly what Confluence page visitors will see — including CDN scripts loading.


A Note on the CDN Whitelist

Your admin needs to whitelist https://cdn.jsdelivr.net in HTML Macro's security settings for the Chart.js scripts to load. If the charts appear blank, that's the most common cause. Check the browser console for a CSP error and confirm the domain is in the allowlist.

For environments where all external CDNs are blocked, you can paste the minified Chart.js source directly into the <script> tag — it's about 60KB minified, which is manageable.


Install HTML Macro for Confluence — free on the Atlassian Marketplace

Top comments (0)