How to screenshot webpages in Golang
Tags: go, screenshot, backend, developers
Published: 2023-07-01 13:48:35

Hello there, 
So, I've been lazy to publish an article for about a month or probably more but today is that day :). 
This article is about my recent project. Wondering what that is?
Well, it is about [Urlbox](https://urlbox.io).
I wanted to implement a website screenshotting functionality. So,  I got into googling, and at the end of it all, I came across Urlbox. Here is a little explanation as to what Urlbox is about.
Urlbox is a lightweight REST API built to automate the process of capturing website screenshots on your product.
The reason why I am so excited about this project is that Urlbox seems to be the answer to the problem I had at hand. But then, I realized that Urlbox doesn't have a Golang library. And so, just as I always do, I decided to build [one](https://github.com/iqquee/urlbox). Now, you can add this functionality to your application. Well, I mean for Golang developers anyways. You should know me by now. I'm all about Golang ;).
Below are sample screenshots taken with the library:

![Urlbox website Image screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0mftf8wg96y6nyqoe458.png)

![Iqquee github's profile Image screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ugg5nak5df97q3f501dz.png)

![Youtube website image screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ii6nd9fbas6tm0tlnx54.png)

So here's how to setup Urlbox in your Golang application:
NOTE: This Golang library supports the two ways of taking the screenshot of websites supported by Urlbox.

## Installation
This package can in installed using the go command below.
```sh
go get github.com/iqquee/urlbox
```
### List of file formats you could use for the Format field in the Request{} struct. 
```go
const (
	//FileFormatPng for png file format
	FileFormatPng string = "png"
	//FileFormatJpeg for jpeg file format
	FileFormatJpeg string = "jpeg"
	// FileFormatAvif for avif file format
	FileFormatAvif string = "avif"
	//FileFormatWebp for webp file format
	FileFormatWebp string = "webp"
	//FileFormatWebm for webm file format
	FileFormatWebm string = "webm"
	// FileFormatPdf for pdf file format
	FileFormatPdf string = "pdf"
	//FileFormatSvg for svg file format
	FileFormatSvg string = "svg"
	// FileFormatHtml for html file format
	FileFormatHtml string = "html"
	// FileFormatMd for md file format
	FileFormatMd string = "md"
	// FileFormatMp4 for mp4 file format
	FileFormatMp4 string = "mp4"
)
```

## Screenshot
Screenshot takes the screenshot of a website synchronously. 
Inother words, whenever you make a request using this method, you wait to get the screenshotted data([]byte) from the server.

This method takes in the Request{} struct as a parameter.
### List of all the fields available in the Request{} struct.
```go
type (
    // Request parameter for the ScreenshotAsync method
	Request struct {
		Url     string  `json:"url"`    // url of website to screenshot
		Format  string  `json:"format"` // screenshot file format
		Options Options // optional params for the request
	}
	// optional parameter
	Options struct {
		FullPage        bool // for full page screenshot
		Width           int  // the viewport width of the browser, in pixels
		Height          int // the viewport height of the browser, in pixels
		BlockingOptions Blocking // options for blocking or dismissing certain page elements, such as cookie banners
		SelectorOption  Selector // take a screenshot of the element that matches this selector. By default, if the selector is not found, Urlbox will take a normal viewport screenshot. If you prefer Urlbox to fail the request when the selector is not found, pass fail_if_selector_missing=true.
		ImageOption     Image    // options relating to the outputted PNG, WebP or JPEG file
		WaitOption      Wait // options relating to waiting before taking the screenshot 
	}
	// blocking option parameter
	Blocking struct {
		BlockAds          bool `json:"block_ads"`           // remove ads from page
		HideCookieBanners bool `json:"hide_cookie_banners"` // remove cookie banners if any
		ClickAccept       bool `json:"click_accept"`        // click accept buttons to dismiss pop-upsSelector
	}
	// selector option parameter
	Selector struct {
		Selector              string `json:"selector"`                 // for css selectors e.g #playground for id of playground
		FailIfSelectorMissing bool   `json:"fail_if_selector_missing"` // fail the request when the selector is not found
	}
	// image option parameter
	Image struct {
		Retina      bool `json:"retina"`      // take a 'retina' or high-definition screenshot, equivalent to setting a device pixel ratio of 2.0 or @2x. Please note that retina screenshots will be double the normal dimensions and will normally take slightly longer to process due to the much bigger image size.
		Quality     int  `json:"quality"`     // the image quality of the resulting screenshot (JPEG/WebP only)
		Transparent bool `json:"transparent"` // if a website has no background color set, the image will have a transparent background (PNG/WebP only)
	}

	// wait option parameter
	Wait struct {
		Delay   int // the amount of time to wait before Urlbox takes the screenshot or PDF, in milliseconds.
		TimeOut int // the amount of time to wait for the requested URL to respond, in milliseconds.
	}
)
```

```go
package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/iqquee/urlbox"
)

func main() {
	apiKey := ""
	secreteKey := ""
	client := urlbox.New(*http.DefaultClient, apiKey, secreteKey)

	request := urlbox.Request{
		Url:    "https://urlbox.io",
		Format: urlbox.FileFormatPng,
		Options: urlbox.Options{
			ImageOption: urlbox.Image{
				Retina:  true,
				Quality: 100,
			},
		},
	}

	data, err := client.Screenshot(request)
	if err != nil {
		fmt.Println("an error occured: ", err)
		return
	}

	fmt.Println("This is the response byte: ", data)

	filename := fmt.Sprintf("%s-%d.%s", strings.Replace(request.Url, "/", "-", -1), time.Now().UTC().Unix(), request.Format)

	if err := os.WriteFile(filename, data, 0666); err != nil {
		fmt.Println("error writing to disk: ", err)
		return
	}
}
```

## ScreenshotAsync
ScreenshotAsync allows your application to receive information when a screenshot has been rendered.
This allows you to render screenshots asynchronously.

This method takes in the RequestAsync{} struct as a parameter.
### Use this object payload to implement the ScreenshotAsync() method
```go
type RequestAsync struct {
    Url        string `json:"url"`         // url of website to screenshot
    WebhookUrl string `json:"webhook_url"` // Pass a webhook URL in as the webhook_url option and Urlbox will send a POST request back to that URL with data about the screenshot in JSON format once it has completed rendering
}
```

```go
package main

import (
	"fmt"
	"net/http"

	"github.com/iqquee/urlbox"
)

func main() {
	apiKey := ""
	secreteKey := ""
	client := urlbox.New(*http.DefaultClient, apiKey, secreteKey)

	request := urlbox.RequestAsync{
		Url:        "https://urlbox.io",
		WebhookUrl: "https://example.com/webhooks/urlbox",
	}

	message, err := client.ScreenshotAsync(request)
	if err != nil {
		fmt.Println("an error occured: ", err)
		return
	}

	fmt.Println("This is the response message: ", message)

}
```

I have put in some work to make sure that this [library](https://github.com/iqquee/urlbox) was properly documented so that Golang developers out there can find it quite easy to use and without much stress. And as such, sample code were added for each methods.
Do have a great day ahead.