Elixir
Use ScreenshotAPI from Elixir with the Req HTTP client.
Overview
These examples use Req, the modern HTTP client for Elixir. Add it to your mix.exs:
defp deps do
[{:req, "~> 0.5"}]
endQuick Start
Set your API key
export SCREENSHOTAPI_KEY="sk_live_your_key_here"Take a screenshot
api_key = System.get_env("SCREENSHOTAPI_KEY")
{:ok, response} =
Req.get("https://screenshotapi.to/api/v1/screenshot",
params: [url: "https://example.com"],
headers: [{"x-api-key", api_key}]
)
if response.status == 200 do
File.write!("screenshot.png", response.body)
credits = Req.Response.get_header(response, "x-credits-remaining") |> List.first()
IO.puts("Credits remaining: #{credits}")
else
IO.puts(:stderr, "Error #{response.status}: #{response.body}")
endClient Module
A reusable client with all screenshot options:
defmodule ScreenshotAPI do
@base_url "https://screenshotapi.to"
defstruct [:api_key, base_url: @base_url]
defmodule Result do
defstruct [:content, :content_type, :credits_remaining, :screenshot_id, :duration_ms]
end
def new(api_key, opts \\ []) do
%__MODULE__{
api_key: api_key,
base_url: Keyword.get(opts, :base_url, @base_url)
}
end
def capture(%__MODULE__{} = client, url, opts \\ []) do
params =
[url: url]
|> maybe_add(:width, opts[:width])
|> maybe_add(:height, opts[:height])
|> maybe_add(:fullPage, if(opts[:full_page], do: "true"))
|> maybe_add(:type, opts[:format])
|> maybe_add(:quality, opts[:quality])
|> maybe_add(:colorScheme, opts[:color_scheme])
|> maybe_add(:waitUntil, opts[:wait_until])
|> maybe_add(:waitForSelector, opts[:wait_for_selector])
|> maybe_add(:delay, opts[:delay])
case Req.get("#{client.base_url}/api/v1/screenshot",
params: params,
headers: [{"x-api-key", client.api_key}]
) do
{:ok, %{status: 200} = resp} ->
{:ok,
%Result{
content: resp.body,
content_type: get_header(resp, "content-type") || "image/png",
credits_remaining: get_header(resp, "x-credits-remaining") |> to_int(),
screenshot_id: get_header(resp, "x-screenshot-id") || "",
duration_ms: get_header(resp, "x-duration-ms") |> to_int()
}}
{:ok, resp} ->
{:error, "Screenshot failed (#{resp.status}): #{inspect(resp.body)}"}
{:error, reason} ->
{:error, "Request failed: #{inspect(reason)}"}
end
end
defp maybe_add(params, _key, nil), do: params
defp maybe_add(params, key, value), do: Keyword.put(params, key, value)
defp get_header(resp, name) do
Req.Response.get_header(resp, name) |> List.first()
end
defp to_int(nil), do: 0
defp to_int(val) when is_binary(val), do: String.to_integer(val)
endUsage
api = ScreenshotAPI.new(System.get_env("SCREENSHOTAPI_KEY"))
{:ok, result} =
ScreenshotAPI.capture(api, "https://github.com",
width: 1280,
height: 720,
format: "webp",
quality: 85
)
File.write!("github.webp", result.content)
IO.puts("Credits remaining: #{result.credits_remaining}")
IO.puts("Duration: #{result.duration_ms}ms")Common Patterns
Batch Screenshots
Capture multiple URLs concurrently with Task.async_stream:
urls = [
"https://example.com",
"https://github.com",
"https://news.ycombinator.com"
]
urls
|> Enum.with_index()
|> Task.async_stream(fn {url, i} ->
case ScreenshotAPI.capture(api, url) do
{:ok, result} ->
File.write!("screenshot-#{i}.png", result.content)
IO.puts("✓ #{url}")
{:error, reason} ->
IO.puts(:stderr, "✗ #{url}: #{reason}")
end
end, max_concurrency: 5)
|> Stream.run()Phoenix Controller
Serve screenshots in a Phoenix application:
defmodule MyAppWeb.ScreenshotController do
use MyAppWeb, :controller
@api ScreenshotAPI.new(System.get_env("SCREENSHOTAPI_KEY"))
def show(conn, %{"url" => url}) do
case ScreenshotAPI.capture(@api, url, format: "webp", quality: 80) do
{:ok, result} ->
conn
|> put_resp_content_type(result.content_type)
|> put_resp_header("cache-control", "public, max-age=3600")
|> send_resp(200, result.content)
{:error, _reason} ->
conn
|> put_status(502)
|> json(%{error: "Screenshot failed"})
end
end
def show(conn, _params) do
conn
|> put_status(400)
|> json(%{error: "url is required"})
end
endGenServer for Rate Limiting
Wrap the client in a GenServer with built-in rate limiting:
defmodule ScreenshotWorker do
use GenServer
def start_link(api_key) do
GenServer.start_link(__MODULE__, api_key, name: __MODULE__)
end
def capture(url, opts \\ []) do
GenServer.call(__MODULE__, {:capture, url, opts}, 30_000)
end
@impl true
def init(api_key) do
{:ok, %{api: ScreenshotAPI.new(api_key)}}
end
@impl true
def handle_call({:capture, url, opts}, _from, state) do
result = ScreenshotAPI.capture(state.api, url, opts)
{:reply, result, state}
end
endError Handling
case ScreenshotAPI.capture(api, "https://example.com") do
{:ok, result} ->
File.write!("screenshot.png", result.content)
{:error, message} when message =~ "402" ->
IO.puts(:stderr, "Out of credits — purchase more at screenshotapi.to")
{:error, message} when message =~ "403" ->
IO.puts(:stderr, "Invalid API key — check your configuration")
{:error, message} ->
IO.puts(:stderr, "Screenshot failed: #{message}")
end