ScreenshotNeo

BlogHow-to

How to schedule website screenshots with Azure Functions

Use an Azure Functions timer trigger to schedule screenshot work, understand UTC and hosting limits, and choose a browser and image-storage approach.

By the ScreenshotNeo team4 October 20269 min read

To answer “How to schedule website screenshots with Azure Functions”: create a Timer trigger with an NCRONTAB schedule, then have its handler call a browser or screenshot service and save the result to an artifact destination you choose. The timer schedules code; it does not render the website or decide where screenshots are stored. Microsoft documents the timer and Azure Functions platform setup, but the reviewed Microsoft sources do not provide a general-purpose end-to-end recipe for launching a headless browser from a timer function and persisting captures. Validate browser compatibility and storage behavior for your chosen plan and workload before relying on it.

1. Separate scheduling, capture, and storage

A scheduled screenshot workflow has three parts:

  1. Schedule: Azure Functions invokes your function according to its timer trigger.
  2. Capture: Your handler requests or controls a browser, navigates to the target, and produces an image.
  3. Artifact storage: Your code writes the image to a destination with the access, retention, and naming policy you need.

The Functions host needs a default Azure Storage account for runtime operations. That requirement is separate from where your generated screenshots should live; the default account does not automatically define an artifact store. See Microsoft’s Azure Functions storage considerations.

Microsoft’s Foundry documentation describes Playwright Workspaces as headless browser infrastructure for Foundry browser automation and recording screenshots during browser sessions. It does not establish that a Playwright browser can be installed or run in every Functions plan, or give a timer-triggered screenshot-and-upload implementation. Treat it as an adjacent managed-browser option to investigate, not a drop-in recipe: Microsoft Foundry computer use documentation.

2. Choose and verify the schedule

Azure Functions timer triggers use NCRONTAB expressions. The six fields are second minute hour day month day-of-week. Azure Functions uses UTC by default. For example, 0 0 9 * * * means 9:00 AM in the effective timezone, which is UTC unless a supported timezone setting changes it.

Expression Meaning
0 */1 * * * * Every minute
0 0 */1 * * * At the start of every hour
0 0 9 * * * Every day at 9:00 AM
0 30 9 * * 1-5 Weekdays at 9:30 AM
0 0 */2 * * * Every two hours

These are calendar times, not elapsed intervals: the hour field value 5 means 5 AM, not “every five hours.” The NCRONTAB syntax and examples are documented in Microsoft’s Timer trigger reference.

Local wall-clock time and daylight saving

For local wall-clock scheduling, Microsoft documents WEBSITE_TIME_ZONE on Windows plans and Linux Premium or Dedicated plans. Windows uses Windows timezone names; Linux Premium and Dedicated use timezone database names. For instance, Eastern time is Eastern Standard Time on Windows and America/New_York on Linux. Where supported, the timezone setting accounts for daylight and standard time changes.

Do not set WEBSITE_TIME_ZONE or TZ on Linux Consumption or Flex Consumption. Microsoft says these settings are unsupported there and can cause SSL-related issues and broken metrics. If using one of these plans, schedule in UTC and calculate the UTC schedule you require, including daylight-saving changes if your desired local time shifts seasonally.

Expression versus interval

Use NCRONTAB for recurring calendar schedules and for Consumption or Flex Consumption apps. A TimeSpan interval is available only on an App Service Plan; Consumption and Flex Consumption scale controllers require CRON expressions. The timer schedule can also refer to an app setting by wrapping its name in percent signs, for example %ScreenshotSchedule%, which lets the deployment configuration supply the expression.

3. Create the timer-triggered function

The following Python example shows the scheduling portion of a screenshot workflow. It is a runnable timer handler that logs invocation and past-due status; the capture function is deliberately a placeholder because the reviewed Azure sources do not establish a generally supported browser launch and artifact upload recipe for Functions. Add your validated capture and storage implementation at that boundary.

import datetime
import logging
import azure.functions as func

