No-code tools

Every endpoint is a single HTTP request, so Shotlane works in any tool with an HTTP step: Google Sheets, Zapier, Make, n8n, Airtable and others. Copy a recipe below.

Most no-code tools handle links better than files. Add response_type=json and use the url field of the response: a hosted link that stays valid for 24 hours. To keep the image, have the next step download it or upload it to your own storage with the storage_* parameters.

Google Sheets

Show a live screenshot in a cell with =IMAGE(SHOTLANE(A2)). In your sheet, open Extensions → Apps Script, paste this, fill in your two keys from the dashboard, and save:

// Shotlane for Google Sheets: =IMAGE(SHOTLANE(A2)) shows a live screenshot of the URL in A2.
// Extensions → Apps Script → paste this file → set your keys below → Save. No API call happens here:
// the function only builds a signed image URL, and Sheets loads it. Each URL is cached for 24 hours,
// so a sheet costs 1 credit per URL per day however often it recalculates.
const SHOTLANE_PUBLIC_KEY = "pub_...";   // dashboard → Public key
const SHOTLANE_SECRET_KEY = "sl_...";    // dashboard → Secret API key (stays in this script, not in the sheet)

/**
 * A signed Shotlane screenshot URL for use with IMAGE().
 * @param {string} url The page to capture.
 * @param {string} options Optional extra parameters, e.g. "device=iphone&full_page=true".
 * @customfunction
 */
function SHOTLANE(url, options) {
  if (!url) return "";
  const params = { url: String(url), format: "png", width: "1280", height: "800", hide_cookie_banners: "true" };
  String(options || "").split("&").filter(String).forEach(function (pair) {
    const i = pair.indexOf("=");
    params[decodeURIComponent(pair.slice(0, i))] = decodeURIComponent(pair.slice(i + 1));
  });
  const enc = function (s) {   // the same encoding as Python's urlencode
    return encodeURIComponent(s).replace(/%20/g, "+").replace(/[!'()*]/g, function (c) { return "%" + c.charCodeAt(0).toString(16).toUpperCase(); });
  };
  const query = Object.keys(params).sort().map(function (k) { return enc(k) + "=" + enc(params[k]); }).join("&");
  const path = "/v1/screenshot";
  const sig = Utilities.computeHmacSha256Signature(path + "?" + query, SHOTLANE_SECRET_KEY)
    .map(function (b) { return ("0" + (b & 0xff).toString(16)).slice(-2); }).join("");
  return "https://shotlane.dev" + path + "?" + query + "&key=" + SHOTLANE_PUBLIC_KEY + "&signature=" + sig;
}

Also as a file: shotlane.gs.

Then in the sheet: =IMAGE(SHOTLANE(A2)), or with options =IMAGE(SHOTLANE(A2, "device=iphone&full_page=true")). The function builds a signed URL and makes no request itself; your secret key stays in the script, not in the sheet. Signed URLs are cached for 24 hours, so a sheet costs one credit per URL per day however often it recalculates.

Zapier

  1. Add an action step: Webhooks by Zapier → GET.
  2. URL: https://shotlane.dev/v1/screenshot
  3. Query string params: url (map it from your trigger), response_type = json, plus any options such as full_page = true.
  4. Headers: X-API-Key = your API key.
  5. Use the step's url output in later steps (Slack, email, Google Drive "upload file from URL"…).

The same works for PDFs (/v1/pdf), Markdown (/v1/markdown, the text is the response), page checks (/v1/check) and videos (/v1/animate).

Make

  1. Add the HTTP → Make a request module.
  2. URL https://shotlane.dev/v1/screenshot, method GET, a header X-API-Key with your key.
  3. Query string: url, response_type = json, and options. Turn on Parse response.
  4. Map data.url into the next module. To pass the file itself instead, drop response_type: the response body is the image.

n8n

Use an HTTP Request node: method GET, URL https://shotlane.dev/v1/screenshot, authentication Generic Credential Type → Header Auth with name X-API-Key and your key as the value, and query parameters url and your options. Set Response Format to File to get the image as binary data, or add response_type=json for a link.

Airtable

In a Run a script automation (or the Scripting extension), fetch a screenshot for a record's URL and store it in an attachment field:

const { url, recordId } = input.config();
const r = await fetch("https://shotlane.dev/v1/screenshot?response_type=json&url=" + encodeURIComponent(url), {
  headers: { "X-API-Key": "sl_your_key" },
});
const shot = await r.json();
if (!r.ok) throw new Error(shot.error);
const table = base.getTable("Sites");
await table.updateRecordAsync(recordId, { Screenshot: [{ url: shot.url }] });

Airtable copies the file from the link into its own storage, so the attachment stays after the link expires.

Anything else

Retool, Bubble, Pipedream, Power Automate, Clay and others: use their HTTP or API step with the same three things (the endpoint URL, the X-API-Key header, and your options as query parameters). The OpenAPI spec imports into tools that read it.