Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsThe native way to convert a web page to PDF in Swift is to render it in WKWebView, wait until your navigation has reached the state you want to capture, and call WebKit’s asynchronous PDF API. Use createPDF(configuration:completionHandler:) with a completion handler or try await webView.pdf(configuration:) in an async context. Both return PDF bytes as Data; you can write those bytes to a file, present a share sheet, or upload them.
This approach works for remote URLs, local files, and HTML strings. The examples below use UIKit and make the loading and error paths explicit. WebKit’s PDF configuration controls which portion of the web view is captured, but it does not by itself give you a print-layout system with guaranteed paper sizes, margins, headers, or footers.
Choose the PDF approach
| Requirement | Best starting point | Why |
|---|---|---|
| The app already displays a web page | WKWebView plus WebKit PDF generation |
Captures the rendered contents, including HTML and JavaScript output that has loaded. |
| You prefer structured concurrency | try await webView.pdf(configuration:) |
Returns Data or throws, so it fits an async task. |
| You use delegate-style UIKit code | createPDF(configuration:completionHandler:) |
Keeps completion handling in one callback. |
| You must draw custom print pages | UIPrintPageRenderer |
UIKit’s printing abstraction lets a subclass override page drawing; it is a different route from direct WebKit PDF generation. |
| You are building with SwiftUI WebKit APIs | WebView/WebPage after checking your SDK |
These abstractions integrate WebKit with SwiftUI, but the direct PDF-export recipe and availability surface differ by deployment target. |
Check the exact availability of each method against the SDK and deployment targets used by your app. The API names and asynchronous behavior are established, but a single minimum-OS statement should not be assumed for every project.
Build a UIKit converter with WKWebView
1. Create and load the web view
A web view can load a server URL with URLRequest. For a local document, use WebKit’s local-file or HTML-loading methods instead. Keep a strong reference to the view; it must remain alive while navigation and PDF generation are in progress.
#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
import UIKit
import WebKit
final class WebToPDFViewController: UIViewController {
private let webView = WKWebView(frame: .zero)
private var pendingURL: URL?
private var didFinishLoading = false
override func loadView() {
view = webView
}
func loadPage(at url: URL) {
pendingURL = url
didFinishLoading = false
webView.navigationDelegate = self
webView.load(URLRequest(url: url))
}
}
extension WebToPDFViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
didFinishLoading = true
// Start export here, or enable an Export button for the user.
}
func webView(_ webView: WKWebView,
didFail navigation: WKNavigation!,
withError error: Error) {
print("Navigation failed: (error.localizedDescription)")
}
func webView(_ webView: WKWebView,
didFailProvisionalNavigation navigation: WKNavigation!,
withError error: Error) {
print("Initial load failed: (error.localizedDescription)")
}
}
For a production app, configure the web view before loading if you need custom JavaScript behavior, cookies, or a particular user-agent. The navigation delegate tells you that the main navigation finished; it does not guarantee that every lazy image, late network request, animation, or application-specific render step is complete.
2. Generate PDF with a completion handler
Create a WKPDFConfiguration, then call WebKit’s asynchronous method. Handle both the returned data and the error path.
func exportWithCompletion(completion: @escaping (Result<Data, Error>) -> Void) {
guard didFinishLoading else {
let error = NSError(domain: "WebToPDF", code: 1,
userInfo: [NSLocalizedDescriptionKey:
"The page has not finished loading."])
completion(.failure(error))
return
}
let configuration = WKPDFConfiguration()
webView.createPDF(configuration: configuration) { result in
DispatchQueue.main.async {
switch result {
case .success(let data):
completion(.success(data))
case .failure(let error):
completion(.failure(error))
}
}
}
}
The callback is asynchronous. Do not assume that calling the method immediately after load produces a complete document, and do not block the main thread while waiting.
3. Generate PDF with async/await
In an async context, the throwing API is concise and works naturally with task cancellation and do/catch.
func exportWithAsync() async throws -> Data {
guard didFinishLoading else {
throw NSError(domain: "WebToPDF", code: 1,
userInfo: [NSLocalizedDescriptionKey:
"The page has not finished loading."])
}
let configuration = WKPDFConfiguration()
return try await webView.pdf(configuration: configuration)
}
@MainActor
func exportAndShare() {
Task {
do {
let pdfData = try await exportWithAsync()
let url = FileManager.default.temporaryDirectory
.appendingPathComponent("web-page.pdf")
try pdfData.write(to: url, options: .atomic)
let controller = UIActivityViewController(activityItems: [url],
applicationActivities: nil)
present(controller, animated: true)
} catch {
print("PDF export failed: (error.localizedDescription)")
}
}
}
Present UIKit UI on the main actor. Writing to the temporary directory is convenient for a share sheet; move the file into your app’s Documents directory when it must persist between launches.
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⁴
Coordinate capture with page readiness
PDF creation is asynchronous, but WebKit’s PDF API does not establish a universal “all resources are finished” guarantee. Choose a readiness signal appropriate to the page:
- Start from
WKNavigationDelegate’sdidFinishfor ordinary documents. - If your page has a known application-ready condition, evaluate JavaScript such as a page-owned flag before exporting.
- For lazy-loaded content, scroll or trigger the page’s own loading mechanism before capture, then verify that images appear.
- Disable or wait for transitions when a moving layout would make output inconsistent.
- Inspect the resulting PDF for missing fonts, images, authentication redirects, or an error page.
These checks are application policy rather than a promise from WebKit. A page can report navigation complete while it continues making requests or rendering client-side content.
Load local HTML instead of a URL
When the source is an HTML string, load it directly and provide a base URL so relative stylesheets, images, and scripts resolve correctly.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →let html = "<html><body><h1>Invoice</h1></body></html>"
let baseURL = Bundle.main.resourceURL
webView.loadHTMLString(html, baseURL: baseURL)
For a local file, use WebKit’s file-loading API and grant access to the directory containing resources. Export only after the navigation delegate indicates that the document loaded.
What WKPDFConfiguration does—and does not do
WKPDFConfiguration specifies the portion of the web view to capture. Treat it as a capture-region control, not a replacement for a full print-layout engine. The available evidence does not establish a universal mapping for paper sizes, margins, page ranges, headers, footers, or pagination behavior across SDKs and deployment targets.
Rank #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.
If your requirement is custom page drawing—such as placing a logo in a fixed header, drawing a page number, or composing several views—use UIPrintPageRenderer. Subclass it and override its drawing methods, accepting that this is a UIKit printing workflow rather than a direct snapshot of WebKit’s rendered page.
SwiftUI and newer WebKit abstractions
WebKit also provides SwiftUI-oriented WebView and WebPage abstractions. They are useful when the rest of the feature is SwiftUI, but do not assume that their export behavior is identical to WKWebView.pdf(configuration:). The exact APIs and availability depend on the SDK and deployment targets you support. If you need a predictable PDF data pipeline today, keep the rendering and export path explicit and verify the relevant SDK documentation for your target platforms.
Recommended Free Tools
Save, share, or upload the PDF data
Persist it in the app
func savePDF(_ data: Data, named name: String = "page.pdf") throws -> URL {
let documents = try FileManager.default.url(
for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
let destination = documents.appendingPathComponent(name)
try data.write(to: destination, options: .atomic)
return destination
}
Share it
Pass a file URL to UIActivityViewController, as shown above. A URL is preferable to a large in-memory Data object for sharing and lets the system provide the appropriate document activity.
Upload it
Use URLSession with a request whose body is the returned PDF data, or write the data to a temporary file and use an upload task for larger documents. Keep network credentials out of page JavaScript and handle upload cancellation separately from PDF-generation errors.
Common failures and fixes
The PDF is blank or shows an error page
- Confirm the web view actually loaded the intended URL rather than a redirect, login page, or bot-check page.
- Export only after your navigation/readiness condition, not immediately after calling
load. - Check the generated bytes by opening the PDF and log the final URL and navigation errors.
Images or web fonts are missing
- Verify that relative URLs have a correct base URL for local HTML.
- Wait for the page’s own lazy-loading logic and test on the same network conditions your users have.
- Check that authentication cookies and resource requests are available to the web view.
Output differs between devices
Viewport size, scale, fonts, media queries, and platform rendering can change the result. Set the web view’s frame and configuration deliberately, avoid relying on animation timing, and validate representative devices and SDKs.
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
The method is unavailable for the deployment target
Check the method declaration in the SDK you compile against and gate newer APIs with availability checks. If a target cannot use the async method, use the completion-handler variant when available, or maintain a separate compatibility path.
The app needs exact pagination and margins
Direct WebKit PDF generation may not provide the print controls your design requires. Move the layout into a print-oriented implementation with UIPrintPageRenderer, or generate a dedicated print HTML layout and verify its output on every supported target.
Performance, reliability, and privacy
- PDF generation runs asynchronously, but rendering still consumes memory and CPU; avoid exporting many large pages concurrently on a memory-constrained device.
- Reuse a configured web view when appropriate, but clear sensitive state between users or documents.
- Set timeouts and cancellation around navigation and export at the task level; WebKit’s PDF call itself should not be treated as an infinite operation.
- Do not claim success merely because you received nonempty data. Validate that the document contains the expected page content.
- Remote pages can contain personal data. Apply your app’s cookie, authentication, logging, and file-retention policies to both the web view and the generated PDF.
Or skip the browser setup
If your goal is an automated screenshot or PDF endpoint rather than an on-device WebKit document, ScreenshotNeo provides a single request to render a URL. Its cleanup steps accept cookie/consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. It also includes an MCP server for AI agents such as Claude and Cursor, with take_screenshot, get_page_info, and capture_pdf tools.
For the full parameter list, see the ScreenshotNeo documentation. A PDF response can be requested from the same API base; this simple image example shows the request shape:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo offers 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots. Every feature is included on every plan, including full-page capture, element selection, device presets, custom CSS and JavaScript, request blocking, cookies and headers, caching, signed links, asynchronous jobs, bulk capture, usage data, and PDF options. Create a free ScreenshotNeo account to try it.
Frequently Asked Questions
Can I export a PDF before didFinish?
You can call the API earlier, but the result may represent an incomplete page. Use a readiness condition appropriate to the site and inspect the output.
Does WebKit automatically add print margins and headers?
Do not assume it does. WKPDFConfiguration controls the captured web-view portion; custom print composition belongs in a print-oriented implementation such as UIPrintPageRenderer.
Should I use the completion handler or async/await?
Use the style that matches your app’s concurrency model. They are two asynchronous entry points for generating PDF data from the web view.
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.