app = func.FunctionApp()

@app.function_name(name="scheduledScreenshot")
@app.timer_trigger(
    schedule="0 0 9 * * *",
    arg_name="timer",
    run_on_startup=False,
    use_monitor=True,
)
def scheduled_screenshot(timer: func.TimerRequest) -> None:
    now = datetime.datetime.now(datetime.timezone.utc).isoformat()
    if timer.past_due:
        logging.warning("Screenshot schedule invocation is past due")

    logging.info("Scheduled screenshot job started at %s", now)

    # Add the browser or screenshot-service request here.
    # Then save the returned image to your chosen artifact destination.

    logging.info("Scheduled screenshot job finished")

For a screenshot job, make the capture and save steps observable: log a stable job identifier, target URL, schedule timestamp, capture outcome, storage outcome, and elapsed time. Avoid logging credentials, authorization headers, or sensitive page content.

Configure the expression outside code

If the schedule should differ by deployment environment, define an app setting named ScreenshotSchedule with the desired NCRONTAB expression and use schedule="%ScreenshotSchedule%". Set the same key in local settings while developing. Keep the Azure Functions host storage configuration separate from screenshot artifact configuration.

Develop locally and deploy

  1. Start with Microsoft’s scheduled tasks quickstart for your language and local development workflow.
  2. Configure AzureWebJobsStorage for the Functions host. The quickstart uses Azurite for local verification.
  3. Run the function locally and inspect host logs to confirm it fires at the expected cadence. Microsoft’s scheduled function tutorial also demonstrates verifying timer execution in logs.
  4. Deploy to the chosen Functions plan using the documented workflow. The quickstart covers deployment to Flex Consumption; confirm the selected language, operating system, plan, and any browser requirements separately.
  5. In Azure, inspect invocation logs and perform a controlled capture to validate target access, image output, and durable storage permissions.

Functions requires access to a default Azure Storage account. Local emulation helps verify the host workflow, but it does not establish that a browser runtime or your selected screenshot artifact destination is configured correctly in Azure.

4. Implement the capture boundary carefully

Before choosing a browser package or managed screenshot service, validate these requirements for the exact operating system and hosting plan:

  • Can the browser binary and its system dependencies run in the selected environment?
  • Do memory limits and maximum execution duration fit navigation, rendering, and upload time?
  • Can the function reach the target website, including any private network routes, authentication, or IP allowlists?
  • What happens when navigation, page rendering, or the screenshot operation fails?
  • Where is the image stored, how is it named, how long is it retained, and who can read it?
  • Can a retry safely avoid producing duplicate artifacts or overwriting a good capture?

This boundary matters for long-running pages, large full-page images, authenticated sites, and targets protected by bot checks. The timer invokes the handler; browser lifecycle, screenshot fidelity, browser compatibility, and artifact persistence remain implementation decisions.

5. Make runs reliable and observable

Timer monitoring persists schedule occurrences to help keep the schedule maintained across app restarts. The timer object also exposes whether an invocation is past due. These features describe schedule behavior; they do not define a screenshot retry policy or guarantee a successful capture.

  • Missed invocation: Decide whether a past-due run should capture immediately, skip if a newer scheduled capture is due soon, or enqueue catch-up work.
  • Duplicate capture: Use an idempotency key based on the target and scheduled time, or make artifact writes versioned so a restart or retry does not silently corrupt the history.
  • Navigation failure: Set a timeout appropriate to your page and record a failure result; do not report the schedule as a successful screenshot merely because the function started.
  • Storage failure: Track capture success separately from upload success. Choose whether to retry upload, preserve the image temporarily, or fail the job for operator attention.
  • Concurrency: Ensure a slow run cannot overlap in a way that violates your storage naming or target-site limits. Define the behavior if a capture takes longer than the schedule interval.
  • Startup behavior: Keep runOnStartup false for predictable recurring work. Microsoft cautions that startup execution can occur on host startup, wake, restart, or scale events and can create unexpected extra invocations and charges.

