Scheduled screenshots
Some pages need watching, not just capturing — a pricing table, a competitor's homepage, a terms page that quietly gets edited. 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.
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.
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.
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.
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.
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
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.
Is there a free tier?
There's no free tier — free tiers get abused and slow everyone down. Access runs on a prepaid ForHosting KIT balance: top up from $10.00 (it never expires) and each request is charged at its published price, so a call with no balance returns HTTP 402. 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.
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.
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.
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. |