ScreenshotNeo

BlogHow-to

How to Automate Website Screenshot Reports with Microlink and Google Sheets

Build a scheduled screenshot report with Google Sheets, Apps Script, and Microlink. Store image links or display captures, handle failures, and plan around quotas.

By the ScreenshotNeo team4 October 20269 min read

To automate website screenshot reports with Microlink and Google Sheets, keep one target URL per spreadsheet row, use Google Apps Script to request a screenshot from Microlink, write the returned screenshot URL and status back to the row, then run the script on an installable time-driven trigger. You can store a link or insert the public image into the sheet. This guide uses the documented APIs and services; the example has not been run as a live integration.

1. Design the report sheet

Create a sheet named Report with these headers in row 1:

Column Purpose
A: Page URL The website page to capture.
B: Captured at When the script recorded the result.
C: Screenshot URL The asset URL returned by Microlink.
D: Status OK or a concise failure reason.
E: Notes Optional owner, expected change, or review notes.

Enter one URL per row starting in row 2. Keep the screenshot URL even if you plan to show the image: the URL helps with debugging and offers a fallback if the inserted image cannot load.

2. Add the Apps Script capture function

Open Extensions → Apps Script from the spreadsheet and add the following code. Replace YOUR_MICROLINK_API_KEY with the key for your Microlink account. The API key is sent in the request header; do not put it in a cell or share the script with people who should not have access to it.

const SHEET_NAME = 'Report';
const MICROLINK_API_KEY = 'YOUR_MICROLINK_API_KEY';

function refreshScreenshotReport() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
  if (!sheet) throw new Error(`Sheet not found: ${SHEET_NAME}`);

  const lastRow = sheet.getLastRow();
  if (lastRow < 2) return;

  const rows = sheet.getRange(2, 1, lastRow - 1, 5).getValues();
  const capturedAt = new Date();

  rows.forEach((row, index) => {
    const sheetRow = index + 2;
    const pageUrl = String(row[0] || '').trim();
    if (!pageUrl) {
      sheet.getRange(sheetRow, 4).setValue('Skipped: no URL');
      return;
    }

    try {
      const endpoint = 'https://api.microlink.io/';
      const params = {
        url: pageUrl,
        screenshot: true,
        'meta': false
      };
      const query = Object.keys(params)
        .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
        .join('&');

      const response = UrlFetchApp.fetch(`${endpoint}?${query}`, {
        method: 'get',
        headers: { 'x-api-key': MICROLINK_API_KEY },
        muteHttpExceptions: true
      });
      const httpCode = response.getResponseCode();
      const body = response.getContentText();
      if (httpCode < 200 || httpCode >= 300) {
        throw new Error(`Microlink HTTP ${httpCode}: ${body.slice(0, 300)}`);
      }

      const result = JSON.parse(body);
      const screenshotUrl = result && result.data && result.data.screenshot
        && result.data.screenshot.url;
      if (!screenshotUrl) {
        throw new Error('Response did not contain data.screenshot.url');
      }

      sheet.getRange(sheetRow, 2).setValue(capturedAt);
      sheet.getRange(sheetRow, 3).setValue(screenshotUrl);
      sheet.getRange(sheetRow, 4).setValue('OK');
    } catch (error) {
      sheet.getRange(sheetRow, 2).setValue(capturedAt);
      sheet.getRange(sheetRow, 4).setValue(`Error: ${String(error.message || error).slice(0, 400)}`);
    }
  });
}

Microlink documents its screenshot option and response asset at the screenshot guide and its API at microlink.io/api. The endpoint supports screenshot configuration through request parameters; consult the current documentation for parameter syntax and account requirements. Google Apps Script’s UrlFetch service makes HTTP and HTTPS requests. The first run prompts for authorization, including external request and spreadsheet access.

