To add JavaScript stored in a Python string to a generated PDF, create the PDF first, then attach the string as a PDF JavaScript action. A practical Python workflow is to generate the document with ReportLab and use pypdf’s add_js(javascript) method to add a document-level script that runs when the PDF opens. Writing JavaScript text onto a page is not enough: it must be embedded as an action, and the PDF viewer must permit scripts to run.
How the Python string becomes executable PDF JavaScript
A PDF does not execute JavaScript just because a script appears in a Python variable or as visible text on a page. The string has to be stored in the PDF as the payload of a JavaScript action. PDF 32000-1:2008 describes that action with an S value of JavaScript and a JS value containing the script as a text string or stream. The standard defines the file structure; it does not guarantee that a particular viewer will execute the action.
For a Python-generated PDF, separate the job into two stages:
- Use ReportLab to create the pages and, if needed, interactive AcroForm fields.
- Open the saved PDF with pypdf, call
add_js()with the Python string, then write the modified PDF.
This example adds a document-open alert. It is deliberately simple: it verifies that the action is present without making changes to a form or relying on a specific field name.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →#1 Best Overall
- INNOVATIVE CARTRIDGE-FREE PRINTING — No more dealing with lots of tiny ink cartridges; With this wireless document and photo printer each ink bottle set is equivalent to about 90 individual cartridges²
- LESS FREQUENT INK REPLACEMENT — Replacement ink bottles don't have to be changed nearly as often as ink cartridges¹; When you choose this combination printer, scanner and copier you can print up to 4,500 pages black/7,500 color³
- COLOR PRINTING — Up to 2 years of ink in the box4 (and with every replacement ink set) for fewer out-of-ink frustrations
- ZERO CARTRIDGE WASTE — By using an Epson EcoTank printer you can help reduce the amount of cartridge waste ending up in landfills
- HOME PRINTER DESIGNED FOR RELIABILITY — The Epson EcoTank ET-2800 All-in-One Supertank Color Printer creates vivid, detailed prints and documents thanks to Micro Piezo Heat-Free Technology; Fire off 10 ISO pages per minute1 to easily finish large jobs
Runnable example: ReportLab plus pypdf
Install the libraries in the Python environment that will run the script:
python -m pip install reportlab pypdf
Save the following as make_pdf.py and run python make_pdf.py. It creates hello-with-js.pdf in the current directory.
from pathlib import Path
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from pypdf import PdfReader, PdfWriter
output_path = Path("hello-with-js.pdf")
base_path = Path("hello-base.pdf")
# Keep the JavaScript source in an ordinary Python string.
js = "app.alert('Hello from this PDF.');"
# Stage 1: generate the PDF with ReportLab.
c = canvas.Canvas(str(base_path), pagesize=letter)
c.setTitle("PDF with a JavaScript action")
c.setFont("Helvetica", 12)
c.drawString(72, 720, "This PDF has a document-level JavaScript action.")
c.drawString(72, 700, "Open it in a viewer that permits PDF JavaScript to test it.")
c.save()
# Stage 2: attach the script as a document-level open action.
reader = PdfReader(str(base_path))
writer = PdfWriter()
writer.append(reader)
writer.add_js(js)
with output_path.open("wb") as output_file:
writer.write(output_file)
print(f"Wrote {output_path.resolve()}")
The intermediate hello-base.pdf is the ReportLab output; hello-with-js.pdf is the file with the added action. Keep the intermediate file if you want to inspect or regenerate either stage, or remove it after a successful write if your workflow does not need it.
Change the script without changing the PDF-generation stage
Replace the value of js with the JavaScript you intend the viewer to run. For example, a multiline script can be represented with a triple-quoted Python string:
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →js = """
app.alert('Review this document before submitting it.');
"""
For JavaScript containing quotes, either escape them in the Python string or use a different Python quote style. Python evaluates the string first; pypdf then places its contents in the PDF action. Avoid concatenating untrusted input into executable script text. If a value must be inserted, validate it and encode it for the JavaScript context rather than assuming that ordinary string formatting is safe.
Add AcroForm fields when the PDF needs user input
ReportLab can create AcroForm widgets such as text fields, checkboxes, radio buttons and choice controls. A widget and a document-level JavaScript action are distinct PDF features: making a field does not automatically attach a script to it. The example above attaches JavaScript that runs on document open; it does not attach a field-specific calculation, validation or mouse action.
Rank #2
- CARTRIDGE-FREE PRINTING — Print lab-quality photos, graphics and creative projects; Get vibrant colors and sharp text with Epson's high-accuracy printhead and Claria ET Premium 6-color inks
- INK BOTTLES — Save on photos1 and creative projects with affordable in-house printing; All-in-one printer allows you to print 4" x 6" photos for about 4 cents each vs. 40 cents with traditional ink cartridges1
- LESS FREQUENT INK REPLACEMENT — Replacement ink bottles don't have to be changed nearly as often as ink cartridges¹; Printer, scanner and copier lets you print up to 6,200 color pages³
- PRINT FOR LONGER — Up to 2 years of ink in the box² (and with every replacement ink set) for fewer out-of-ink frustrations with this wireless printer
- ZERO CARTRIDGE WASTE — Epson EcoTank printer helps reduce the amount of cartridge waste ending up in landfills; Cartridge-free printer uses high-yield ink bottles; Each replacement ink bottle set is equivalent to about 100 individual ink cartridges⁴
ReportLab’s own documentation cautions that its interactive support covers only a fraction of the PDF standard. If your design depends on a particular field trigger or more advanced interactive behavior, verify that the generation library supports that feature before building the rest of the workflow around it.
What pypdf’s add_js() does—and what it does not
pypdf documents add_js(javascript: str) as a way to add JavaScript that launches when the PDF is opened. That makes it useful for a document-level open action after another library has created the file. It is not a Python JavaScript engine, a browser runtime or a promise that code will run in every PDF reader.
Keep the distinction between three operations clear:
- Store script text: a Python string holds the source code in memory.
- Embed an action: pypdf writes a PDF JavaScript action into the document.
- Execute the action: a PDF viewer decides whether it supports and permits that action.
The third step happens outside Python, when someone opens the PDF. A successful call to writer.write() only establishes that the output file was written; it does not establish that a viewer executed the code.
Can WeasyPrint execute JavaScript while converting HTML to PDF?
WeasyPrint documents an HTML-string workflow using HTML(string=...).write_pdf(...) and can produce PDFs with optional form support. The cited documentation describes HTML and CSS rendering, not a browser-style JavaScript runtime that executes arbitrary JavaScript during PDF generation. If the content must be computed before rendering, calculate it in Python and pass the resulting HTML to WeasyPrint. If you need a PDF JavaScript action, attach an action using a PDF library after generation and test it in the target viewer.
Do not treat JavaScript included in HTML as equivalent to a PDF JavaScript action. The former would need a rendering engine that executes page scripts; the latter is an action stored in the PDF for a compatible viewer to handle. Also treat untrusted HTML and CSS as security-sensitive input: WeasyPrint’s documentation warns that they can create security problems.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsRank #3
- SET IT UP ONCE AND PRINT WITH CONFIDENCE. No complicated maintenance. Just easy, reliable printing you can count on.
- INK FOR YEARS. NOT MONTHS. Up to 2 years of ink included. Get thousands of pages of cartridge-free printing. More pages, less hassle
- KEEPS PRINTING WELL AFTER COMPETITORS HAVE QUIT. No complex maintenance. Sharper text, richer colors.[2] Only with HP Smart Tank
- PREMIUM SUPPORT - Strong technical expertise to solve issues faster
- THE LAST PRINTER YOU'LL EVER NEED. Enjoy years of refillable, cartridge-free printing.
Choose the right library for the task
| Tool or specification | Use it for | Important limit |
|---|---|---|
| ReportLab | Generating PDF pages directly in Python and creating supported AcroForm widgets. | Its documentation says interactive support covers only a fraction of PDF capabilities. |
| pypdf | Post-processing a generated PDF with a document-level JavaScript action through add_js(javascript: str). |
It adds the action; viewer support and security policy determine whether it runs. |
| WeasyPrint | Rendering HTML/CSS to PDF with HTML(string=...).write_pdf(...), including optional PDF forms. |
The cited documentation does not describe arbitrary JavaScript execution during rendering. |
| PDF 32000-1:2008 | Understanding the standardized structure of a JavaScript action in a PDF. | It defines the format, not a Python API or identical behavior across viewers. |
Testing and deployment: check the viewer, not just the file
- Write the final PDF. Confirm the Python process completes and that the output file exists and is non-empty.
- Open it in the actual target viewer. Test the readers your recipients are expected to use, rather than relying only on a PDF parser or one desktop application.
- Check JavaScript policy. The viewer or organization may disable PDF JavaScript or restrict actions for security reasons. Use the deployment environment’s policy and do not instruct users to bypass protections casually.
- Test the intended action and fallback. Check what a recipient sees if the viewer ignores the script. The document should remain understandable and usable without the action unless the workflow explicitly requires a compatible viewer.
- Retest after changing libraries or viewers. The PDF standard defines the action model, but it does not make behavior identical across applications.
For automated checks, inspect the generated PDF’s structure with a PDF library or parser to verify that an action is present, then perform a separate manual or controlled viewer test for execution. Structural inspection cannot establish that a recipient’s viewer will permit the action.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Common problems and fixes
The script appears on the page but does not run
Text drawn with ReportLab is page content, not an executable action. Pass the source string to writer.add_js(js) after generating the PDF, then save the writer’s output. Confirm you are opening the post-processed file rather than the intermediate ReportLab PDF.
The Python script runs, but no alert appears
Writing the file does not run its JavaScript. Try the output in a viewer that supports PDF JavaScript, and check whether JavaScript is enabled by that viewer’s settings or organizational policy. An alert is only a test action; its absence does not by itself prove the file is malformed.
The script works in one reader but not another
Viewer behavior and security settings are external to pypdf’s API. Test the applications and versions relevant to your recipients. If consistent execution cannot be established, move essential logic to the Python generation stage or provide a non-script-dependent document path.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
A field is present but does not trigger the expected code
add_js() attaches a document-level open script, not a field-specific event handler. Confirm the required trigger is supported by the library and the viewer; ReportLab documents only partial interactive-PDF support. Do not assume that creating a text field also binds it to the document-open script.
The PDF is missing, incomplete or cannot be opened
Check that the ReportLab canvas is saved before reading base_path, that the Python process has permission to write the destination, and that the code opens the output in binary mode. If a previous run left an incomplete file after an exception, regenerate the base PDF and post-process it again; validate the final artifact before distributing it.
Rank #4
- Wireless Bluetooth Printer: Portable thermal printer compatible with iPhone, Android phones, iPad and tablet computers via Bluetooth. For smartphones, please download the "Nada Print" App. You can also connect to laptops and computers for printing using a USB-C cable. (Note: Laptops and computers can only be connected via USB and require the installation of a driver first. Bluetooth connection is not supported.)
- No-ink printing: Only supports US Letter and A4 size thermal paper.(Doesn't support regular paper) The no-ink portable thermal printer uses direct thermal technology, requiring no ink, toner or ribbons, making it environmentally friendly, cost-effective and time-saving. The thermal printer package comes with a roll of US Letter thermal printing paper. Note: When installing the paper, remember to switch the paper size switch on APP
- Clear Print: NDYIN N80 portable thermal printer adopts high-definition printing technology, with a 203DPI resolution to provide you with clear printing results. This mobile printer is compatible with roll paper, folded paper and tattoo transfer paper, supporting printing from your mobile phone PDF, Word, pictures and web pages anytime and anywhere. It is recommended to use our NDYIN thermal paper to achieve good printing quality
- Portable wireless printer for travel: The thermal printer is equipped with a built-in 1500mAh rechargeable battery, which can print 160 sheets of 8.5" x 11" thermal paper after being fully charged. It weighs only 1.5 pounds and is compact in size. This ink-free portable printer can be easily carried in a backpack or briefcase! It is perfect for business travel, cars, small offices, construction sites, schools and homes. You can print documents, contracts, invoices and boarding passes anytime and anywhere
- The N80 thermal printer has a wide range of uses. The package includes the N80 printer, a roll of US Letter paper(7m/roll), a user manual, a guide card, a type-C soft cable and a type C adapter. Note: The charging adapter is not included. Special thermal paper is required for use; ordinary paper cannot be used. This ink-free portable thermal printer is suitable for various scenarios such as home, school, travel, office, and outdoor, meeting the printing needs of different groups of people. This tattoo template printer is also compatible with tattoo transfer paper, making it an ideal choice for tattoo art
HTML JavaScript is not reflected in a WeasyPrint PDF
The documented HTML-string-to-PDF path is not documented as a browser-style JavaScript execution environment. Compute dynamic values in Python before rendering, or use a PDF action if the requirement is to have a compatible viewer run code after the file is opened.
Security and reliability considerations
PDF JavaScript is active content. A viewer may restrict it, and recipients may use readers with different policies. Limit scripts to the behavior the document genuinely needs, avoid embedding secrets, and do not assume a script can safely read or modify data in every viewer. Treat scripts derived from user input as code injection risk, just as you would in another executable context.
For dependable business workflows, keep essential calculations, validation and data handling in the Python application before producing the PDF where possible. Use an embedded action for viewer-side behavior only when that behavior is appropriate and you can define a supported-reader expectation. This reduces dependence on a recipient’s settings without overstating what the PDF format or a Python API can guarantee.
Or skip the browser setup
If your actual goal is to capture a webpage as a screenshot rather than embed arbitrary JavaScript in a PDF generated by Python, ScreenshotNeo is a separate API option. It does not replace the ReportLab-plus-pypdf method for attaching your own PDF JavaScript action. Its one-request screenshot flow can return an image or PDF, and its MCP server provides screenshot tools for AI agents.
For a screenshot capture, install requests and use the documented Python request pattern below. See the ScreenshotNeo API documentation for setup and request details.
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
- Cookie banners and consent prompts are accepted or removed before capture; newsletter popups and chat widgets are also removed, and each step can be turned off.
- Bot checks, blank pages, failed loads, timeouts and cache hits are not billed; response headers report the page verdict and billing status.
- An MCP server exposes screenshot tools for AI agents, including Claude, Cursor and other MCP clients.
- The Free plan includes 1,000 screenshots a month without a card; paid plans start at $5 for 3,000 screenshots.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
Recommended Free Tools
Frequently Asked Questions
Does embedding a PDF JavaScript action execute the script on the server?
No. The Python code writes the action into the PDF; execution, if allowed, occurs in a PDF viewer when the document is opened.
Can I use this approach with a PDF created by another Python library?
Yes, if the generated file can be read and rewritten by pypdf; add the action after the PDF-generation stage and then validate the rewritten file.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

