Mobile screenshot
A page that looks flawless on a laptop can hide a broken nav menu on an actual phone. This endpoint renders a URL through real device viewports — specific phones, specific tablets — so what you see is genuinely what a mobile visitor sees, not a resized browser window pretending to be one.
Run it online
Run this on our servers with your account. Free tools run in your browser; this one bills your KIT balance per the price above.
Desktop-shaped testing on a mobile-first web
Most traffic to most sites is mobile, yet a lot of visual QA still happens by shrinking a desktop browser window, which approximates layout but misses the details that actually break mobile experiences: how a sticky footer behaves on an iPhone's safe area, how a responsive image crops on a narrower Android viewport, whether a modal covers the address bar in a way that traps a user. Testing on the real device shapes catches what a resized window quietly hides.
How the rendering works
Send POST /web/screenshot-device with a URL and a target device profile, and the task renders the page using that device's actual viewport dimensions, pixel density and user-agent behavior — iPhone, Android handset, or tablet — so fonts, breakpoints and touch-target sizing all render as they would on the physical hardware. Like every task in the catalog it runs asynchronously, returning a task_id immediately and delivering the image via signed webhook or a signed link valid for 24 hours.
Why device-accurate matters more each year
Responsive design was meant to solve this with fluid layouts, but breakpoints are still developer guesses about where content should reflow, and those guesses are frequently wrong for the long tail of screen sizes actually in use — a foldable phone, an older Android with a different aspect ratio, an iPad in split-screen. Rendering against real device profiles instead of a handful of common breakpoints is what turns 'it should work' into 'it does work.'
Common use inside a team
Mobile QA teams verifying a checkout flow across phone models before a release, marketing teams confirming an ad landing page renders cleanly on the devices campaign traffic actually uses, design teams reviewing how a redesign holds up on a tablet in addition to a phone, and support teams reproducing a bug a customer reported from a specific device.
Automating device checks
At a $0.040 base per request plus $0.001 per URL, running the same page through several device profiles on every deploy stays affordable to schedule regularly. Failed captures are never billed — the task retries up to three times before returning a clear error — so it's safe to wire into a release pipeline that screenshots a staging URL across a device matrix without manual review of every run.
What you can do with it
Pre-release mobile QA
A team screenshots the checkout flow across iPhone and Android profiles before shipping to catch layout breaks a desktop preview would miss.
Ad landing page checks
A performance marketing team verifies a landing page renders cleanly on the specific device types driving the most campaign clicks.
Design review on tablets
A design team reviews how a new layout holds up on a tablet viewport in addition to phone sizes before sign-off.
Bug reproduction
A support team captures a page exactly as a customer's reported device would render it to confirm or rule out a device-specific bug.
FAQ
What devices can the mobile screenshot API render?
Common device profiles including iPhone, Android handsets and tablets, each using that device's real viewport dimensions and pixel density.
How is this different from just resizing a browser window?
It renders against the actual viewport, pixel density and user-agent behavior of the target device rather than approximating it by shrinking a desktop browser.
Is there a free trial?
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's the pricing?
A $0.040 base per request plus $0.001 per URL, published upfront with no hidden per-device surcharge.
Can I capture the same page across multiple devices at once?
Yes, submit one async request per device profile; each is billed and processed independently, which suits a full device matrix per release.
How do I get the screenshot back?
Via signed webhook when the task finishes, or a signed link valid for 24 hours.
Does it handle responsive breakpoints correctly?
Yes, because it renders through the actual device viewport, content reflows exactly as it would on that physical device rather than at an approximated breakpoint.
What if a capture fails?
It retries automatically up to three times and is never charged on failure; a clear error is returned once retries are exhausted.
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
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, and soon from our app, email and Telegram.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/web/screenshot-device \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://ejemplo.com"}'const res = await fetch("https://api.kit.forhosting.com/web/screenshot-device", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://ejemplo.com"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/web/screenshot-device",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"url": "https://ejemplo.com"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/web/screenshot-device", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"url":"https://ejemplo.com"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"url":"https://ejemplo.com"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/web/screenshot-device", 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://ejemplo.com"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "web.screenshot_device",
"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. |