Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteUse a browser-backed renderer rather than trying to “print” HTML yourself. For a raw HTML string in Go, the most practical documented workflow is to upload it as index.html to Gotenberg’s Chromium HTML endpoint through its Go client, then stream the returned PDF. This handles modern CSS, web fonts, images and JavaScript more reliably than legacy renderers, while keeping browser processes outside your application.
Choose the right conversion route
Your input determines the API route:
| Input | Recommended route | Why |
|---|---|---|
| Raw HTML string plus local or uploaded assets | Gotenberg HTML conversion | Uploads an index.html document and renders it with Headless Chromium. |
| A live URL or JavaScript-driven single-page application | Gotenberg URL conversion | Chromium loads the page, executes its JavaScript and waits for the application to render. |
| Existing workload proven to work with an older renderer | wkhtmltopdf | Uses Qt WebKit through a command-line tool or C library; it is a separate rendering engine with different CSS and JavaScript behavior. |
Do not send a raw string to the URL route and expect identical behavior. The HTML route represents your string as an uploaded document. The URL route makes a network request and therefore has different access, security and loading characteristics.
Prerequisites and document preparation
- Run a Gotenberg instance whose version matches the Go client documentation you are using.
- Keep the complete document in the string: include
<!doctype html>,<html>,<head>, styles and a<body>. - Use
html/templatefor production templates so interpolated values are escaped as HTML. - Make images, stylesheets and fonts available through paths the renderer can reach. When uploading a document and assets, relative paths are generally easier to reason about than development-machine absolute paths.
- Decide the paper size, margins, orientation, scaling, background printing and header/footer behavior before validating the output.
Generate safe HTML with html/template
Keep presentation in a template and data in a struct. Do not concatenate untrusted values into markup.
package main
import (
"html/template"
"os"
)
type Invoice struct {
Number string
Total string
}
func renderHTML() (string, error) {
const source = `<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
@page { size: A4; margin: 18mm; }
body { font-family: sans-serif; color: #222; }
</style>
</head>
<body>
<h1>Invoice {{.Number}}</h1>
<p>Total: {{.Total}}</p>
</body>
</html>`
t, err := template.New("invoice").Parse(source)
if err != nil { return "", err }
var out bytes.Buffer
err = t.Execute(&out, Invoice{Number: "INV-1001", Total: "$125.00"})
return out.String(), err
}
func main() {
html, err := renderHTML()
if err != nil { panic(err) }
_ = os.Stdout
_ = html
}
Add bytes to the imports in that example. The important result is a complete string, not a fragment such as only the contents of <body>.
#1 Best Overall
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Convert the string with the Gotenberg Go client
The client flow is: create a document named index.html from the string, create an HTML request, then send or store the response.
package main
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"os"
"time"
"github.com/gotenberg/gotenberg-go-client/v8"
"github.com/gotenberg/gotenberg-go-client/v8/document"
)
func main() {
rawHTML := `<!doctype html>
<html><head><meta charset="utf-8">
<style>@page { size: A4; margin: 18mm; } body { font-family: sans-serif; }</style>
</head><body><h1>Hello from Go</h1><p>Generated as a PDF.</p></body></html>`
index, err := document.FromString("index.html", rawHTML)
if err != nil { panic(fmt.Errorf("create HTML document: %w", err)) }
req := gotenberg.NewHTMLRequest(index)
// Set the options supported by your pinned client version here, for example:
// req.PaperSize("A4")
// req.Margins(18, 18, 18, 18)
// req.Landscape()
// req.PrintBackground(true)
// req.PreferCSSPageSize(true)
client := gotenberg.NewClient("http://localhost:3000")
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
defer cancel()
resp, err := client.Send(ctx, req)
if err != nil { panic(fmt.Errorf("convert HTML: %w", err)) }
defer resp.Body.Close()
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
panic(fmt.Errorf("Gotenberg returned %s: %s", resp.Status, bytes.TrimSpace(body)))
}
f, err := os.Create("output.pdf")
if err != nil { panic(err) }
defer f.Close()
if _, err := io.Copy(f, resp.Body); err != nil { panic(fmt.Errorf("save PDF: %w", err)) }
}
The exact constructor and option method names are version-sensitive. Pin the client and server versions together, then check that matching client documentation before compiling. The stable concepts are document.FromString("index.html", rawHTML), gotenberg.NewHTMLRequest(index), and sending the request to a running service.
Return the PDF from an HTTP handler
Streaming avoids holding a second full copy of a large PDF in memory.
func pdfHandler(w http.ResponseWriter, r *http.Request) {
rawHTML, err := renderHTMLForRequest(r)
if err != nil { http.Error(w, "template error", http.StatusInternalServerError); return }
index, err := document.FromString("index.html", rawHTML)
if err != nil { http.Error(w, "document error", http.StatusInternalServerError); return }
req := gotenberg.NewHTMLRequest(index)
ctx, cancel := context.WithTimeout(r.Context(), 90*time.Second)
defer cancel()
resp, err := gotenbergClient.Send(ctx, req)
if err != nil { http.Error(w, "PDF conversion failed", http.StatusBadGateway); return }
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
http.Error(w, "renderer returned an error", http.StatusBadGateway); return
}
w.Header().Set("Content-Type", "application/pdf")
w.Header().Set("Content-Disposition", `inline; filename="document.pdf"`)
if _, err := io.Copy(w, resp.Body); err != nil {
// The client may have disconnected; log the error rather than writing another response.
log.Printf("stream PDF: %v", err)
}
}
Control layout and rendering
Page geometry
Set paper dimensions, margins, orientation and scale in the request or CSS. If your design uses @page, enable the client option that prefers CSS page size when your pinned version exposes it. Validate both the CSS and request settings: a request-level paper size can override a stylesheet.
Recommended Free Tools
Rank #2
Backgrounds, headers and footers
Background colors and images often require an explicit print-background option. Headers and footers are separate templates or request fields in the Chromium module; reserve margin space so they do not overlap the body. Test long titles, page numbers and empty header values.
Images, fonts and relative assets
A browser can only render an asset it can read. Upload supporting files as the client allows, or serve them from an address reachable by Gotenberg. Check font licensing and confirm that the font actually loaded rather than silently falling back. For deterministic output, bundle assets and avoid dependencies on a developer laptop’s filesystem.
JavaScript and asynchronous content
The HTML route uses Headless Chromium, but a document that starts network requests or timers may be captured before it is ready. Use the module’s wait controls—such as a selector wait or a deliberate delay—based on the page’s actual behavior. Configure handling for failed resources and console exceptions so a missing image or script does not silently produce an incomplete invoice.
HTML route versus URL route
Use the HTML route for a string you already own. Use the URL route when the source is a live page, an SPA, or a page whose JavaScript must run from its normal origin. The URL route introduces network access, authentication and remote-resource failure modes; apply the same wait and timeout discipline. If you need to convert untrusted URLs, add an allowlist and network controls before exposing that capability to users.
Rank #3
Alternative: wkhtmltopdf
wkhtmltopdf is an open-source command-line tool and C library built on Qt WebKit and licensed LGPLv3. It can be a reasonable choice for an existing, tested workload that already matches its renderer. It is not interchangeable with Chromium: CSS support, JavaScript behavior, font handling and pagination can differ. The available material does not establish a current performance winner or browser-feature parity, so measure your own documents before changing engines.
Reliability, security and performance checklist
- Timeouts: bound both the Go request context and the renderer’s page waits; never allow an unbounded browser job.
- Concurrency: size conversion concurrency for your CPU and memory limits. Browser processes can be expensive; use a queue rather than allowing unlimited simultaneous jobs.
- Isolation: run the conversion service separately from the API handling user traffic and restrict its outbound network access when HTML is untrusted.
- Input limits: cap HTML size, asset count, render time and output size. Reject unexpected schemes such as local-file URLs where your deployment does not need them.
- Observability: record request duration, status, page count and renderer errors, but avoid logging confidential HTML or credentials.
- Determinism: pin versions, bundle fonts and assets, set a timezone where supported, and avoid content that changes between runs.
- Validation: compare PDFs visually and extract text in automated tests. Include long tables, page breaks, right-to-left text, missing assets and a slow JavaScript case.
Troubleshooting common failures
“Document not found” or a rejected multipart request
The HTML route requires an uploaded file named index.html. Ensure the client’s FromString call uses that exact name and that the request is sent to the Chromium HTML route.
PDF is blank or missing late content
The page was captured before rendering finished, or a script failed. Add a selector wait or measured delay, inspect browser console/resource errors, and make sure the required assets are reachable from the Gotenberg container.
Images or fonts disappear
Replace machine-local absolute paths with uploaded files or reachable URLs, verify case-sensitive filenames, and confirm that the renderer can resolve relative paths from index.html.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Styles look different from Chrome
Confirm the Gotenberg/Chromium version, print-background setting, paper and margin options, and whether CSS page size is being honored. Remove unsupported browser assumptions and test the exact production renderer.
The Go request hangs
Set a context deadline, inspect renderer health and container logs, and look for a page waiting on an unavailable resource. A network-idle wait can be inappropriate for pages with analytics or long-lived connections; prefer a readiness selector or bounded delay.
Large documents exhaust memory
Reduce concurrency, stream the response, limit asset dimensions and split exceptionally large jobs. Do not build multiple byte copies of the same HTML and PDF unless required by your API.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If your HTML is available at a URL, ScreenshotNeo can return a PDF with one request. It accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets before capture; bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server also gives Claude, Cursor and other MCP clients take_screenshot, get_page_info and capture_pdf tools.
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 →curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://your.example.com/invoice/1001
-d format=pdf
-o invoice.pdf
See the ScreenshotNeo API documentation for the available parameters. You can also use the same endpoint from Go:
Best Value
resp, err := http.Get("https://api.screenshotneo.com/v1/shot?access_key=YOUR_API_KEY&url=https%3A%2F%2Fyour.example.com%2Finvoice%2F1001&format=pdf")
if err != nil { return err }
defer resp.Body.Close()
out, err := os.Create("invoice.pdf")
if err != nil { return err }
defer out.Close()
_, err = io.Copy(out, resp.Body)
return err
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. Create a free ScreenshotNeo account.
Frequently Asked Questions
Can I convert an HTML fragment instead of a complete document?
You can, but wrap it in a complete HTML document with a doctype, head and body so page styles, fonts and print rules are predictable.
Should I wait for network idle on every page?
No. Pages with analytics or persistent connections may never become idle. A readiness selector or bounded delay is usually a better match for the page’s actual loading behavior.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Does Gotenberg guarantee accessible or tagged PDFs?
The cited material describes rendering and layout controls but does not establish a tagged-PDF or accessibility guarantee. Validate the generated files against your accessibility requirements.
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.

