Cracking the Challenge of Automating PDF Downloads in Playwright
Automation always comes with surprises. Recently, I stumbled upon one such challenge while working on a scenario that required automating PDF download using Playwright to verify a PDF download functionality. Sounds straightforward, right? At first, I thought so too. But the web application I was dealing with had other plans.
The Unexpected Complexity

Instead of a simple file download, the application displayed the report PDF inside an iframe. Looking deeper, I noticed a blob source associated with the PDF. Initially, it felt promising—maybe I could just fetch the blob and save it. But soon, I realized the blob didn’t actually contain the full PDF file. It only represented the layout instructions, not the content itself.
Things got more interesting (and complicated) when I found out that the entire PDF was rendered inside a canvas. The content wasn’t static—it was dynamically displayed page by page. This meant I couldn’t directly extract or save the file from the DOM.
At this point, downloading the PDF programmatically felt like chasing shadows.
The Print Button Dilemma

To make matters trickier, the only straightforward option available on the page was the print button. Clicking it triggered the system’s file explorer dialog, asking me to manually pick a save location. While that works fine for an end-user, for automation purposes it was a dealbreaker.
I didn’t want my automation scripts to depend on manual interaction. The whole point of this exercise was to make the process seamless and repeatable.
Digging Deeper: A Breakthrough

After exploring multiple dead ends, I finally turned my focus back to Playwright itself. That’s when I discovered something powerful—Playwright’s built-in capability to generate PDFs directly from a page.
The key was:
- Wait for the report to open in a new tab (triggered by the app after selecting “Print View”).
- Bring this new page into focus and make sure all content was fully rendered.
- Use Playwright’s page.pdf() function to export the page as a properly styled PDF file.
The Solution in Action
Here’s the snippet that solved it:
// Wait for new tab to open and capture it
const [newPage] = await Promise.all([
context.waitForEvent("page"),
event.Click("(//span[text()='OK'])[1]", page), // triggers tab open
]);
global.secondPage = newPage;
await global.secondPage.bringToFront();
await global.secondPage.waitForLoadState("domcontentloaded");
// Use screen media for styling
await global.secondPage.emulateMedia({ media: "screen" });
// Path where you want the file saved
const downloadDir = path.resolve(__dirname, "..", "Downloads", "Reports");
if (!fs.existsSync(downloadDir)) fs.mkdirSync(downloadDir, { recursive: true });
const filePath = path.join(downloadDir, "report.pdf");
// Save as PDF
await global.secondPage.pdf({
path: filePath,
format: "A4",
printBackground: true,
margin: {
top: "1cm",
bottom: "1cm",
left: "1cm",
right: "1cm",
},
});
console.log(`✅ PDF saved to: ${filePath}`);Key Highlights of the Implementation

- Capturing the New Tab
The Print/PDF Report option opened the report in a new browser tab. Instead of losing control, we captured it with context.waitForEvent(“page”) and stored it in a global variable global.secondPage. This ensured smooth access to the report tab for further processing. - Switching to Print View
The dropdown option was switched to Print View to ensure the PDF was generated in the correct layout before proceeding with export. - Emulating Screen Media
To preserve the on-screen styling (instead of print-only styles), we used page.emulateMedia({ media: “screen” }). This allowed the generated PDF to look exactly like what users see in the browser. - Saving the PDF to a Custom Path
A custom folder structure was created dynamically using Node.js path and fs modules. The PDFs were named systematically and stored under Downloads/ImageTrend/<date>/, ensuring organized storage. - Full-Page Export with Print Background
Using Playwright’s page.pdf() method, we captured all pages of the report (not just the visible one), along with background colors and styles for accurate representation. - Clean Tab Management
Once the PDF was saved, the secondary tab (global.secondPage) was closed, bringing the focus back to the original tab for processing the next incident report.
What I Learned

This challenge taught me something new: PDFs in web apps aren’t always what they seem. Sometimes they’re iframes, sometimes blob objects, and in trickier cases, dynamically rendered canvases. Trying to grab the raw file won’t always work.
But with Playwright, there’s a smarter way. By leveraging its ability to generate PDFs from a live-rendered page, I was able to bypass the iframe/blob/canvas complexity entirely and produce consistent, high-quality PDF files.
Conclusion:
What started as a simple “verify PDF download” task quickly turned into a tricky puzzle of iframes, blobs, and canvases. But the solution I found—automating PDF download using Playwright with its built-in PDF generation—was not just a fix, it was an eye-opener.
It reminded me once again that automation isn’t just about tools; it’s about understanding the problem deeply and then letting the tools do what they do best.
This was something new I learned, and I wanted to share it with all of you. Hopefully, it helps the next time you face a similar challenge.
Click here to read more blogs like this.
Top-Tier SDET | Advanced in Manual & Automated Testing | Skilled in Full-Spectrum Testing & CI/CD | API & Mobile Automation | Desktop App Automation | ISTQB Certified
