# HTML to PDF in Bubble Convert HTML to PDF in Bubble with the API Connector. Set up the call, pass dynamic HTML, get a PDF link back and save it to a file field. Bubble apps often need to hand users a document, such as an invoice, a quote, a certificate or a report. Bubble has no built-in HTML-to-PDF action, so most apps either use a plugin or call a PDF API through the API Connector. This guide covers the API Connector route. It gives you full control over the layout with your own HTML and CSS. **Quick answer:** in the API Connector, add a `POST` call to `https://html-pdf.com/v1/pdf` with the header `Authorization: Bearer YOUR_API_KEY` and this JSON body. The response contains a `url` to the PDF. ```json { "html": , "response": "url" } ``` ## Native options and their limits This section covers what you can do without an API, and why it falls short. - **Browser print.** You can open a page and let the user "Print → Save as PDF". The result depends on the user's browser, includes page chrome, and can't run in a backend workflow. - **PDF plugins.** Several marketplace plugins convert a page or a group to PDF in the browser. Many rasterize the screen into an image, so text isn't selectable and long content splits awkwardly. A server-side Chromium render avoids both problems. You get selectable text, real page breaks, headers and footers, and it works in backend workflows. ## Step 1: get an API key First, create a free account. Sign up at https://html-pdf.com/login. You get 100 free credits (1 credit = 1 PDF page), and purchased credits never expire. ## Step 2: add the API in the API Connector Next, register html-pdf.com as an API with your key. Install the **API Connector** plugin (by Bubble), then click **Add another API** and fill in these values. - **API Name:** `html-pdf` - **Authentication:** `Private key in header` - **Key name:** `Authorization` - **Key value:** `Bearer YOUR_API_KEY` A private key in header stays on Bubble's server and is never exposed to the browser. ## Step 3: configure the call Now add the call that renders the PDF. Name it `Render PDF` and use these settings. - **Use as:** `Action` (so it appears in workflows) - **Data type:** `JSON` - **Method / URL:** `POST` `https://html-pdf.com/v1/pdf` - **Headers:** `Content-Type` = `application/json` - **Body type:** `JSON` Use this body. ```json { "html": , "format": "A4", "margin": "15mm", "print_background": true, "filename": "document.pdf", "response": "url" } ``` `` creates a dynamic parameter. Uncheck **Private** next to it so you can set it from workflows. Bubble inserts the value as-is, so it must be a valid JSON string including the quotes. When you set it in a workflow, use the dynamic expression with `:formatted as JSON-safe`, which adds the quotes and escapes characters like `"` and line breaks. ### Why `"response": "url"` By default the API returns raw PDF bytes. Bubble's API Connector expects a JSON (or text) response and won't turn binary data into a file. With `"response": "url"` the API returns JSON instead. ```json { "url": "https://...", "expires_at": "..." } ``` The link is valid for 24 hours, which is plenty for Bubble to download it into its own storage. ## Step 4: initialize the call Bubble needs one test request to learn the response shape. Give the `html` parameter a test value such as `"

Hello from Bubble

"` (with the quotes, since it's raw JSON here) and click **Initialize call**. Bubble sends a real request (it uses 1 credit) and shows the detected fields. Confirm that `url` is a text field and save. If initialization fails, the response body explains why. Errors look like `{"error": {"code", "message", "hint"}}`, for example `401` for a wrong key or `402 insufficient_credits` when your balance is empty. ## Step 5: use it in a workflow Here is a typical "Download invoice" button workflow. 1. **Plugins → html-pdf - Render PDF**, with `html` set to your HTML. Build it with Bubble's text editor and dynamic data, for example `

Invoice Current Page Invoice's Number

...`, then apply `:formatted as JSON-safe` to the whole expression. 2. **Make changes to a thing** on the invoice. Set its `PDF` (file field) to `Result of step 1's url`. Bubble saves the file from the URL into its own storage so it outlives the 24-hour link. If your editor doesn't accept a URL for a file field directly, store the URL in a text field and save the file with a file-upload plugin, or save it in a backend workflow. 3. Optional: **Open an external website** with `Result of step 1's url` to let the user download it immediately, or **Send email** with the link. The same call works in **backend workflows** (API workflows). You can generate PDFs on a schedule or when data changes, without a user on the page. ## Building the HTML These tips help your template print cleanly. Keep your template in an option set, a text field, or a "template" thing, and fill in dynamic values with Bubble expressions. - Use inline `