Skip to content

Ruby HTML to PDF API

Convert any URL into a pixel-perfect PDF with one HTTP request in Ruby — no wkhtmltopdf binary, no Chrome in your slug, no servers to maintain.

Convert a URL to PDF in Ruby

No gem and no browser binaries — the Microlink REST API turns any URL into a hosted PDF with a single HTTP GET. Everything below is standard library, built on net/http, uri and json.
Step 01 · Skip the Gemfile
Nothing to bundle install — the standard library already speaks HTTP. Run this from your terminal and a hosted PDF URL comes back before you write a single file.
ruby -rnet/http -rjson -e '
  uri = URI("https://api.microlink.io?url=https://example.com&pdf=true&meta=false")
  puts JSON.parse(Net::HTTP.get(uri)).dig("data", "pdf", "url")'
Step 02 · Convert any URL
Point it at a page, ask for a PDF, and read the hosted document URL out of the JSON response. Net::HTTP.start carries the timeouts and keeps the connection open for the request. This module is reused everywhere below.
microlink.rb
require 'json'
require 'net/http'
require 'uri'

module Microlink
  Error = Class.new(StandardError)

  ENDPOINT = 'https://api.microlink.io'.freeze

  module_function

  def pdf_url(target)
    uri = URI(ENDPOINT)
    uri.query = URI.encode_www_form(url: target, pdf: true, meta: false)

    request = Net::HTTP::Get.new(uri)

    response = begin
      Net::HTTP.start(
        uri.host, uri.port,
        use_ssl: true, open_timeout: 10, read_timeout: 60
      ) { |http| http.request(request) }
    rescue Net::OpenTimeout, Net::ReadTimeout => e
      raise Error, "microlink: #{e.class}"
    end

    payload = begin
      JSON.parse(response.body.to_s)
    rescue JSON::ParserError
      raise Error, "microlink: #{response.code} #{response.message}: invalid JSON"
    end

    unless response.is_a?(Net::HTTPSuccess)
      raise Error, "microlink: #{response.code}: #{payload['message']}"
    end

    payload.dig('data', 'pdf', 'url') ||
      raise(Error, 'microlink: no pdf url in response')
  end
end

puts Microlink.pdf_url('https://example.com')
Step 03 · Customize the document
Paper format, margins, orientation, and print CSS are all query params — swap this hash into URI.encode_www_form. Nested options use dot notation, so pdf.format maps to the format field.
options.rb
def pdf_params(target)
  {
    url: target,
    'pdf.format': 'A4',         # A0-A6 | Letter | Legal | Tabloid
    'pdf.margin': '0.35cm',     # cm, mm, in or px
    'pdf.landscape': false,     # portrait (default) | landscape
    'pdf.scale': 1,             # zoom the rendering, 0.1 to 2
    mediaType: 'print',         # print stylesheets (default) | screen
    meta: false
  }
end
Step 04 · Stream it to disk
The response is a hosted PDF URL on a global CDN. Copy it into a file with a second request that streams the body in chunks, or hand the URL straight to your view.
save.rb
def save_pdf(target, path = 'document.pdf')
  uri = URI(Microlink.pdf_url(target))

  Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
    http.request(Net::HTTP::Get.new(uri)) do |response|
      unless response.is_a?(Net::HTTPSuccess)
        raise Microlink::Error, "download #{uri}: #{response.code}"
      end

      File.open(path, 'wb') do |file|
        response.read_body { |chunk| file.write(chunk) }
      end
    end
  end

  path
end

Drop it into your app

A controller, a route, or a background job — the same request becomes your own PDF endpoint, perfect for invoice downloads, nightly reports, and export views in Rails, Sinatra, Sidekiq or plain Rack.
  • Rails
  • Sinatra
  • Sidekiq
  • Rack
require 'sinatra'
require_relative 'microlink'

# GET /pdf?url=https://example.com
get '/pdf' do
  redirect Microlink.pdf_url(params['url'])
rescue Microlink::Error => e
  halt 502, e.message
end
Every tab reuses the quickstart module: Microlink.pdf_url(target)

Deploy a slug, not a browser

Rendering a web page to PDF from Ruby means shelling out to a binary, running a headless browser beside Puma, or drawing the document by hand. The API gives you a real browser rendering engine without any of the infrastructure.

Self-hosted PDF tooling

  • wicked_pdf and pdfkit shell out to wkhtmltopdf, archived upstream
  • Grover needs Node and Puppeteer installed beside Ruby
  • Ferrum and Cuprite drive a Chrome you install, pool and restart
  • Prawn draws documents from primitives, never from a URL
  • Each browser eats hundreds of MB of RAM; workers crash under load
  • Fonts, emoji, and modern CSS break differently on every host

Microlink for Ruby

  • One HTTP request — net/http and json, nothing to add to the Gemfile
  • Runs anywhere: a Rails app, a Sidekiq worker, a rake task, your laptop
  • Autoscaled managed browser fleet with a 99.9% uptime SLA
  • Sub-second cached responses from 340+ edge locations
  • A0-A6, Letter, Legal & Tabloid — set as plain query params
  • Print stylesheets, custom CSS & DOM interaction, no extra deps

