How to Schedule Website Screenshots on an Android Tablet Using a Browser Automation Server in India
Schedule Playwright to capture Chrome on an Android tablet through ADB, then save each screenshot from a host in India Standard Time.
To schedule website screenshots on an Android tablet, run a capture script on an always-available host and use Playwright’s experimental Android support to control Chrome on the tablet through authenticated ADB. The host scheduler decides when the script runs; Chrome on the tablet renders the site; the script saves the image. This guide uses Node.js, Playwright, and GitHub Actions as one documented scheduling option.
Playwright describes Android automation as experimental. It supports Chrome for Android and Android WebView, but compatibility is not universal. The device must be awake to produce screenshots. Check the Playwright Android API requirements and limitations before relying on this setup.
1. Understand the architecture
The workflow has two separate parts: scheduling and capture.
- A scheduler on a host starts the Node.js script at the configured time.
- The script connects to the tablet through ADB and Playwright’s Android interface.
- Playwright opens Chrome on the tablet, loads the page, and saves a screenshot.
- The host stores the output as a local file or uploads it to a destination you configure.
The tablet is the browser target, not the scheduler. Keep the host online and the tablet connected, awake, and ready when the run begins.
2. Prepare the Android tablet and host
Playwright’s documented Android setup calls for an Android device or AVD emulator, an authenticated ADB connection, Chrome 87 or newer, and the Chrome flag named “Enable command line on non-rooted devices.” The device also needs to be awake when screenshots are taken. The Playwright Android API uses ADB; it does not directly automate a tablet over a raw USB connection.
- Install Android Debug Bridge (ADB) on the host that will run the scheduler.
- Enable developer options and USB debugging on the tablet, then connect it to the host or arrange another authenticated ADB connection.
- On the tablet, open
chrome://flags, enable “Enable command line on non-rooted devices,” and relaunch Chrome as prompted. - Confirm Chrome is version 87 or newer.
- From the host, run
adb devicesand accept the debugging authorization prompt on the tablet. Confirm the device appears as authorized. - Keep the tablet powered and awake during scheduled runs. A setup suggestion is to use a suitable USB data cable if connecting by wire; cable choice and device compatibility depend on the ports and hardware available.
These are documented prerequisites, not a guarantee that every tablet or Chrome build will work with the experimental API.
3. Install Playwright and make a capture script
Use a currently supported Node.js installation on the host, then create a project and install Playwright:
mkdir android-site-capture
cd android-site-capture
npm init -y
npm install playwright
Create capture.mjs with the following code. It follows Playwright’s Android connection pattern, stops Chrome if it is already running, opens a page, navigates to a target, waits for a page-specific readiness signal, and saves a PNG.
import { _android as android } from 'playwright';
import { mkdir } from 'node:fs/promises';
const targetUrl = process.env.TARGET_URL ?? 'https://example.com';
const outputDir = process.env.OUTPUT_DIR ?? 'screenshots';
const readySelector = process.env.READY_SELECTOR;
if (!/^https?:\/\//i.test(targetUrl)) {
throw new Error('TARGET_URL must be an http or https URL');
}
await mkdir(outputDir, { recursive: true });
let device;
try {
const devices = await android.devices();
if (devices.length === 0) {
throw new Error('No Android device found. Check ADB authorization and connection.');
}
// If more than one tablet or emulator is attached, select one explicitly.
const requestedSerial = process.env.ANDROID_SERIAL;
device = requestedSerial
? devices.find((item) => item.serial() === requestedSerial)
: devices[0];
if (!device) {
throw new Error(`No Android device found with serial ${requestedSerial}`);
}
await device.shell('am force-stop com.android.chrome');
const context = await device.launchBrowser();
try {
const page = await context.newPage();
await page.goto(targetUrl, { waitUntil: 'domcontentloaded', timeout: 60000 });
if (readySelector) {
await page.locator(readySelector).waitFor({ state: 'visible', timeout: 30000 });
}
const stamp = new Date().toISOString().replaceAll(':', '-');
const outputPath = `${outputDir}/page-${stamp}.png`;
await page.screenshot({ path: outputPath, fullPage: true });
console.log(`Saved ${outputPath}`);
} finally {
await context.close();
}
} finally {
await device?.close();
}
Run it manually first. Set the target and output directory explicitly:
TARGET_URL='https://example.com' OUTPUT_DIR='./screenshots' node capture.mjs
For a page that renders important content after navigation, set a selector that appears only when the content is ready:
TARGET_URL='https://example.com/dashboard' READY_SELECTOR='main .report-ready' node capture.mjs
Replace the example selector with one from the target page. The code uses domcontentloaded as the initial navigation condition because many sites keep network connections open. A selector wait is optional and should reflect the page’s actual readiness condition; there is no single wait that makes every dynamic page ready.
The Android API documentation shows the connection and browser-launch flow, including page.screenshot({ path: 'page.png' }). See the Android API documentation and the Playwright screenshot guide for the full API details.
4. Choose the screenshot type and output
Decide whether you need a browser page image or a picture of the entire device before scheduling:
| Need | Method | Notes |
|---|---|---|
| Visible browser page | page.screenshot({ path: 'page.png' }) |
Captures the page at its current scroll position. |
| Whole page, including content below the fold | page.screenshot({ path: 'page.png', fullPage: true }) |
Captures the full page extent; it is not a physical device screenshot. |
| Specific element | await page.locator('.report').screenshot({ path: 'report.png' }) |
Useful for a chart, card, or other selected page element. |
| Image bytes for custom handling | const bytes = await page.screenshot() |
Returns a buffer, so the script can upload or process it rather than save directly to a path. |
| Entire Android display | await device.screenshot({ path: 'device.png' }) |
Captures the device screen, rather than only the browser page. |
For example, replace the full-page call in the script with an element capture:
const report = page.locator('.report');
await report.waitFor({ state: 'visible', timeout: 30000 });
await report.screenshot({ path: `${outputDir}/report.png` });
For buffer capture, the caller must decide how to store or transmit the returned bytes. The screenshot guide documents ordinary, full-page, buffer, and element screenshots; consult it for current options and behavior.
5. Schedule the script in India Standard Time
Schedule only after the manual capture works. GitHub Actions supports scheduled workflows using cron syntax. Its documentation says schedules default to UTC, accepts an optional IANA timezone, and has a shortest supported interval of five minutes. Configure the timezone explicitly for India Standard Time (Asia/Kolkata) where the workflow syntax in use supports it, and verify the schedule in the current GitHub reference. Do not assume a cron expression is interpreted as Indian local time by default.
Example workflow structure:
name: Scheduled Android screenshot
on:
schedule:
- cron: '30 9 * * 1-5'
timezone: 'Asia/Kolkata'
workflow_dispatch:
jobs:
capture:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- name: Capture page on attached tablet
env:
TARGET_URL: https://example.com
OUTPUT_DIR: screenshots
ANDROID_SERIAL: ${{ secrets.ANDROID_SERIAL }}
run: node capture.mjs
- uses: actions/upload-artifact@v4
with:
name: android-site-screenshots
path: screenshots/*.png
This example assumes a self-hosted Actions runner on a host with ADB installed and the tablet connected and authorized. A hosted runner generally cannot see a tablet physically attached to your own machine. Store the device serial as a secret only if you have chosen to treat it as sensitive configuration; adapt the artifact retention and storage to your needs. The example schedules weekdays at 09:30 India time only if the configured timezone field is supported by the workflow environment.
Alternatively, use the host’s local scheduler, such as cron or a service manager. Confirm the host timezone, whether the host remains online, and what happens after downtime. Scheduling systems may skip a run or start it later after downtime, depending on their configuration. For a local crontab using a host configured to India time, the schedule could be:
30 9 * * 1-5 cd /path/to/android-site-capture && TARGET_URL='https://example.com' OUTPUT_DIR='./screenshots' /usr/bin/node capture.mjs >> capture.log 2>&1
Use the actual project path and Node.js executable path on the host. If the host clock is UTC, convert the intended local schedule or configure the scheduler’s timezone explicitly. GitHub’s schedule reference is the authority for its current syntax and timezone behavior: GitHub Actions scheduled workflows.
6. Name, retain, and inspect screenshot artifacts
The script uses a timestamp in each filename to avoid overwriting prior runs. Pick an explicit output directory and decide how long to keep captures. A scheduler reporting a successful job means the job ran; it does not prove the page rendered correctly or that the output was retained.
- Keep a predictable folder structure, such as one subdirectory per site or job.
- Choose an artifact retention period appropriate to the comparison or audit task.
- Check that the file exists and has nonzero size after capture.
- For visual monitoring, inspect representative screenshots and add page-specific readiness checks.
- For longer retention, upload files to storage configured by your organization instead of relying only on a temporary runner workspace.
7. Secure the Android automation endpoint
Playwright’s Android WebSocket host defaults to localhost. Keep it local unless remote control is an intentional requirement with network access restricted. Binding the server to a reachable interface can expose device control: Playwright warns that someone who knows the WebSocket path may be able to control the operating system user.
Do not expose an unauthenticated Android automation endpoint to the public internet. If a remote design is required, restrict network reachability, protect the endpoint and path, and review the current Playwright security guidance before deployment.
8. Troubleshoot common failures
| Symptom | Likely cause | What to check |
|---|---|---|
| No Android devices found | ADB is unavailable, the device is disconnected, or debugging has not been authorized. | Run adb devices, accept the prompt on the tablet, and confirm the device state is authorized. |
| More than one device is connected | The script selected the first device returned. | Set ANDROID_SERIAL to the intended device serial. |
| Browser launch fails | Chrome is too old, the required Chrome flag is off, or this device/build is incompatible with experimental support. | Check Chrome 87 or newer, enable “Enable command line on non-rooted devices,” relaunch Chrome, and review Playwright’s Android requirements. |
| Screenshot is blank or stale | The tablet may be asleep, the page may not have finished rendering, or the capture method may target the wrong surface. | Keep the device awake, wait for a page-specific selector, and choose between page.screenshot and device.screenshot based on the desired result. |
| Navigation times out | The page may be slow, unreachable, or waiting on long-lived network activity. | Check URL reachability from the tablet, use a suitable navigation condition, and wait for a meaningful selector instead of requiring all network activity to stop. |
| Scheduled job runs at the wrong time | The schedule is being interpreted as UTC or its timezone configuration is missing or unsupported. | Set Asia/Kolkata where supported, or convert the intended local time to UTC; verify the active scheduler’s syntax. |
| Job succeeds but no artifact is available | The output path does not match the upload step, the working directory differs, or the scheduler did not retain the workspace. | Log the output path, use an absolute or known project-relative directory, and verify the artifact upload path and retention configuration. |
| Remote controller cannot connect | The server is bound only to localhost, or network policy blocks access. | Prefer local control. If remote control is required, configure restricted access and secure the WebSocket endpoint; do not expose it publicly. |
9. Reliability, performance, and cost considerations
This approach depends on several things being available at the scheduled time: the host and scheduler, an authenticated ADB connection, an awake tablet, a compatible Chrome version, and the target website. A failure in any one can prevent a capture. Because Playwright Android support is experimental, validate the workflow on the exact device and software versions you plan to operate, then monitor both job status and resulting images.
Capture duration varies with the target site, network conditions, device, and readiness criteria. Full-page screenshots can require more rendering and produce larger files than viewport captures. Use the narrowest capture that answers your monitoring question, and avoid arbitrarily long waits that make a schedule fall behind.
The browser automation software and scheduler do not establish a cost for the tablet, host, network, or artifact storage. Account for the host that must remain available, storage and retention, and any infrastructure you choose. This guide does not assume a particular tablet model, India price, or performance level.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. Its one-call API captures a URL without requiring you to manage Playwright or an Android device:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
See the ScreenshotNeo API documentation for the request options and authentication details. Python and Node.js versions are also available:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
ScreenshotNeo removes cookie banners, 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; paid plans start at $5 for 3,000. Sign up for free and get 1,000 screenshots a month with no card.
Frequently asked questions
Can I take a screenshot of the whole tablet screen?
Yes. Use Playwright Android’s device screenshot method for the Android display. Use the page screenshot method when you want the browser page itself.
Can I schedule a capture every minute?
GitHub Actions documents a shortest scheduled interval of five minutes. Other schedulers have their own limits and delivery behavior.
Does the tablet have to be in India?
No special Playwright browser setting is tied to India. India matters here for the operator’s local schedule; use the scheduler’s timezone configuration or convert the desired time carefully.


