Issue Nº 14 — Aug 31, 2026

QuickChart turns a broken chart config into a blank image, not an error

Issue fourteen covers QuickChart, an API that renders a Chart.js config into an image instead of returning JSON. This session generated charts, a QR code, and an SVG, all with no key and wide-open CORS. It also found a gap: a config that fails to parse gets a plain-text error in a response header. A config that parses fine but names an unsupported chart type returns 200 and a blank picture instead, with no error signal anywhere in the response.

What it covers

QuickChart takes a Chart.js configuration and renders it as an image. A caller passes the config in the c parameter of a GET request, or posts it as JSON to the same path, and gets back a picture, not JSON. A live GET this session to /chart, with a three-bar Chart.js config, returned 200 and a 14,355-byte PNG. The same call with format=svg on the query string returned 200 and a 26,920-byte SVG instead, matching the formats field already on file.

A second hero endpoint, /qr, turned the text greatapis.com into a 909-byte PNG QR code from a plain GET with one parameter. Neither endpoint needed a key.

The version parameter picks which Chart.js release renders the chart. That same bar-chart config, sent with version=4, returned a 14,411-byte PNG instead of the 14,355 bytes above. Sent with version=2, it returned 14,355 bytes: byte for byte the size of the call that named no version at all. Version 2 is the default, and QuickChart runs more than one Chart.js release on its own servers.

No key, and CORS answers every check

No key or sign-up was needed for any call this session. This matches the auth: None already on file. An OPTIONS preflight against /chart, sent with an Origin header of https://greatapis.com, returned 200. The response carried access-control-allow-origin: *, access-control-allow-methods: GET, POST, and an allow header listing GET,HEAD,POST. This confirms the cors: yes on file.

The two endpoints do not answer alike on cookies. A plain GET to /chart sets a GAESA cookie, an App Engine session-affinity cookie, and so does the preflight above. Four GETs to /qr this session, each with different text and no cookie sent, set no cookie at all. Every one of the four was a cf-cache-status: MISS, so each reached the origin rather than a Cloudflare cache. The two paths run on different backends. That cookie plays no part in the CORS behaviour above.

A broken config renders a blank picture, not an error

A config string that fails to parse gets a real error. Sending c={type:"bar" with the closing brace left off returned 400. The response header read x-quickchart-error: Chart error: Error: Unexpected token ';' - 1:12. QuickChart names the exact parse failure in a header, not just the status line.

A config that parses as valid JSON but names a chart type QuickChart doesn't support behaves differently. Sending c={"type":"nope"} returned 200, not 400. The response is a real PNG, 2,424 bytes. Decoding it gives a 1000x600 RGBA canvas, and all 600,000 of its pixels hold the same value: zero red, zero green, zero blue, zero alpha. The image is fully transparent, with no opaque pixel anywhere. QuickChart sized and encoded a chart surface, then drew nothing on it. Composite that PNG onto a dark page and it leaves no mark.

That 200 response carries no x-quickchart-error header at all, even though every response lists that header as available in access-control-expose-headers. A caller that checks only the status code, or only the error header, sees success. Only opening the image shows that nothing rendered.

No rate-limit header shows up on any call

The entry's rateLimit field cites a cap of 60 charts a minute and 1,000 a month on the free tier. That figure comes from QuickChart's FAQ, which also gives the burst rate as 1 chart a second. The pricing page says only that a rate limit applies. Five rapid GET calls to /qr this session, sent back to back, all returned 200. None carried a rate-limit, retry-after, or quota header.

This does not prove there is no cap. It only shows that QuickChart, like Fiscal Data in issue thirteen, does not surface one in its response headers. A caller has no way to see, from the response alone, how close a burst of calls comes to the free tier's monthly ceiling.

QuickChart, by the numbers

Rendered live from the atlas entry
AuthenticationNone required
HTTPSSupported
CORSEnabled
PricingFreemium
FormatsPNG, SVG, PDF, WEBP
Rate limit

60 charts/min & 1,000 charts/month on the free tier; the $40/month Professional plan lifts both limits

Key endpoints
  • GET/chart
  • GET/qr
chartqr-codechart.jsopen-sourceimage-generation

Sources

Facts checked Aug 2026