Do not assume a generic retry policy from the timer documentation. Define retries for browser and storage failures in your own workflow, and make repeated attempts safe.

6. Performance, cost, and operational tradeoffs

Capture resource use depends on the page, browser runtime, image dimensions, and storage path. No performance benchmark or comparative cost figure is established by the sources used here, so measure your workload in the chosen hosting plan. Track duration, memory where available, image size, failed navigation rate, and storage latency.

The Microsoft portal tutorial provisions Azure resources including storage and Application Insights and notes that resources may incur charges depending on account status. Treat the timer cadence as a cost driver: a frequent schedule produces more invocations and potentially more browser work. Avoid enabling runOnStartup casually, since unexpected starts can add executions. Review current Azure pricing for your own region and plan before estimating spend; no price is quoted here.

For reliability, retain enough logs to distinguish “timer fired,” “page captured,” and “artifact stored.” For cost control, set a cadence that matches the monitoring need, bound navigation time, and set artifact retention in the storage system you choose.

7. Troubleshooting

Symptom Likely cause What to check or fix
Timer never fires Invalid NCRONTAB, function not enabled, or host configuration issue Check the six-field expression and function host logs. The portal’s test view can show a 404 for an invalid expression; Application Insights can contain more detail.
Runs at the wrong local time Schedules default to UTC, or timezone setting is unsupported/misconfigured Confirm the effective timezone and platform. Use a supported WEBSITE_TIME_ZONE only on documented OS/plan combinations. On Linux Consumption or Flex Consumption, remove WEBSITE_TIME_ZONE and TZ.
Runs unexpectedly after restart or scale runOnStartup enabled Set it to false unless startup capture is explicitly required; use the recurring schedule for cadence.
Local timer fails to start Missing or invalid AzureWebJobsStorage Configure the local storage connection and Azurite as in Microsoft’s scheduled-task quickstart.
Function runs, but no screenshot appears Timer is healthy but capture implementation, browser compatibility, target access, or artifact write failed Separate capture and upload logs. Verify browser binaries/dependencies, network/auth access, memory and duration, and destination credentials.
Screenshot appears more than once Past-due handling, manual invocation, retry, or startup execution produced repeated work Log scheduled timestamps and invocation IDs; use idempotent artifact naming and decide a catch-up policy.
Runs are delayed Host restart, load, long-running invocation, or configuration issue Inspect invocation timestamps and past-due status. Measure browser and upload duration, and decide how missed schedules should be handled.

8. Or skip the browser setup

Instead of managing a browser runtime and screenshot artifact flow in the timer function, you can call ScreenshotNeo, a website screenshot API and MCP server. Its API returns a screenshot or PDF from one GET request. The documented API options include full-page capture with lazy images loaded, element selection, viewport and device presets, dark mode, custom CSS and JavaScript, waits, request blocking, headers and cookies, caching, and asynchronous jobs. See the ScreenshotNeo API documentation.

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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An 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. For recurring automation, your scheduler can invoke the API on its cadence and store the returned artifact wherever your workflow requires.

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

9. FAQ

Does the timer trigger take the screenshot by itself?

No. It invokes your function on schedule. Your handler must perform or request the capture and decide where to store the result.

Can I run a capture every hour?

Yes. For example, 0 0 */1 * * * runs at the start of every hour in the effective timezone.

Will a scheduled screenshot run at the same local time all year?

Only when the timezone setting is supported and configured for the hosting plan and operating system. Otherwise the timer uses UTC by default.

Does Azure Functions storage automatically hold my screenshot files?

No. Functions needs a default storage account for runtime needs, but your workflow must explicitly write screenshot artifacts to a destination.

Can I test the screenshot browser integration from Microsoft’s timer tutorial?

The timer tutorial verifies scheduling. Browser runtime compatibility and screenshot upload need separate validation for your chosen plan and implementation.