McAPI - HTML to PDF Converter API with Swift

Swift sample code to convert websites and plain HTML to a PDF document with the McAPI HTML to PDF Converter REST API service. We provide an iOS Playground that you can use for testing, download. The sample uses Swift 5, the playground requires Xcode 12.4 or higher.

Requirements: A free RapidAPI account. Replace YOUR_API_KEY in the code below with your RapidAPI key.

All samples below work with the free tier of the API, see the McAPI HTML to PDF API Listing for available plans.

See the overview page for a reference that lists all available parameters and error codes.

Convert invoices, package lists, delivery notes and other business documents from HTML to PDF with Swift

In the first Swift snippet we'll convert this invoice from HTML to PDF, a common application of HTML to PDF conversion. We set the paper size to "A4" and the storeExternal parameter to "true"; the PDF will then be stored on McAPI cloud servers and the API returns a downloadable URL (If you plan to store the returned URLs, keep in mind that server-stored PDFs are deleted after 30 days.)

The Swift source code. The relevant parts are the headers and parameters arrays, the code around NSMutableURLRequest is Swift boilerplate for doing POST requests:

// Swift 5

import Foundation
import UIKit

let headers = [
  "content-type": "application/json",
  "x-rapidapi-key": "YOUR_API_KEY",
  "x-rapidapi-host": "mcapi-html-2-pdf.p.rapidapi.com"
]

let parameters = [
  "url": "https://mcapi.io/html2pdf/templates/invoice.html",
  "storeExternal": "true",
  "format": "A4"
] as [String : Any]

let postData = try JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://mcapi-html-2-pdf.p.rapidapi.com/")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  }
  else {
    let httpResponse = response as? HTTPURLResponse
    if httpResponse?.statusCode == 200{
      if let data = data{
        ...
      }
    }
    else{
      // handle 400 errors here, see documentation for possible error conditions
    }
  }
})

dataTask.resume()

The PDF's URL will be delivered as a JSON object in data, see further below for sample code that shows how to parse the JSON with Swift:

{
  "service": "McAPI HTML 2 PDF, https://mcapi.io",
  "version": "V1",
  "pdf": "https://...pdf"
}

McAPI HTML to PDF API - Converted HTML Invoice as PDF with Swift

Here's the created PDF from the Swift snippet, viewed in the Preview app on a Mac. Just like the HTML source the generated PDF is mostly text (except for the ACME-logo) and as such it is fully indexable and searchable:

Image of Converted HTML Invoice to PDF in Swift

Specifying page formats

The HTML to PDF Converter API comes with a built-in list of standard paper formats like "Letter" or "A4". To get a list of all formats use the listFormats option, like so:

// Swift 5
  
...

let parameters = [
  "listFormats": "true"
] as [String : Any]

...

When this option is set, the API will ignore all other parameters and instead return an array of all predefined page sizes, shown here as JSON source:

{
  formats: ["Letter", "Legal", "Tabloid", "Ledger", "A0", "A2", "A3", "A4", "A5", "A6"]
}

Selecting one of the predefined formats is simple, just use its name in the call (formats, like all parameters and options, are case sensitive with the API):

// Swift 5
  
...

let parameters = [
  "url": "https://mcapi.io/html2pdf/templates/invoice.html",
  "storeExternal": "true",
  "format": "Letter"
] as [String : Any]

...

Convert a HTML string to PDF with Swift

All previous examples sent URLs for conversion to the API. You can also add HTML code directly to your call to the API with the html option. We first load the HTML code from a file and then encode the HTML data so that it can be safely put into a JSON block.

A basic example:

// Swift 5

...

let fileURL = URL(fileURLWithPath: "invoice.html")!
do{
  let data = try String(contentsOf: fileURL)
  let html = try JSONDecoder().encode(data)

  ...

}
catch{
  // Error
}

... 

Then we set the parameters like so:

// Swift 5

...

let parameters = [
  "html": html,
  "storeExternal": "true",
  "format": "Letter"
] as [String : Any]

...

The rest of the call to the API remains unchanged. The API will now render the HTML string into a PDF and return it to the caller.

Note that relative references or links in the HTML string will not resolve. Example for an image that will not be loaded:

<img src="../templates/logo.png"/>

All references and links in your HTML must be absolute and point to valid web locations, here's an example:

<img src="https://mcapi.io/html2pdf/templates/logo.png"/>

Make sure to see the section in the API overview for more on this.

With your call you can also add some HTML to define header and footer sections for the PDF. Those sections can display page number, print date and other static and dynamic data. The API overview has more on this and provides some sample HTML.

Cookie consent banners and ad blocking with Swift

If so desired, the API can auto-click the "Accept" (or a similarly worded) button on GDPR / DSGVO cookie consent banners (Note that this feature is currently experimental, discussion.)

Consider the website of CNBC which we convert to a PDF with this Swift parameters array:

// Swift 5
  
...

let parameters = [
  "url": "https://cnbc.com",
  "storeExternal": "true",
  "format": "A4",
  "orientation": 1,
  "background": "true"
] as [String : Any]

...

Screenshot from the captured PDF (link to PDF), note the dominant cookie consent banner which covers half the page:

Swift Website HTML to PDF Conversion with Cookie Banner

Set the cookie option in the parameters array to "true" to get a PDF without the banner:

// Swift 5
  
...

