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%7DAfter
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%7DNot 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.
- Your URLs have
version=4: the config is already in the right format. Remove theversionparameter, because ChartPNG refuses it. - Your URLs have no version, or a lower one: you have a v2 config. ChartPNG does not convert it. You rewrite the options in the v4 format.
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.
legend.display: false are lost. 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%7DThe changes you will meet most
| Chart.js v2 | Chart.js v4 |
|---|---|
scales.xAxes[0], scales.yAxes[0] | scales.x, scales.y |
scaleLabel: { labelString } | title: { text } |
ticks.beginAtZero, ticks.min, ticks.max | beginAtZero, min, max on the scale |
options.title, options.legend | options.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:
chartorcwidthorwheightorhbackgroundColororbkgdevicePixelRatioordpr
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 listed | ChartPNG | |
|---|---|---|
| Width | 500 | 600 |
| Height | 300 | 360 |
| Pixel ratio | 2 | 1 (it accepts 1 or 2) |
| Background | transparent | white (bkg=transparent works) |
| Largest side | 3000 | 2000 (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:
- JavaScript-only syntax such as single quotes, keys without quotes and trailing commas. ChartPNG answers
chart config must be valid JSON. - Functions such as tick callbacks and label formatters. A function written as a string stays a string and is not run. In a test on 2 Nov 2026, a string in
ticks.callbackmade the tick labels disappear. Remove them, and format the numbers in your data or labels instead.
What else is different
- Chart types: bar, line, pie, doughnut, radar, polarArea, scatter and bubble.
- Output: PNG only.
- Plugins: Chart.js core and no third-party plugins.
- Size: the config can be up to 16 KB.
- Free plan: a small
chartpng.devwatermark and up to 4 megapixels per image (width times height times dpr squared). - Look: a chart that sets no colors gets the ChartPNG theme. Anything your config sets wins.
Sources
Claims about other products, read at their source on 2 Nov 2026.
- QuickChart uses Chart.js 2.9.4 unless told otherwise:
The default is v2.9.4.
quickchart.io - QuickChart switches to v4 with a parameter:
Set version=4 when using a v4 configuration.
quickchart.io - QuickChart has a version parameter:
Chart.js major version.
quickchart.io - QuickChart width is in pixels before the pixel ratio (default 500, max 3000):
Width of the image in pixels, before applying devicePixelRatio.
quickchart.io - QuickChart background (default transparent):
Background of the chart canvas.
quickchart.io - QuickChart pixel ratio (default 2):
Device pixel ratio of the output.
quickchart.io - QuickChart accepts a config that is not strict JSON:
Javascript or JSON object
quickchart.io - Chart.js v3 dropped the axes arrays:
scales.[x/y]Axes arrays were removed.
www.chartjs.org - Chart.js v3 renamed the axis label option:
scales.[x/y]Axes.scaleLabel was renamed to scales[id].title
www.chartjs.org - Chart.js v3 moved ticks.beginAtZero:
scales.[x/y]Axes.ticks.beginAtZero was renamed to scales[id].beginAtZero
www.chartjs.org - Chart.js v3 moved legend and title:
legend, title and tooltip namespaces were moved from options to options.plugins.
www.chartjs.org - Chart.js v3 replaced horizontalBar:
Horizontal bar charts can be configured using the new indexAxis option
www.chartjs.org