Chart Image Generator: Chart.js & ECharts to PNG, SVG, PDF avatar

Chart Image Generator: Chart.js & ECharts to PNG, SVG, PDF

Pricing

Pay per event

Go to Apify Store
Chart Image Generator: Chart.js & ECharts to PNG, SVG, PDF

Chart Image Generator: Chart.js & ECharts to PNG, SVG, PDF

Turn data or a Chart.js or ECharts config into chart images: PNG, SVG, PDF, WebP or JPEG. Bar, line, pie, scatter, candlestick, sankey and more, from labels and values, CSV, JSON or an Apify dataset. A QuickChart alternative for AI agents.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Jumble Mog

Jumble Mog

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

12 days ago

Last modified

Security

Limited permissions

Share

Turn data into chart images. Send a Chart.js config, an Apache ECharts option, or just your data (labels and values, CSV, JSON rows, a link to a data file, or the dataset of another Actor run), and get back a clean chart as PNG, SVG, PDF, WebP or JPEG with a download link. Bar, line, area, pie, doughnut, scatter, radar, mixed bar and line, candlestick, sankey, treemap, heatmap, box plot, word cloud, gauge and more. It reads the same Chart.js configs as QuickChart, including old Chart.js 2 configs, so it works as a pay-per-chart QuickChart alternative that people, automations and AI agents can call.

Six charts made by this Actor: grouped bars with dollar labels, a dark area chart of weekly visits, a doughnut of traffic sources, a candlestick chart of a share price, a sankey diagram of where visits go, and an ECharts radar chart comparing two laptops

What it does

  • Chart.js configs: {"type": "bar", "data": {...}, "options": {...}}, drawn with Chart.js 4. Chart.js 2 configs (the version QuickChart uses by default, and what many AI models write) are converted automatically: xAxes and yAxes, horizontalBar, top-level title and legend, scaleLabel, gridLines, ticks.beginAtZero, cutoutPercentage, lineTension and v2 annotations. Configs written as JavaScript can contain functions, such as tick and label formatters.
  • Plugins included: data labels, annotations (lines, boxes, labels), time axes, candlestick and OHLC (financial), matrix (heatmaps), sankey, treemap, box plot and violin, and word cloud charts.
  • Apache ECharts options: line, bar, pie, scatter, radar, gauge, funnel, heatmap, treemap, sunburst, sankey, candlestick, box plot, graph, parallel, theme river and calendar charts, with ECharts' own light and dark themes.
  • Charts from plain data, no config needed: labels with one or more series, CSV or TSV text, JSON rows, an Apify dataset ID, or a link to a CSV or JSON file or a public Google Sheet. Pick the label and value fields (nested fields like stats.views work), add up, count, average or take the min or max of rows that share a label, sort, and keep the top N. Dates become a time axis, and a series can be a line over bars or use a second axis.
  • Styled by default: a left-aligned title and subtitle, round legend markers, soft grid lines, rounded bars, and value labels with your prefix, suffix and decimals ($1,200, 45%, 3.5 kg).
  • Five formats: PNG at 1x to 4x pixel density, SVG and PDF as vector files that stay sharp at any size, lossless WebP, and JPEG. One charge per chart, whatever the number of formats.
  • Look: light or dark theme, any background color or transparent, six palettes (including a colorblind-safe one) or your own colors, 13 fonts, and number and date formats for any locale (de-DE writes 1.234,5).
  • Emoji and every script: color emoji, Chinese, Japanese and Korean, Greek and Cyrillic in titles, labels and legends.
  • Errors that say what to fix: an unknown chart type lists the ones that exist, a broken config gives the JavaScript error and line, a missing field lists the fields in your data. Failed charts are free.
  • Image straight from the API: the first chart is also the run's OUTPUT, so the run-sync endpoint answers with the image itself.

Who it's for

  • AI agents and LLM apps that answer with a chart: write a Chart.js config (most models know the format) or pass the numbers, and show the image in a chat, report, email or slide.
  • Automation builders in n8n, Make or Zapier who send weekly KPI charts to Slack, email or Notion.
  • Apify users who want to see their scraped data: chart prices, ratings, review counts or items per category straight from a scraper's dataset.
  • Developers who need server-side chart images without running a browser, or a QuickChart replacement priced per chart.