let parameters = [
  "url": "https://cnbc.com",
  "storeExternal": "true",
  "format": "A4",
  "orientation": 1,
  "background": "true",
  "cookie": "true"
] as [String : Any]

...

The CNBC site without the banner but now displaying ads (link to PDF):

Swift Website HTML to PDF Conversion with Ad.png

Blocking ads on a website before conversion to a PDF with Swift

In most cases you'll prefer your PDFs without any ads at all. The API comes with a built-in ad blocker, put it to use with the adblock option:

// Swift 5
  
...

let parameters = [
  "url": "https://cnbc.com",
  "storeExternal": "true",
  "format": "A4",
  "orientation": 1,
  "background": "true",
  "cookie": "true",
  "adblock": "true"
] as [String : Any]

...

The site without cookie banner and without ads (link to PDF):

Swift Website HTML to PDF Conversion no Cookies no Ads

For the conversion of the CNBC site we had set the orientation to "1" for landscape (default is "0", portrait) and the background param to "true". This is a useful option for converting websites to a PDF because they frequently have inverted text (i.e. light text on dark background) and similar styling.

Here's the CNBC site with background set to "false". The site's design features lots of white text against a blue or black background which is now no longer visible against the white background of the page:

Swift Website HTML to PDF Conversion Transparent Background

As a rule of thumb, set the background option to "false" for conversion of documents like invoices, package lists, time sheets, set it to "true" when converting web pages or sites to a PDF.

The header-parameter - writing PDFs to a file with Swift

With the storeExternal option set to "false", the PDF is returned immediately as a base64 encoded string rather than being stored in the cloud. Per default, this string has a MIME header (or prefix) that describes the media type of the encoded content.

Sample parameters array:

// Swift 5

...

let parameters = [
  "url": "https://mcapi.io/html2pdf/templates/invoice.html",
  "storeExternal": "false",
  "format": "A4"
] as [String : Any]

...

The returned response with the MIME prefix at the beginning of the PDF string:

{
  "service": "McAPI HTML 2 PDF, https://mcapi.io",
  "version": "V1",
  "pdf": "data:application/pdf;base64,JVBERi0 ... JUVPRg=="
}

To parse the JSON string, we set up an auxiliary struct, Result, that declares the fields that the API returns (Note that the struct must conform to the Decodable protocol in order for the JSON parser to work.) After decoding you can then directly set the "pdf"-string as the data property of an HTML object tag.

This is particularly useful if you want to load PDFs into a web view, like in this example:

// Swift 5

...

struct Result : Decodable{
  let service: String
  let version: String
  let pdf: String
}

...

if httpResponse?.statusCode == 200{
  if let data = data{
    let result: Result = try! JSONDecoder().decode(Result.self, from: data)
    // result.pdf now holds the PDF as a base64 encoded string
    let pdf = result.pdf
    let img = "<object data=\"" + pdf + "\""/>"
    webView.loadHTMLString(img)
  }
}

...

The MIME prefix will make sure that the PDF data is interpreted correctly by the browser (Note that not all browsers support the embedding of PDF files with the object tag.)

However, when writing the PDF data to a file, including the prefix would result in an invalid PDF document as the header is not part of a PDF file. To have the API convert your HTML content to a PDF without the prefix, set the header-parameter to "false", like so:

// Swift 5

...

let parameters = [
  "url": "https://mcapi.io/html2pdf/templates/invoice.html",
  "storeExternal": "false",
  "format": "A4",
  "header": "false"
] as [String : Any]

...

The API will now return the PDF data without the MIME header:

{
  "service": "McAPI HTML 2 PDF, https://mcapi.io",
  "version": "V1",
  "pdf": "JVBERi0 ... JUVPRg=="
}

All that is left now is decoding the base64 string to get the binary PDF data and then write this data to a file. Shown here as a complete Swift program (this is essentially the contents of the Playground mentioned in the introduction):

// Swift 5

import Foundation
import UIKit

struct Result : Decodable{
  let service: String
  let version: String
  let pdf: String
}

let headers = [
  "content-type": "application/json",
  "x-rapidapi-key": "YOUR_API_KEY",
  "x-rapidapi-host": "mcapi-html-2-pdf.p.rapidapi.com"
]

let parameters = [
  "url": "https://mcapi.io/html2pdf/templates/invoice.html",
  "storeExternal": "false",
  "format": "A4",
  "header": "false"
] as [String : Any]

let postData = try JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://mcapi-html-2-pdf.p.rapidapi.com/")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  }
  else {
    let httpResponse = response as? HTTPURLResponse
    if httpResponse?.statusCode == 200{
      if let data = data{
        let result: Result = try! JSONDecoder().decode(Result.self, from: data)
        // result struct will now hold the PDF, we decode it to get the binary data
        if let pdfData = Data(base64Encoded: result.pdf, options: .ignoreUnknownCharacters){
          let folder = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last! as URL
          let fileName = "invoice.pdf"
          let path = folder.appendingPathComponent(fileName)
          do {
            try pdfData.write(to: path, options: .atomic)
          }
          catch {
            // Error handling
          }
        }
      }
    }
    else{
      // handle 400 errors here, see documentation for possible error conditions
    }
  }
})

dataTask.resume()

When run in Xcode, the folder where the PDF is stored will be under ~/Library/Developer/XCPGDevices, the default location of the file system for iOS Playgrounds.

Back to McAPI HTML to PDF API main page.