Important implementation notes

  • The code handles each row independently, so one failing page does not prevent later rows from being processed.
  • It updates the capture date and status on failure, but keeps the previous screenshot URL. If you prefer to clear stale results, add sheet.getRange(sheetRow, 3).clearContent() inside the catch block.
  • It sends requests sequentially. This is easier to reason about and reduces bursts; for large lists, split work across scheduled batches rather than parallelizing requests blindly.
  • For production, consider putting the key in Apps Script Properties rather than source code. Restrict editor access because script editors can access the stored credential.

3. Choose what the screenshot captures

The default is a viewport capture. Pick the capture shape and page readiness behavior that matches the report:

Need Choice Tradeoff
Same visible area each run Default viewport screenshot Fast to inspect, but content below the fold is omitted.
Entire long page Full-page capture May take longer and can trigger lazy-loaded content; verify the resulting image dimensions.
One chart, card, or section Element targeting Useful for stable report panels; selectors can break when the site changes.
JavaScript-rendered content Wait for a selector, or use documented click/scroll interaction where needed More reliable than guessing with a fixed delay, but depends on a stable page signal.
Different downstream use Choose an image type supported by Microlink Balance image quality, file size, and compatibility with the sheet/report consumer.

Microlink documents full-page, element, and image type options in its screenshot guide. For dynamic pages, its dynamic-content guide describes selector waits and page interactions. Use a selector that appears only when the content you need is ready. A fixed delay can still be appropriate for a known animation or delayed third-party widget, but it can be both slower and less dependable as page behavior changes.

4. Store the screenshot URL or show the image

The sample stores the returned asset URL in column C. This is the simplest option for large reports: it avoids embedding many images in the spreadsheet and preserves a direct reference to the asset. Check Microlink’s current asset retention and URL behavior before treating these links as a permanent archive.

Insert a public image into the sheet

Google’s spreadsheet service can insert an image from a publicly accessible URL with insertImage(url, column, row). For example, after obtaining screenshotUrl, insert it in column F on the same row:

sheet.insertImage(screenshotUrl, 6, sheetRow);

The URL must be publicly accessible to Google’s image fetcher. If the asset requires authentication, insertion may fail. Google documents a 2 MB maximum for the blob-based image insertion method; URL insertion has a separate method and requirement. See the Spreadsheet class reference. Avoid inserting a new image on every refresh without removing or replacing the prior image, or the sheet will accumulate overlapping images. For frequently refreshed or many-URL reports, storing links is usually easier to maintain.

5. Schedule recurring captures

  1. In Apps Script, open Triggers (the clock icon) and choose Add Trigger.
  2. Select refreshScreenshotReport as the function.
  3. Choose Time-driven, then select the cadence that matches your report: hourly, daily, weekly, or another offered interval.
  4. Save and authorize the trigger under the account that should own the automation.
  5. Review the trigger’s execution history after its first scheduled run and keep an owner responsible for authorization and failures.

An installable trigger runs as the account that created it, so the creator must retain access to the spreadsheet and the script’s permissions. Google says time-driven triggers can run as frequently as every minute, but hourly execution time may be randomized within the selected hour; do not use a trigger as an exact-time scheduler. See Google’s installable triggers guide.

6. Plan capacity, performance, and cost

Estimate monthly capture demand as number of URLs × runs per month. For example, 30 URLs captured once each weekday is about 600 captures in a 20-workday month. Retries, manual runs, and multiple report sheets increase demand. Compare that estimate with the screenshot provider’s current plan and the Apps Script account quotas.

  • Microlink’s API page reviewed for this guide lists 25 requests per day on its free plan and a Pro configuration with 46,000 monthly requests at $49/month; it also lists a 99.9% uptime SLA for paid plans. These are current published terms, not permanent guarantees. Check the live API pricing and plan page before choosing capacity. The uptime figure applies to paid plans as stated there.
  • Google’s quotas page reviewed for this guide lists URL Fetch limits of 20,000 calls/day for consumer accounts and 100,000/day for Workspace accounts, plus daily trigger runtime limits of 90 minutes and 6 hours respectively. Quotas vary by account type and can change; check Google’s current quotas page.
  • A script run has a maximum execution duration. Large sheets or slow pages can hit runtime limits before daily request quotas. Process a bounded number of rows per run, record a cursor, and continue on a later trigger if the list is large.
  • Captures are network and browser work. Full-page captures, delayed content, and slow target sites increase elapsed time. Use the smallest wait that reliably captures the needed content.
  • Retries can improve recovery from transient failures but also consume request capacity. Retry only transient network and server errors, with a small retry count and a delay; do not retry authentication or invalid-parameter errors without changing the request.

