Scheduled screenshots
Register a page once with a daily or weekly rhythm: each run opens it in a real browser and compares it with the previous render, and you hear about it only when the page actually changed. Suited to pricing tables and terms pages. You pay per use, with no subscription.
Some pages need watching, not just capturing — a pricing table, a competitor's homepage, a terms page that quietly gets edited.
Why a one-off screenshot isn't enough
A single capture tells you what a page looked like once. Teams tracking a pricing page, a job listing, a status banner or a regulator's notice board want to know the moment it changes, not to eyeball it themselves. Building that yourself means running a server that never sleeps, rendering the page on a schedule, and diffing each run against the last — the actual job you wanted to outsource in the first place.
How the schedule works
You register a URL with a daily or weekly cadence and an optional time window; from then on each run loads the page in a real browser, waits for it to settle, and renders it. Each render is compared against the previous one, so instead of a stream of identical screenshots you get a signal only when the page actually changed.
A short history of watching pages
Before APIs like this existed, 'monitoring a page' usually meant a browser extension polling every few minutes on someone's laptop, or a fragile Selenium script glued to a cron job. Headless browser rendering made server-side capture reliable enough to run unattended; scheduling turns that reliability into a standing watch instead of a one-time favor.
What you can do with it
Competitor price watch
Watch a competitor's pricing page every morning and get pinged the day the page changes, without anyone opening a browser.
Uptime and layout sanity checks
Schedule a daily render of a critical landing page and get alerted when its appearance changes, catching a broken deploy or a missing hero image before customers do.
Compliance and audit trails
Watch a public disclosure or terms page weekly and get notified when it is edited, so a quiet change never slips past you.
Internal dashboard snapshots
Watch an internal metrics dashboard on a schedule and get a ping when what it shows changes, without exposing the dashboard to more logins.
FAQ
Is there a free tier?
There's no free tier — free tiers get abused and slow everyone down. No subscription, no tokens, no invented credits, and a failed task is never charged.
What happens if a run fails?
The task retries automatically up to three times; if it still fails you get a clear error and are not charged for that run.
Can I change the cadence later?
Yes, update the schedule's cadence or target URL at any time; future runs use the new settings, past runs are unaffected.
Does it hand me the screenshots?
No — this capability renders the page to detect changes and notifies you when the appearance differs from the last run; it does not deliver or archive the images themselves. To pull a page image on demand, use the one-off screenshot capability.
How long is old data kept?
Renders are used only to compare one run against the next and are never used for training; each change notification is the record that the page moved at that time.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
One authenticated POST creates the task; the result comes back by webhook or a signed link. This capability is currently available through the API, not as an interactive Web tool.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/web/screenshot-scheduled \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com"}'const res = await fetch("https://api.kit.forhosting.com/web/screenshot-scheduled", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://example.com"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/web/screenshot-scheduled",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"url": "https://example.com"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/web/screenshot-scheduled", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"url":"https://example.com"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"url":"https://example.com"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/web/screenshot-scheduled", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"url": "https://example.com"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "web.screenshot_scheduled",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
timeout_sec | 30 |
max_crawl_pages | 25 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
422 | task_failed | The task failed after 3 retries. You are never charged for it. |
Technical notes
This scheduled capture takes the work off your cron server: tell it a URL and a cadence, and on each run a real browser renders the page, compares it against the last render, and calls your webhook when it has changed.
What arrives, and when
You are not emailed an image or handed a gallery to scroll through — when a run's render differs from the one before it, the change is posted to your signed webhook with a timestamp, so your system learns a page moved without polling a dashboard. That keeps the pipeline entirely event-driven: no polling loop, no login, just a notification landing when something actually changed.
Where it fits in a pipeline
The diff runs for you: each scheduled render is checked against the last, so you get change detection without writing a scraper or standing up a browser farm. Point the change webhook at your alerting channel and a quiet page stays quiet, while an edited one pings you the day it happens.
Technical questions
How do I set up a scheduled screenshot?
Call POST /web/screenshot-scheduled with the URL, a daily or weekly cadence, and your webhook; from then on each run renders the page and compares it to the last, and you're billed per run.
How is it priced?
$0.040 per request plus $0.001 per URL, published and predictable — the same rate on every run, whether the schedule fires daily or weekly.
Do I need to poll for results?
No. When a run detects the page has changed, it posts a webhook with a timestamp; a run that finds no change is silent, so you only hear from it when something moved.