I’m self-hosting on Ubuntu (and sometimes Amazon Linux 2023). Trying to use puppeteer from the code module to render HTML into PDF. It almost always fails to start. But after a couple of tries it works and then keeps working. Any suggestions?
I’ve tried inserting an execute command module with sudo snap refresh --edge chromium before the code module. I have no idea if that has any effect. Doesn’t seem to help or hurt. Mostly just indicates that I don’t know what I’m doing.
Here’s the script in the code module. Maybe there’s another puppeteer call I need to make before I start trying to render anything?
Any help would be great. Thanks!
Lee
const puppeteer = require('puppeteer');
// Create a browser instance
const browser = await puppeteer.launch({ headless: true, executablePath: "/snap/bin/chromium", args: ['--disable-gpu', '--disable-setuid-sandbox', '--no-sandbox', '--no-zygote']});
// Create a new page
const page = await browser.newPage();
// To reflect CSS used for screens instead of print
await page.emulateMediaType('print');
//Get HTML content from HTML file
await page.setContent($input.item.json.html, { waitUntil: 'domcontentloaded' });
// Downlaod the PDF
const pdf = await page.pdf({
path: `/tmp/${$input.item.json.client.invoiceNum}.pdf`,
margin: { top: '1in', right: '1in', bottom: '1in', left: '1in' },
printBackground: true,
format: 'Letter',
landscape: true
});
// Close the browser instance
await browser.close();
return $input.item;
Information on your n8n setup
n8n version: 1.64.3
Database (default: SQLite): Postgres
n8n EXECUTIONS_PROCESS setting (default: own, main): main
Running n8n via (Docker, npm, n8n cloud, desktop app): npm
Have you tried to launch puppeteer outside of n8n to see if there are any prompts or anything else that needs to be done? I have tried to use puppeteer once and I think I had to set an option for it to work. There is a puppeteer community node have you tried using that instead?
Great suggestion @Jon ! Just tried that and didn’t see anything too wonky. But it gives me an avenue to explore that I hadn’t thought of.
For example, in my script I use await page.setContent($input.item.json.html, { waitUntil: 'domcontentloaded' });
to actually render the page. I wonder if I’m waiting for the wrong thing.
Another thing I should probably do is insert an annoying number of console.log lines to see where it’s stalling. That might illuminate where it’s running into problems.
Anyway, I’ll report back if/when I figure this out. Thanks again for your help!
Edit /etc/apparmor.d/chrome-snap and change the executable to /snap/bin/chromium
sudo service apparmor reload
Next, when you call chromium from the code module it’ll help to add a few command line args. I have no idea if this is a good or even complete list, but it seems to work for me.
After that, here’s how I render the HTML that’s in $json.html in landscape mode.
// Create a new page
const page = await browser.newPage();
// To reflect CSS used for screens instead of print
await page.emulateMediaType('print');
//Get HTML content from HTML file
await page.setContent($input.item.json.html);
await waitTillHTMLRendered(page);
// Downlaod the PDF
const pdf = await page.pdf({
path: `/tmp/${$input.item.json.client.invoiceNum}.pdf`,
margin: { top: '1in', right: '1in', bottom: '1in', left: '1in' },
printBackground: true,
format: 'Letter',
landscape: true
});
// Close the browser instance
await browser.close();
return $input.item;
That puts the pdf in /tmp, and you can use the read files module to pull it into the N8N flow.