Built for the way you write Ruby.

A REST API that feels native in Ruby — one HTTP call, JSON back, and at home in any runtime from a Rails controller to a Sidekiq worker. Read the PDF guide to go deeper.

  • No Binaries to Install

    Skip wkhtmltopdf and the buildpack that ships it. There is no rendering engine to download, patch, or keep in sync across hosts.
  • Standard Library Only

    net/http sends the request, uri builds the query, json reads the response. No gem to add to your Gemfile and no native extension to compile.
  • Rails & Sinatra Friendly

    Drop it into a controller, a route, or a Sidekiq job in a few lines. The same request works in every framework.
  • Smaller Deploys

    No browser layer to bundle into the slug or image. Deploys stay small, which keeps boot times on Heroku, Fly and Kamal short.
  • Real Browser Rendering

    Pages render in Headless Chrome, so JavaScript-driven dashboards and charts come out right — the blind spot of PDF builders that never run scripts.
  • Zero Infrastructure

    No Chrome to pin to a driver version and no browser pool inside Puma. Your app stays a plain HTTP client.
  • Custom Paper & Layout

    Every layout option is a query param: pdf.format, pdf.margin, pdf.landscape, pdf.scale, and pdf.pageRanges.
  • Screen & Print Media

    Print stylesheets apply by default. Set mediaType to screen in the same query to keep the on-screen layout instead.
  • Generous Free Tier

    Start with 25 requests per day — no account, no credit card. Point at pro.microlink.io with an x-api-key header when you scale.
  • No Binaries to Install

    Skip wkhtmltopdf and the buildpack that ships it. There is no rendering engine to download, patch, or keep in sync across hosts.
  • Standard Library Only

    net/http sends the request, uri builds the query, json reads the response. No gem to add to your Gemfile and no native extension to compile.
  • Rails & Sinatra Friendly

    Drop it into a controller, a route, or a Sidekiq job in a few lines. The same request works in every framework.
  • Smaller Deploys

    No browser layer to bundle into the slug or image. Deploys stay small, which keeps boot times on Heroku, Fly and Kamal short.
  • Real Browser Rendering

    Pages render in Headless Chrome, so JavaScript-driven dashboards and charts come out right — the blind spot of PDF builders that never run scripts.
  • Zero Infrastructure

    No Chrome to pin to a driver version and no browser pool inside Puma. Your app stays a plain HTTP client.
  • Custom Paper & Layout

    Every layout option is a query param: pdf.format, pdf.margin, pdf.landscape, pdf.scale, and pdf.pageRanges.
  • Screen & Print Media

    Print stylesheets apply by default. Set mediaType to screen in the same query to keep the on-screen layout instead.
  • Generous Free Tier

    Start with 25 requests per day — no account, no credit card. Point at pro.microlink.io with an x-api-key header when you scale.

Try it live in the playground

Paste a URL and see the exact API request before you write a line of Ruby.

Ruby PDF FAQ

What Ruby developers ask before integrating. For formats, limits, and SLA, see the PDF API overview.

Do I need wkhtmltopdf or a Chrome binary?

No. It is a plain HTTP request to the Microlink API — there is no binary to install next to your app and no buildpack to add. The Headless Chrome fleet runs on Microlink's side.
That matters most for wicked_pdf and pdfkit users: both shell out to wkhtmltopdf, which is archived upstream and no longer maintained.

Do I need a gem or an HTTP client?

No. net/http sends the request, uri builds the query string, and json parses the response — all standard library, so the Gemfile does not change.
Clients like faraday or httparty work the same way if you already use one; the request is an ordinary GET either way.

Should I call it from a background job?

For anything user-facing, yes. Rendering happens on Microlink's side, but your request still waits on the network, so a Sidekiq or Active Job worker keeps Puma threads free — see the Sidekiq tab above.
Each conversion is an independent stateless request, so workers can run in parallel. Concurrency is bounded by your plan rather than your dynos — check the rate limit docs before fanning out widely.

Does it work with Rails, Sinatra, and Rack?

Yes. Because it is just an HTTP call, it drops into any controller or route in a few lines — see the tabs above for Rails, Sinatra, Sidekiq, and Rack, or the PDF guide.
In Rails, redirecting to the hosted document needs allow_other_host: true, since the PDF is served from the Microlink CDN rather than your own domain.

How do I authenticate from Ruby?

Two things change together: send your key as the x-api-key header, and point the request at pro.microlink.io instead of api.microlink.io. Sending the header to the free endpoint returns an EPRO error.
The module already builds a request, so add one line before http.request(request): request['x-api-key'] = ENV['MICROLINK_API_KEY']. See the authentication docs and pricing.

How do I set a timeout?

Both at once, the way the module above does it: open_timeout caps how long Ruby waits to connect and read_timeout caps how long it waits for the response body.
Rendering happens on Microlink's side, so your app only ever waits on the network — never on a browser it has to start itself.

Start converting in Ruby

Get 25 requests/day with zero commitment — no account, no credit card. Paste the module into a controller and ship a PDF today.
No login needed
25 reqs/day free
No credit card