ChartPNG

Recipes

Migrating from QuickChart

Move your QuickChart URLs to ChartPNG and fix the configs that need it.

1. Change the domain

The c parameter and the JSON config keep their names. For many URLs this is the whole change.

Before

https://quickchart.io/chart?w=600&h=360&c=%7B%22type%22%3A%22bar%22%2C%22data%22%3A%7B%22labels%22%3A%5B%22Mon%22%2C%22Tue%22%2C%22Wed%22%5D%2C%22datasets%22%3A%5B%7B%22label%22%3A%22Signups%22%2C%22data%22%3A%5B12%2C19%2C7%5D%7D%5D%7D%2C%22options%22%3A%7B%22title%22%3A%7B%22display%22%3Atrue%2C%22text%22%3A%22Signups%20per%20day%22%7D%2C%22legend%22%3A%7B%22display%22%3Afalse%7D%2C%22scales%22%3A%7B%22yAxes%22%3A%5B%7B%22ticks%22%3A%7B%22beginAtZero%22%3Atrue%7D%2C%22scaleLabel%22%3A%7B%22display%22%3Atrue%2C%22labelString%22%3A%22Signups%22%7D%7D%5D%2C%22xAxes%22%3A%5B%7B%22scaleLabel%22%3A%7B%22display%22%3Atrue%2C%22labelString%22%3A%22Day%22%7D%7D%5D%7D%7D%7D

After

https://chartpng.dev/chart?w=600&h=360&c=%7B%22type%22%3A%22bar%22%2C%22data%22%3A%7B%22labels%22%3A%5B%22Mon%22%2C%22Tue%22%2C%22Wed%22%5D%2C%22datasets%22%3A%5B%7B%22label%22%3A%22Signups%22%2C%22data%22%3A%5B12%2C19%2C7%5D%7D%5D%7D%2C%22options%22%3A%7B%22title%22%3A%7B%22display%22%3Atrue%2C%22text%22%3A%22Signups%20per%20day%22%7D%2C%22legend%22%3A%7B%22display%22%3Afalse%7D%2C%22scales%22%3A%7B%22yAxes%22%3A%5B%7B%22ticks%22%3A%7B%22beginAtZero%22%3Atrue%7D%2C%22scaleLabel%22%3A%7B%22display%22%3Atrue%2C%22labelString%22%3A%22Signups%22%7D%7D%5D%2C%22xAxes%22%3A%5B%7B%22scaleLabel%22%3A%7B%22display%22%3Atrue%2C%22labelString%22%3A%22Day%22%7D%7D%5D%7D%7D%7D

Not every config survives the move unchanged. The next step is the one that matters.

2. Check the Chart.js version

ChartPNG renders Chart.js v4 today, and nothing else. QuickChart's default is older. Its FAQ says the default is v2.9.4, and that you set version=4 to use a v4 config.

A v2 config that is valid JSON and uses one of the eight supported chart types does not fail: the bars still draw, and the options v4 does not know are ignored. A config with type: "horizontalBar", a QuickChart-only chart type or JavaScript syntax is refused with a 400. Here is the same config on ChartPNG, before and after the rewrite.

Bar chart from a v2 config: no title, no axis titles, legend still shown
The v2 config, only the domain changed. The title, the axis titles and legend.display: false are lost. Open the PNG.
The same bar chart from a v4 config: title, axis titles and no legend
The same chart in the v4 format. Open the PNG.

Before: Chart.js v2 (QuickChart's default)

{
  "type": "bar",
  "data": {
    "labels": [
      "Mon",
      "Tue",
      "Wed"
    ],
    "datasets": [
      {
        "label": "Signups",
        "data": [
          12,
          19,
          7
        ]
      }
    ]
  },
  "options": {
    "title": {
      "display": true,
      "text": "Signups per day"
    },
    "legend": {
      "display": false
    },
    "scales": {
      "yAxes": [
        {
          "ticks": {
            "beginAtZero": true
          },
          "scaleLabel": {
            "display": true,
            "labelString": "Signups"
          }
        }
      ],
      "xAxes": [
        {
          "scaleLabel": {
            "display": true,
            "labelString": "Day"
          }
        }
      ]
    }
  }
}

After: Chart.js v4 (what ChartPNG renders)

{
  "type": "bar",
  "data": {
    "labels": [
      "Mon",
      "Tue",
      "Wed"
    ],
    "datasets": [
      {
        "label": "Signups",
        "data": [
          12,
          19,
          7
        ]
      }
    ]
  },
  "options": {
    "plugins": {
      "title": {
        "display": true,
        "text": "Signups per day"
      },
      "legend": {
        "display": false
      }
    },
    "scales": {
      "y": {
        "beginAtZero": true,
        "title": {
          "display": true,
          "text": "Signups"
        }
      },
      "x": {
        "title": {
          "display": true,
          "text": "Day"
        }
      }
    }
  }
}

The URL that draws the v4 chart

https://chartpng.dev/chart?w=600&h=360&c=%7B%22type%22%3A%22bar%22%2C%22data%22%3A%7B%22labels%22%3A%5B%22Mon%22%2C%22Tue%22%2C%22Wed%22%5D%2C%22datasets%22%3A%5B%7B%22label%22%3A%22Signups%22%2C%22data%22%3A%5B12%2C19%2C7%5D%7D%5D%7D%2C%22options%22%3A%7B%22plugins%22%3A%7B%22title%22%3A%7B%22display%22%3Atrue%2C%22text%22%3A%22Signups%20per%20day%22%7D%2C%22legend%22%3A%7B%22display%22%3Afalse%7D%7D%2C%22scales%22%3A%7B%22y%22%3A%7B%22beginAtZero%22%3Atrue%2C%22title%22%3A%7B%22display%22%3Atrue%2C%22text%22%3A%22Signups%22%7D%7D%2C%22x%22%3A%7B%22title%22%3A%7B%22display%22%3Atrue%2C%22text%22%3A%22Day%22%7D%7D%7D%7D%7D

The changes you will meet most

Chart.js v2Chart.js v4
scales.xAxes[0], scales.yAxes[0]scales.x, scales.y
scaleLabel: { labelString }title: { text }
ticks.beginAtZero, ticks.min, ticks.maxbeginAtZero, min, max on the scale
options.title, options.legendoptions.plugins.title, options.plugins.legend
type: "horizontalBar" (a 400 on ChartPNG until you change it)type: "bar" with options.indexAxis: "y"

The Chart.js v3 migration guide lists the rest.

3. Check the parameters

ChartPNG accepts QuickChart's long names, so these pairs mean the same thing:

Any other parameter is refused with a 400 and a message such as unknown parameter: version. That includesversion, v, format, f and key. A parameter given twice is refused too, and so are two names for one field, such as c and chart. Every distinct URL is a new render, so junk parameters are not allowed to bust the cache.

The defaults differ

The same URL with no size gives a different image. Set the values you need.

QuickChart, as listedChartPNG
Width500600
Height300360
Pixel ratio21 (it accepts 1 or 2)
Backgroundtransparentwhite (bkg=transparent works)
Largest side30002000 (50 at the least)

4. Functions are never run

QuickChart describes its config as a JavaScript or JSON object. ChartPNG reads strict JSON and never runs code. Fix these before you switch:

What else is different

Sources

Claims about other products, read at their source on 2 Nov 2026.