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)