C H P R H E A LT H — I N T E R N A L T E C H N I C A L D O C U M E N T
WhatsApp Chart
Renderer
How to integrate and test the chart-renderer sidecar service
from the n8n workflow editor — no terminal access required.
This document covers what the service does, how to wire it into your
existing n8n data-dump workflow, and how to verify it is working
correctly — all from the n8n web interface at [Link]
v1.1.0 update: Puppeteer (headless Chrome) is now available as a
second rendering engine — screenshot any HTML report directly as a
PNG.
VERSION SERVICE URL D AT E
INTERNAL USE ONLY
1.1.0 [Link] May 2026
SECTION 01
What This Service Does
Currently, your data-dump reports are sent to Microsoft Teams as HTML cards and to
WhatsApp as plain text. The HTML renders beautifully on Teams but loses all formatting on
WhatsApp, making the statistics hard to read.
The chart-renderer solves this by converting the report statistics into a clean PNG chart
image that WhatsApp displays inline — no tapping to open, no broken markup.
HOW IT WORKS
Your n8n workflow sends the report statistics to the chart-renderer as JSON. The service
returns a PNG image with up to three color-coded bar chart panels. Your workflow then
sends WhatsApp a short plain-text summary plus the PNG as an attachment.
Available Rendering Endpoints
The service exposes two rendering engines — choose the one that fits your workflow.
Endpoint Engine Input Best for
/render- [Link] + Structured Auto-colored bar charts from report
dump- node-canvas JSON statistics — fast, lightweight (~30–80 KB)
charts (buckets,
counts)
/render- Puppeteer Raw HTML Screenshot any existing styled HTML
html (headless string or a report exactly as it would appear in a
Chrome 148) URL browser
/health — GET, no Confirm service is running — returns
body {"ok":true,"version":"1.1.0"}
Message Split: What Goes Where
Part Format Contains
WhatsApp Plain text Site, uploader, timestamp, project, file name, key
message body percentages (OOH %, Missing %, avg delay)
Attached image PNG (~30– Three bar charts: Submission Delay buckets, Screening
80 KB) Time-of-Day, Missing Compulsory % by form
Automatic Color Coding
The charts apply traffic-light colors automatically — you do not need to configure anything.
Orange — Red — Action
Chart Panel Green — Good
Watch needed
Submission Delay 0d 1–2d — 3–7d 8–14d 15+d
Screening Time-of- 08–12 — <08:00 ≥14:00
Day
12–14
Missing Compulsory Below 1% 1–5% ≥ 5%
chart-renderer v1.1.0 — CHPR Internal Section 01 — Overview
SECTION 02
Wiring Into Your Workflow
All steps below are performed inside the n8n editor at [Link] Open your
existing data-dump workflow before starting.
WHERE TO INSERT
Add the new "Render Charts" node after your existing Code node that produces the report
statistics, and before your WhatsApp send node.
1 Add a new HTTP Request node
Click the
"+"
button between your Code node and the WhatsApp node. Search for
"HTTP Request"
and select it. Name it Render Charts.
2 Configure the node settings
Fill in the fields exactly as shown below:
HTTP Request Node — Settings
Method POST
URL [Link]
charts
Body Content Type JSON
Specify Body Using JSON
Response Format File
Binary Property Name data
3 Set the JSON body
In the
JSON Body
field, paste the expression below. This maps the statistics your Code node already
produces to the chart renderer:
{{
{
submissionDelay: $[Link],
screeningQuality: $[Link],
missingCompulsoryByForm: $[Link]
}
}}
4 Update your WhatsApp send node
Change your existing WhatsApp node to use the afkanerd media endpoint (multipart form-
data) instead of the plain message endpoint:
Set the
file
field to the binary data property from the Render Charts node
Put your plain-text summary in the
caption
field
C A P T I O N F O R M AT
Keep the caption concise — site, timestamp, project, and the three key
percentages. The image carries the detail. Example:
DATA DUMP — 2PIT_HD_PITOA | GATAKOUITA_PAUL
12 May 2026 05:21 PM — Wave11 Plus PID 88
OOH: 36% Missing: 0.2% Avg delay: 0.8d
[chart attached]
5 Handle the "no data" case
Add an
IF node
after the Render Charts node:
Condition: HTTP status code equals 204
True branch
→ send WhatsApp text-only (no attachment)
False branch
→ send WhatsApp with PNG attached
chart-renderer v1.1.0 — CHPR Internal Section 02 — Wiring
SECTION 03
Testing From n8n Interface
Run these four tests in order from the n8n editor before going live. No terminal or server
access is needed.
Test 1 — Verify the Service is Reachable
Create a quick one-off workflow to confirm n8n can talk to the chart-renderer.
1 Create a new blank workflow
Click
+ New Workflow
and name it chart-renderer health check.
2 Add Manual Trigger + HTTP Request node
HTTP Request Node — Health Check
Method GET
URL [Link]
Response Format JSON (default)
3 Click "Test Workflow" and inspect the output
Click the HTTP Request node to see its result panel.
PASS — Service is up
✓
Output shows: { "ok": true }
FAIL — Connection error
✗
You see "connection refused" or "bad address" — contact your sysadmin.
Test 2 — Full Chart Render
Confirm the renderer produces a valid PNG from a sample payload.
1 Add a second HTTP Request node to the same test workflow
HTTP Request Node — Chart Render Test
Method POST
URL [Link]
charts
Body Content Type JSON
Response Format File
Binary Property data
2 Paste this sample payload into the JSON Body field:
{
"submissionDelay": {
"sample": 30,
"buckets": [
{ "label": "0d", "count": 7 },
{ "label": "1-2d", "count": 23 },
{ "label": "3-7d", "count": 0 },
{ "label": "8-14d", "count": 0 },
{ "label": "15+d", "count": 0 }
]
},
"screeningQuality": {
"sample": 30, "outOfHoursPct": 36,
"timeOfDay": [
{ "label": "<08:00", "count": 0 },
{ "label": "08-12", "count": 10 },
{ "label": "12-14", "count": 4 },
{ "label": ">=14:00", "count": 16 }
]
},
"missingCompulsoryByForm": [
{ "form": "Screening", "missingPct": 0.24 },
{ "form": "Specimen1", "missingPct": 3.5 }
]
}
3 Run and inspect the output
PASS — PNG returned
✓ Output shows a binary data property with type image/png , file size 25–80 KB.
You can click the download icon to save and open the image.
FAIL — JSON error body returned
✗ Check your JSON payload for missing fields or wrong data types. The error field
in the response describes the exact issue.
FAIL — Response Format shows text/JSON instead of binary
Response Format in the node settings must be set to
✗
File
, not JSON.
chart-renderer v1.1.0 — CHPR Internal Section 03 — Testing
SECTION 03 — CONTINUED
Testing (continued) & Troubleshooting
Test 3 — Empty Payload Returns No Image
Confirm the workflow handles the case where there is no chart data gracefully.
1 Add another HTTP Request node with an empty body
HTTP Request Node — Empty Payload Test
Method POST
URL [Link]
charts
JSON Body {}
Response Format File
2 Run and check the result
PASS — HTTP 204, no binary data
✓ The node returns successfully with no data property — your IF node should route
this to text-only WhatsApp.
Test 4 — End-to-End on Your Live Workflow
1 Open your existing data-dump workflow
Make sure you have already added the "Render Charts" node and updated the WhatsApp
node as described in Section 02.
2 Click "Test Workflow"
Use a known test dump file so you can predict the expected output values.
3 Check each node output in sequence
Code node
— must output submissionDelay , screeningQuality , and
missingCompulsoryByForm fields
Render Charts node
— must output a binary data property of type image/png
WhatsApp node
— must show a success response from afkanerd
4 Verify on the WhatsApp test number
The message should arrive with the plain-text caption visible immediately and the chart
image displayed inline below it — no tapping required to view.
Test 5 — Puppeteer HTML Screenshot
Test the /render-html endpoint by sending a raw HTML string and confirming a PNG comes
back.
1 Add an HTTP Request node — "Render HTML (Puppeteer)"
HTTP Request Node — Puppeteer Test
Method POST
URL [Link]
Body Content Type JSON
Response Format File
Binary Property data
2 Paste this sample JSON body:
{
"html": "<html><body style='background:#0f3460;color:white;font-
family:sans-serif;padding:40px'><h1>CHPR Report</h1><p>Puppeteer test —
OK</p></body></html>",
"width": 1200,
"height": 800,
"fullPage": true
}
3 Run and inspect the output
PASS — PNG returned
✓ Binary data property of type image/png . Download it — you should see the
dark-blue HTML page rendered as an image.
FAIL — HTTP 500 / Chromium error
✗
Contact your sysadmin. The Puppeteer engine may need a container restart.
Troubleshooting Quick Reference
What you see in n8n Likely cause What to do
"Could not connect" Service is down or Contact your sysadmin — the
/ "bad address" unreachable chart-renderer container may need
restarting
HTTP 500 with Malformed request payload Check your Code node outputs all
JSON error body three fields. Read the error
value in the response.
HTTP 204, no binary All payload arrays are empty Your Code node is not populating
returned statistics — check its logic for this
dump
Output type is Response Format not set to Open the Render Charts node →
JSON/text, not File set Response Format to File
image
WhatsApp receives Binary property name Confirm WhatsApp node
text but no image mismatch references data (the binary
property set in Render Charts)
Image arrives but is All bucket counts are zero At least one bucket must have a
blank/white non-zero count for a panel to
render
Puppeteer: first Chromium cold start (browser Normal on first call after a
request takes 3–5 s not yet launched) container restart. Subsequent calls
are fast (~200 ms).
Puppeteer: fullPage is false and Set "fullPage": true in the
screenshot cuts off content is taller than height JSON body, or increase height
content
Puppeteer: external HTML references external Inline all styles and images in the
fonts/images URLs; waitFor: HTML string, or use "waitFor":
missing networkidle0 timed out "load"
chart-renderer v1.1.0 — CHPR Internal Section 03 — Testing & Troubleshooting
SECTION 04
Puppeteer Endpoint Reference
The /render-html endpoint uses Puppeteer with headless Chromium 148 to take a full
screenshot of any HTML content and return it as a PNG. Use this when you already have a
styled HTML report and want to send it as an image instead of building charts from scratch.
W H E N T O U S E P U P P E T E E R V S C H A R T. J S
Use /render-dump-charts when you have structured statistics (buckets, counts,
percentages) and want clean auto-colored charts — it is faster and produces smaller files.
Use /render-html when you already have a designed HTML report (like your Teams card)
and want to screenshot it exactly as-is for WhatsApp.
Request Body Fields
Field Required Default Description
html One of — Full HTML string to render. Inline your
html or CSS — external stylesheets may not
url load.
url One of — A URL for Puppeteer to navigate to and
html or screenshot. Must be reachable from the
url server.
width No 1200 Viewport width in pixels. Affects how the
HTML lays out.
height No 800 Viewport height in pixels. Only relevant
when fullPage is false.
fullPage No true Screenshot the full scrollable page
height. Set to false to capture only the
viewport.
waitFor No networkidle0 When to take the screenshot: load ,
domcontentloaded , or
networkidle0 (wait until no network
activity for 500 ms).
Wiring /render-html Into a Workflow
The setup is identical to the [Link] endpoint — only the URL and body fields differ. Place an
HTTP Request node after the node that produces your HTML string.
HTTP Request Node — Puppeteer HTML Render
Method POST
URL [Link]
Body Content Type JSON
Specify Body Using JSON
Response Format File
Binary Property Name data
Sample JSON body expression (when your Code node outputs an htmlReport field):
{
"html": {{ $[Link] }},
"width": 1200,
"fullPage": true,
"waitFor": "networkidle0"
}
Performance Characteristics
[Link] (/render-dump-
Metric Puppeteer (/render-html)
charts)
First request (cold) 80–150 ms 3–5 s (Chromium launch)
Subsequent requests 80–150 ms 150–400 ms (browser reused)
Output file size 30–80 KB 100–500 KB (depends on
HTML)
Memory usage ~80 MB ~250 MB (Chromium running)
Handles custom fonts/CSS Limited (node-canvas) Full browser rendering
Renders charts/SVG in No Yes — anything Chrome
HTML renders
I M A G E S I Z E O N W H AT S A P P
Puppeteer screenshots of full-page HTML reports can exceed 500 KB. WhatsApp delivers
large images fine, but they may load slowly on clinic sites with limited mobile data. For
bandwidth-sensitive deployments, prefer /render-dump-charts or crop the screenshot
using the fullPage: false + height fields to capture only the summary section of your
report.
chart-renderer v1.1.0 — CHPR Internal Section 04 — Puppeteer Reference