7. Troubleshooting

Symptom Likely cause Fix
Authorization prompt or authorization error Apps Script has not been granted external request or spreadsheet access. Run the function manually as the intended trigger owner and approve the requested scopes. Review the script manifest if scopes are explicitly set.
HTTP 401 or 403 from Microlink Missing, invalid, or unauthorized API key; account access or plan restriction. Check the credential and current Microlink API requirements. Keep the key out of the sheet and logs.
HTTP 429 or quota-related response Provider rate/plan capacity or Google quota exhaustion. Reduce cadence, spread work across runs, batch by a cursor, and check both provider terms and Google quotas.
HTTP 400 or API error payload Invalid URL or unsupported/malformed screenshot option. Validate that the cell contains an absolute HTTP or HTTPS URL and compare options with Microlink’s current docs.
Response lacks data.screenshot.url The response represents an error or screenshot generation did not produce an asset. Inspect the response status and a safely truncated response body; confirm the screenshot option and target page are valid.
Blank or incomplete screenshot Page content had not rendered, the viewport missed it, or the site returned a bot check/error page. Use full-page capture if needed, wait for a meaningful selector, or configure documented interactions. Confirm the target page is reachable to the capture service.
Image not visible after insertion Asset URL is not public, URL is expired, or image placement overlaps another image. Open the URL without authentication, verify current asset lifetime, and remove/replace old images before inserting refreshed ones.
Trigger succeeds manually but fails on schedule Trigger owner lost access, authorization was revoked, or scheduled runs exceed quotas/runtime. Check execution history, restore owner access and authorization, lower work per execution, and keep an operational owner assigned.
Runs take too long or time out Many targets, slow pages, full-page capture, or excessive waits. Split rows into smaller runs, choose appropriate readiness conditions, and schedule within provider and Apps Script limits.

8. Operational checklist

  • ☐ Each input row contains a valid absolute URL.
  • ☐ The report records capture time, screenshot URL, status, and enough context to identify failures.
  • ☐ The script owner and trigger owner are documented and retain spreadsheet access.
  • ☐ Credentials are restricted to script editors who are trusted with the API key.
  • ☐ Capture frequency and retry policy fit both Microlink capacity and Apps Script quotas.
  • ☐ Dynamic pages use a page-specific readiness signal rather than an arbitrary long delay.
  • ☐ The report’s image/link retention expectations match the provider’s current asset behavior.
  • ☐ Someone reviews failed executions and refreshes credentials or plan assumptions when terms change.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. One GET request returns a PNG, JPEG, WebP, or PDF; see the ScreenshotNeo API documentation for options and parameters. For a spreadsheet workflow, store the returned response or link from your script rather than managing a browser installation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up for free and try ScreenshotNeo.

FAQ

Can Google Sheets take a screenshot of a website by itself?

Sheets does not provide the website capture in this workflow. Apps Script calls a screenshot service, then stores or displays the returned asset.

Can I run this for a client or shared report?

Yes, if the script owner, trigger permissions, API plan, and sharing settings support the intended audience. Treat the API key as a secret and ensure image URLs are accessible to viewers if you insert or link them.

Will a scheduled trigger run at an exact minute?

No. Time-driven triggers are recurring scheduling tools, and Google may randomize execution time within an hourly window.

Should I keep every historical screenshot?

That depends on the report’s audit needs and the asset provider’s retention behavior. For durable history, maintain an explicit archive policy and verify that the image URLs remain available for the required period.

References