How to use it

  1. Paste a Chart.js config or an ECharts option into Chart config, or fill in Labels and Series, or paste a CSV into CSV data.
  2. Choose a chart type, title, theme and colors, or keep the defaults.
  3. Click Start. The chart appears in the Output tab with its download link.

For many charts in one run, put them in More charts. You can also run it through the Apify API, on a schedule, or from Make, n8n, Zapier and other integrations.

Input

FieldWhat it does
chartA Chart.js config (type, data, options) or an ECharts option (series, xAxis, ...).
chartCodeThe same kind of config as JavaScript text, which may contain functions. Markdown code fences are removed.
engineauto (default), chartjs or echarts.
chartsMore charts: configs, configs as text, or objects with chart (or data fields) and their own settings, such as {"chart": {...}, "name": "sales", "width": 1200}.
chartTypeFor charts from data: bar (default), horizontalBar, stackedBar, horizontalStackedBar, line, area, stackedArea, pie, doughnut, polarArea, radar or scatter.
labels, series, valuesLabels with named series ([{"name": "Sales", "values": [3, 5]}], optionally with "type": "line", "axis": "right" and "color"), or one list of values.
csv, data, datasetId, dataUrlData as CSV or TSV text, JSON rows, the ID of an Apify dataset (up to 100,000 items), or a link to a public CSV or JSON file or Google Sheet (up to 10 MB).
xField, yFieldsThe field with the labels and the fields with the values. Default: the first text column and every number column.
aggregate, sortBy, limitCombine rows with the same label (auto, none, sum, count, average, min, max), sort (valueDesc, valueAsc, label) and keep the top N.
title, subtitle, xAxisTitle, yAxisTitleText for charts made from data.
showValues, valuePrefix, valueSuffix, decimalsWrite the values on the chart, and how numbers look.
legend, beginAtZero, smoothLegend position or none, the value axis starting at zero (default on), and curved lines.
width, heightChart size in CSS pixels (800 x 450 by default, up to 4,000 each).
theme, backgroundlight (default) or dark, and any CSS color or transparent.
palette, colorstableau10 (default), colorblind, vivid, pastel, chartjs or echarts, or your own list of colors.
fontFamily, fontSize, localeInter (default), Roboto, Open Sans, Lato, Montserrat, Poppins, Source Sans 3, Noto Sans, IBM Plex Sans, Nunito, Arial, Noto Serif or JetBrains Mono; the base size (12 px); and the number and date locale (en-US).
formats, scaleAny of png (default), svg, pdf, webp and jpg, and the pixel density of PNG, WebP and JPEG (2 by default).
name, inlineImage, maxChartsThe files' name, the image as a base64 data URI in the results, and the most charts per run (100).

The data, title and value settings in the form belong to the chart in the form; every chart in More charts has its own. The look and output settings apply to every chart unless a chart sets its own. A chart in More charts that sets only chartType, xField, yFields, aggregate or sortBy uses the form's data, so one dataset or CSV can be drawn several ways in one run.

A Chart.js config, the way QuickChart takes it:

{
"chart": {
"type": "bar",
"data": {
"labels": ["Jan", "Feb", "Mar", "Apr"],
"datasets": [{"label": "Revenue", "data": [120, 190, 170, 240]}, {"label": "Costs", "data": [80, 110, 95, 130]}]
},
"options": {"plugins": {"title": {"display": true, "text": "Revenue and costs"}}}
}
}

A chart from a scraper's dataset: the ten brands with the most products, largest first:

{
"datasetId": "YOUR_DATASET_ID",
"xField": "brand",
"aggregate": "count",
"sortBy": "valueDesc",
"limit": 10,
"chartType": "horizontalBar",
"title": "Products per brand",
"showValues": true
}

A CSV, with the rows of each region added up:

{
"csv": "region,product,revenue\nNorth,Widget,1200\nSouth,Widget,950\nNorth,Gadget,800\nEast,Widget,640",
"xField": "region",
"chartType": "doughnut",
"title": "Revenue by region",
"showValues": true,
"valuePrefix": "$"
}

Orders as bars with the conversion rate as a line on a second axis:

{
"labels": ["Jan", "Feb", "Mar", "Apr"],
"series": [
{"name": "Orders", "values": [320, 410, 380, 520]},
{"name": "Conversion (%)", "values": [2.1, 2.4, 2.2, 2.9], "type": "line", "axis": "right"}
],
"title": "Orders and conversion rate"
}

An ECharts gauge on the dark theme:

{"chart": {"series": [{"type": "gauge", "data": [{"value": 72, "name": "Score"}]}]}, "theme": "dark"}

How-to examples

Each example below is a complete input, checked with a run of the Actor.

How to turn a Chart.js config into a PNG image (a QuickChart alternative)

{
"chart": {"type": "bar",
"data": {"labels": ["Jan", "Feb", "Mar", "Apr"],
"datasets": [{"label": "Revenue", "data": [120, 190, 170, 240]},
{"label": "Costs", "data": [80, 110, 95, 130]}]},
"options": {"plugins": {"title": {"display": true, "text": "Revenue and costs"}}}},
"formats": ["png", "svg"]
}

Result: a grouped bar chart as a 1600 x 900 PNG (800 x 450 at 2x) in pngUrl and a vector SVG in svgUrl, made in about 1.4 seconds.

How to make a line chart from CSV data

{"csv": "Week,Visits\n2026-09-07,1200\n2026-09-14,1350\n2026-09-21,1610\n2026-09-28,1580\n2026-10-05,1900",
"chartType": "line", "title": "Weekly visits", "theme": "dark"}

Result: a dark line chart. The dates become a time axis (Sep 7 to Oct 5), so gaps between weeks are drawn to scale. A link to a CSV file or a public Google Sheet works the same way in dataUrl.

How to chart scraped data: count items per category

Give JSON rows here, or the datasetId of a scraper run:

{"data": [{"brand": "Acme", "price": 19.99}, {"brand": "Bolt", "price": 24.5}, {"brand": "Acme", "price": 22.0},
{"brand": "Cora", "price": 9.99}, {"brand": "Acme", "price": 15.0}, {"brand": "Bolt", "price": 31.0}],
"xField": "brand", "aggregate": "count", "sortBy": "valueDesc", "limit": 10,
"chartType": "horizontalBar", "title": "Products per brand", "showValues": true}

Result: horizontal bars Acme 3, Bolt 2, Cora 1, largest first, with the counts written on the bars. Use "aggregate": "average" and "yFields": ["price"] for the average price per brand instead.

How to let an AI agent answer with a chart

Add this Actor to the Apify MCP server with https://mcp.apify.com/?tools=jumblemog/chart-image-generator. Most models already write Chart.js configs, including old Chart.js 2 ones, which are converted. The agent sends the config in chart and shows the user imageUrl. A broken config comes back with the JavaScript error and line, so the agent can fix it and try again.

FAQ

Can it replace QuickChart? Yes, for drawing images. It reads the same Chart.js configs, including Chart.js 2 ones, and you pay per chart instead of a monthly plan.

Which chart types are there? Bar, line, area, pie, doughnut, scatter, radar, mixed bar and line, candlestick, sankey, treemap, heatmap, box plot, word cloud and gauge, plus every Apache ECharts chart.

Can I get SVG or PDF? Yes. formats takes any of png, svg, pdf, webp and jpg, and one chart costs the same whatever the number of formats.

Can I get the image itself from the API? Yes. The first chart is also the run's OUTPUT, so the run-sync endpoint answers with the image.

Does it work with Zapier, Make or n8n? Yes. Call the Actor with its Apify app or an HTTP request, then send imageUrl to Slack, email or Notion.

Output

Each chart becomes one dataset item, and the files are saved in the run's key-value store:

{
"index": 1,
"name": "revenue",
"status": "ok",
"error": null,
"engine": "chartjs",
"chartType": "bar",
"imageUrl": "https://api.apify.com/v2/key-value-stores/<store>/records/001-revenue.png",
"pngUrl": "https://api.apify.com/v2/key-value-stores/<store>/records/001-revenue.png",
"svgUrl": null,
"pdfUrl": null,
"webpUrl": null,
"jpgUrl": null,
"width": 1600,
"height": 900,
"dataPoints": 8,
"sourceUrl": null,
"notes": [],
"processingSeconds": 0.21
}

When a chart can't be drawn, the item says why and isn't billed:

{
"index": 2,
"status": "failed",
"error": "\"bars\" isn't a Chart.js chart type this tool knows. Use one of: bar, line, pie, doughnut, radar, polarArea, scatter, bubble, candlestick, ohlc, matrix, sankey, treemap, boxplot, violin, wordCloud.",
"imageUrl": null
}

Download your files within your plan's data retention period, or copy them to your own storage, because run storage expires.

Pricing

You pay per chart created, at the price shown on this page, whatever the number of formats (PNG, SVG, PDF, WebP and JPEG of the same chart count once). Charts that can't be drawn are never charged. If you set a maximum cost per run, the Actor stops when the next chart wouldn't fit.

Speed

One chart usually takes 3 to 4 seconds through the API, from request to image, most of it the run starting up. Each further chart in the same run adds about 0.2 to 0.7 seconds as PNG, or 1 to 2 seconds with all five formats (sankey and word cloud charts take longer). On Apify more memory also means more CPU, so give big batches 2 GB or more to draw them faster.

Tips and limits

  • Chart.js configs given as JSON can't contain functions; send the config as JavaScript text in chartCode (or as a string in charts) when it has formatters or callbacks. Text that isn't valid JSON is read as JavaScript.
  • Images inside configs (point styles, ECharts image symbols and graphics) and data URLs inside configs aren't loaded: the renderer has no network access. Give the data in the config, or use the data fields.
  • ECharts maps (which need GeoJSON registered first) and 3D charts (ECharts GL) aren't available. For Vega-Lite specs, Mermaid diagrams and Graphviz graphs, use the Diagram Renderer Actor.
  • Chart.js SVG files have their text turned into outlines, so they look the same everywhere; color emoji show in PNG, WebP, JPEG and PDF files but not in Chart.js SVGs. ECharts SVG files keep text as text in the chosen font.
  • Data: up to 100,000 dataset items, files up to 10 MB, 10,000 labels and 20 series per chart. Each chart has a 60-second limit.
  • Datasets: Apify lets this Actor read only the dataset picked in its Apify dataset field (datasetId at the top of the input), so charts in More charts can use that dataset but no other. To chart several datasets, run once per dataset.
  • Candlestick and OHLC points take x as a date (text such as 2026-09-01, or a timestamp in milliseconds or seconds) with o, h, l and c prices, and are put in time order. [time, open, high, low, close] lists work too.
  • Data file links: CSV, TSV and JSON files, GitHub file links, and Google Sheets links (the sheet must be shared as "Anyone with the link" or published to the web; a gid in the link picks the tab). Every site's robots.txt is checked first, and its crawl delay kept.

For AI agents and developers

This Actor works with the Apify MCP server, so AI agents can call it as a tool: pass a Chart.js config in chart (or labels and series) and read imageUrl from the dataset item. For a direct API call that waits for the result:

curl -X POST "https://api.apify.com/v2/acts/jumblemog~chart-image-generator/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"chart": {"type": "line", "data": {"labels": ["Mon", "Tue", "Wed"], "datasets": [{"label": "Visits", "data": [120, 180, 150]}]}}}'

To get the image itself as the response, call run-sync instead. It returns the run's OUTPUT, which is the first chart (or the error as JSON):

curl -X POST "https://api.apify.com/v2/acts/jumblemog~chart-image-generator/run-sync?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"labels": ["A", "B", "C"], "values": [3, 7, 5], "chartType": "doughnut", "showValues": true}' \
-o chart.png

Credits