Backend Development 9 min read

Using Go and chromedp to Control Headless Chrome for Screenshots, PDF Export, and Device Emulation

This article demonstrates how to use Go with the chromedp library to drive headless Chrome for element screenshots, full‑page captures, PDF generation, and device emulation, offering a lightweight alternative to Selenium‑based solutions.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Using Go and chromedp to Control Headless Chrome for Screenshots, PDF Export, and Device Emulation

The author, inspired by a 360 tech article about server‑side browser screenshots with Selenium, explores implementing similar functionality in Go.

Drawbacks of Selenium/PhantomJS are highlighted: the need to install Selenium or PhantomJS, PhantomJS is no longer maintained, chromedriver version constraints, and reliance on the html2canvas JS library.

Using Go together with the chromedp library eliminates these issues; only the Chrome browser is required at runtime.

Key characteristics of chromedp:

Provides a fast and simple way to drive the browser.

Offers rich low‑level APIs based on the Chrome DevTools Protocol (CDP).

Supplies flexible high‑level actions similar to Selenium’s WebElement actions.

Has no external dependencies beyond Chrome itself.

Leverages Go’s “compile once, run anywhere” advantage.

Installation command:

go get -u github.com/chromedp/chromedp

Element screenshot implementation (example captures the element with selector #main on 360 search homepage):

package main

import (
  "context"
  "io/ioutil"
  "log"

  cdp "github.com/chromedp/chromedp"
)

func main() {
  ctx, cancel := cdp.NewContext(context.Background())
  defer cancel()

  urlstr := `https://www.so.com/`
  var buf []byte
  selector := `#main`
  if err := cdp.Run(ctx, elementScreenshot(urlstr, selector, &buf)); err != nil {
    log.Fatal(err)
  }
  if err := ioutil.WriteFile("360_so.png", buf, 0644); err != nil {
    log.Fatal(err)
  }
}

func elementScreenshot(urlstr, sel string, res *[]byte) cdp.Tasks {
  return cdp.Tasks{
    cdp.Navigate(urlstr),
    cdp.WaitVisible(sel, cdp.ByID),
    cdp.Screenshot(sel, res, cdp.NodeVisible, cdp.ByID),
  }
}

The resulting screenshot is shown in the original article.

Exporting a page to PDF:

// Export specified element as PDF
func elementPDFPrint(urlstr, sel string, res *[]byte) cdp.Tasks {
  var err error
  return cdp.Tasks{
    cdp.Navigate(urlstr),
    cdp.Sleep(time.Duration(5) * time.Second),
    cdp.ActionFunc(func(ctx context.Context) error {
      *res, _, err = page.PrintToPDF().Do(ctx)
      if err != nil {
        return err
      }
      return nil
    }),
  }
}

Using the above on https://www.360.cn/ produces a PDF of the page.

Full‑screen screenshot example (captures the entire viewport of a given URL):

func fullScreenshot(urlstr string, quality int64, res *[]byte) cdp.Tasks {
  return cdp.Tasks{
    cdp.Navigate(urlstr),
    cdp.ActionFunc(func(ctx context.Context) error {
      _, _, contentSize, err := page.GetLayoutMetrics().Do(ctx)
      if err != nil {
        return err
      }
      width, height := int64(math.Ceil(contentSize.Width)), int64(math.Ceil(contentSize.Height))
      err = emulation.SetDeviceMetricsOverride(width, height, 1, false).
        WithScreenOrientation(&emulation.ScreenOrientation{Type: emulation.OrientationTypePortraitPrimary, Angle: 0}).
        Do(ctx)
      if err != nil {
        return err
      }
      *res, err = page.CaptureScreenshot().
        WithQuality(quality).
        WithClip(&page.Viewport{X: contentSize.X, Y: contentSize.Y, Width: contentSize.Width, Height: contentSize.Height, Scale: 1}).
        Do(ctx)
      return err
    }),
  }
}

Resulting full‑page image is displayed in the article.

Device emulation (e.g., iPhone 7 landscape):

func main() {
  ctx, cancel := cdp.NewContext(context.Background())
  defer cancel()

  var b []byte
  if err := cdp.Run(ctx,
    cdp.Emulate(device.IPhone7landscape),
    cdp.Navigate(`https://www.whatsmyua.info/`),
    cdp.CaptureScreenshot(&b),
  ); err != nil {
    log.Fatal(err)
  }
  if err := ioutil.WriteFile("iphone7_ua.png", b, 0644); err != nil {
    log.Fatal(err)
  }
}

The captured user‑agent screenshot is shown.

In conclusion, the Go + chromedp combination enables almost all browser operations—screenshots, PDF export, device simulation, and automation—without external tools, making it a concise and powerful solution for backend services, testing platforms, and reporting pipelines.

AutomationgolangWeb Scrapingheadless-chromechromedpPDF Export
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.