How to Download and Export Screenshots from LambdaTest
Use the documented LambdaTest API endpoints to retrieve individual screenshot URLs or a ZIP archive, with runnable cURL, Python, and Node.js examples.
To download screenshots from LambdaTest, now documented under the TestMu AI name, use the API endpoint that matches the run that produced them. Automated screenshot tests use a test_id: fetch the test details for individual image URLs or request a ZIP archive. Step-by-step browser automation screenshots use a session_id: request the session screenshots endpoint, which returns a URL for a ZIP archive. All three documented retrieval endpoints use HTTP Basic authentication with your LambdaTest username and access key.
Official references: Fetch specified screenshot details, Fetch Zipped Screenshots, and fetch all step-by-step screenshots.
Choose the right export endpoint
| Artifact | Identifier | Endpoint | Response gives you |
|---|---|---|---|
| Automated screenshot test | test_id |
GET https://api.lambdatest.com/screenshots/v1/{test_id} |
Test metadata and per-screenshot screenshot_url values |
| Automated screenshot test archive | test_id |
GET https://api.lambdatest.com/screenshots/v1/{test_id}/zip |
A url for the ZIP file |
| Browser automation step screenshots | session_id |
GET https://api.lambdatest.com/automation/api/v1/sessions/{session_id}/screenshots |
A url for the screenshots ZIP |
A test ID and session ID identify different kinds of runs. Use the ID from the same artifact type as the endpoint. The details endpoint returns metadata such as operating system, browser, browser version, status, activity ID, resolution, and image URLs. The two archive endpoints return a URL; download the ZIP from that URL in a separate request.
Prepare credentials and IDs
- Find the
test_idfor an automated screenshot test or thesession_idfor a browser automation session. - Get the account username and access key used for API authentication.
- Keep both values in environment variables or a secret manager. Do not commit credentials to source control or paste real credentials into shared logs.
The examples below use LT_USERNAME and LT_ACCESS_KEY. Set them in your shell before running the commands. The request authentication is Basic, with the username and access key as the credential pair.
export LT_USERNAME='your-username'
export LT_ACCESS_KEY='your-access-key'
export TEST_ID='your-test-id'
export SESSION_ID='your-session-id'
Download individual screenshots from an automated test
First request test details. The successful response is JSON; each item in screenshots can include a screenshot_url and a thumbnail_url. Use the screenshot URL for the full image. Check the test and screenshot statuses before treating an image as a completed result.
cURL
curl --fail-with-body --user "$LT_USERNAME:$LT_ACCESS_KEY" \
"https://api.lambdatest.com/screenshots/v1/$TEST_ID" \
--output screenshot-details.json
Python
import os
import requests
username = os.environ["LT_USERNAME"]
access_key = os.environ["LT_ACCESS_KEY"]
test_id = os.environ["TEST_ID"]
response = requests.get(
f"https://api.lambdatest.com/screenshots/v1/{test_id}",
auth=(username, access_key),
timeout=30,
)
response.raise_for_status()
data = response.json()
print("Test status:", data.get("test_status"))
for index, shot in enumerate(data.get("screenshots", []), start=1):
print(index, shot.get("status"), shot.get("resolution"), shot.get("screenshot_url"))
Node.js
const username = process.env.LT_USERNAME;
const accessKey = process.env.LT_ACCESS_KEY;
const testId = process.env.TEST_ID;
if (!username || !accessKey || !testId) throw new Error('Set LT_USERNAME, LT_ACCESS_KEY, and TEST_ID');
const auth = Buffer.from(`${username}:${accessKey}`).toString('base64');
const response = await fetch(`https://api.lambdatest.com/screenshots/v1/${encodeURIComponent(testId)}`, {
headers: { Authorization: `Basic ${auth}` },
signal: AbortSignal.timeout(30000),
});
if (!response.ok) throw new Error(`Details request failed: ${response.status} ${await response.text()}`);
const data = await response.json();
console.log('Test status:', data.test_status);
for (const shot of data.screenshots ?? []) {
console.log(shot.status, shot.resolution, shot.screenshot_url);
}
To save one returned image URL, make a separate GET request to that URL and write the response bytes to a file. These image URLs are provided by the API; the reference does not specify their lifetime. If a URL stops working, fetch the details again and use the current returned URL.
curl --fail --location "PASTE_SCREENSHOT_URL_FROM_JSON" --output screenshot.png
Download an automated test as a ZIP
This is the simplest route when you want the test’s screenshot set bundled together. The authenticated API response is JSON containing a url field. Extract that value, then download the archive from it.
cURL
curl --fail-with-body --user "$LT_USERNAME:$LT_ACCESS_KEY" \
"https://api.lambdatest.com/screenshots/v1/$TEST_ID/zip" \
--output zip-response.json
# Read the returned URL and download the archive:
ZIP_URL=$(python -c 'import json; print(json.load(open("zip-response.json"))["url"])')
curl --fail --location "$ZIP_URL" --output screenshots.zip
Python
import os
import requests
username = os.environ["LT_USERNAME"]
access_key = os.environ["LT_ACCESS_KEY"]
test_id = os.environ["TEST_ID"]
api_response = requests.get(
f"https://api.lambdatest.com/screenshots/v1/{test_id}/zip",
auth=(username, access_key),
timeout=30,
)
api_response.raise_for_status()
zip_url = api_response.json()["url"]
archive = requests.get(zip_url, timeout=90)
archive.raise_for_status()
with open("screenshots.zip", "wb") as output:
output.write(archive.content)
Node.js
import { writeFile } from 'node:fs/promises';
const username = process.env.LT_USERNAME;
const accessKey = process.env.LT_ACCESS_KEY;
const testId = process.env.TEST_ID;
if (!username || !accessKey || !testId) throw new Error('Set LT_USERNAME, LT_ACCESS_KEY, and TEST_ID');
const auth = Buffer.from(`${username}:${accessKey}`).toString('base64');
const apiResponse = await fetch(`https://api.lambdatest.com/screenshots/v1/${encodeURIComponent(testId)}/zip`, {
headers: { Authorization: `Basic ${auth}` },
signal: AbortSignal.timeout(30000),
});
if (!apiResponse.ok) throw new Error(`ZIP lookup failed: ${apiResponse.status} ${await apiResponse.text()}`);
const { url } = await apiResponse.json();
if (!url) throw new Error('The response did not contain a ZIP URL');
const zipResponse = await fetch(url, { signal: AbortSignal.timeout(90000) });
if (!zipResponse.ok) throw new Error(`Archive download failed: ${zipResponse.status}`);
await writeFile('screenshots.zip', Buffer.from(await zipResponse.arrayBuffer()));
The archive URL request is a separate download step. Follow redirects for the file download and do not send account credentials to the returned storage URL; the API documentation describes Basic authentication for the API endpoint, while the returned URL is the download target.
Download step-by-step screenshots from an automation session
For screenshots captured during browser automation, call the session endpoint using the session ID. Its successful response includes a message, status, and URL for the screenshot ZIP.
cURL
curl --fail-with-body --user "$LT_USERNAME:$LT_ACCESS_KEY" \
"https://api.lambdatest.com/automation/api/v1/sessions/$SESSION_ID/screenshots" \
--output session-screenshots-response.json
Then read url from the JSON and download it:
ZIP_URL=$(python -c 'import json; print(json.load(open("session-screenshots-response.json"))["url"])')
curl --fail --location "$ZIP_URL" --output session-screenshots.zip
Python
import os
import requests
response = requests.get(
f"https://api.lambdatest.com/automation/api/v1/sessions/{os.environ['SESSION_ID']}/screenshots",
auth=(os.environ["LT_USERNAME"], os.environ["LT_ACCESS_KEY"]),
timeout=30,
)
response.raise_for_status()
data = response.json()
if data.get("status") != "success" or not data.get("url"):
raise RuntimeError(f"Screenshot export did not return a ZIP URL: {data}")
archive = requests.get(data["url"], timeout=90)
archive.raise_for_status()
with open("session-screenshots.zip", "wb") as output:
output.write(archive.content)
Node.js
import { writeFile } from 'node:fs/promises';
const username = process.env.LT_USERNAME;
const accessKey = process.env.LT_ACCESS_KEY;
const sessionId = process.env.SESSION_ID;
if (!username || !accessKey || !sessionId) throw new Error('Set LT_USERNAME, LT_ACCESS_KEY, and SESSION_ID');
const auth = Buffer.from(`${username}:${accessKey}`).toString('base64');
const response = await fetch(`https://api.lambdatest.com/automation/api/v1/sessions/${encodeURIComponent(sessionId)}/screenshots`, {
headers: { Authorization: `Basic ${auth}` },
signal: AbortSignal.timeout(30000),
});
if (!response.ok) throw new Error(`Session screenshot lookup failed: ${response.status} ${await response.text()}`);
const data = await response.json();
if (data.status !== 'success' || !data.url) throw new Error(`No ZIP URL in response: ${JSON.stringify(data)}`);
const archive = await fetch(data.url, { signal: AbortSignal.timeout(90000) });
if (!archive.ok) throw new Error(`Archive download failed: ${archive.status}`);
await writeFile('session-screenshots.zip', Buffer.from(await archive.arrayBuffer()));
Save and inspect the exported files
After downloading a ZIP, extract it with your operating system’s archive utility or a standard ZIP library. Preserve the archive if you need to keep the original bundle. For automated tests, use the details JSON to associate images with their browser, OS, resolution, and activity metadata; filenames alone may not provide that context. Check for an empty archive or missing image if the corresponding test or screenshot status is not complete.
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| 401 Unauthorized | Missing or malformed Basic authentication, or incorrect username/access key. | Check both environment variables and ensure your HTTP client sends Basic auth as the credential pair. Do not manually base64-encode only one value. |
| 403 Forbidden | The authenticated account may not be permitted to access the requested artifact. | Verify the credentials and that the test or session belongs to an account you can access. |
| 404 Not Found | Wrong identifier type, mistyped ID, or no matching artifact at that route. | Use a test ID with the screenshots API and a session ID with the automation API. Confirm the ID from the run that generated the screenshots. |
| Details response has no usable image | The test or individual screenshot may not have completed, or the response may contain no screenshots. | Inspect test_status, each screenshot’s status, and whether screenshot_url is present before downloading. |
| API call succeeds but archive download fails | The second request to the returned URL failed, was not followed through a redirect, or the URL is no longer usable. | Check the HTTP status of the file request, enable redirect following, and call the authenticated endpoint again for a fresh returned URL. The reference does not state a URL expiry period. |
| Downloaded file is JSON or HTML instead of an image or ZIP | The API response was saved as though it were the artifact itself. | Parse the JSON response, extract screenshot_url or url, then make the separate download request. |
| Invalid ZIP or empty file | An error response or interrupted transfer may have been written to the archive path. | Check the response status before writing bytes, use a sufficiently long timeout, and retry the download after obtaining a valid URL. |
Performance, reliability, and cost
Retrieving a details document and downloading an image or ZIP are separate network operations. A ZIP usually requires one archive download, while saving individual images requires a request for each image URL. For large sets, stream downloads to disk rather than holding every image or the entire archive in memory. Use reasonable timeouts, check HTTP status before writing files, and retry transient network failures with bounded backoff. Avoid tight repeated polling; the cited retrieval references document the retrieval endpoints and response fields, but do not specify polling intervals, rate limits, archive size limits, URL lifetime, or service pricing. Check the current account documentation for those operational details.
Or skip the browser setup
If your goal is to capture a page as an image or PDF without configuring browser infrastructure, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. 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)
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}`);
- Cookie banners are accepted and removed before the capture, along with supported newsletter popups and chat widgets; each of these steps can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers report the page verdict and billing status.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for AI agents and MCP clients. - The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; all features are on every plan.
Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
FAQ
Can I use a test ID to fetch step-by-step screenshots?
No. The documented step-by-step route takes a browser automation session ID. Automated screenshot test results use the screenshot test routes.
Does the details endpoint return the image bytes?
No. It returns JSON metadata with screenshot URL fields. Request the image URL separately to download the image.
Does LambdaTest document how long the returned download URLs last?
The cited endpoint references show the URL fields but do not specify their validity period. If a URL fails, request the endpoint again and use the newly returned URL.
Is there a documented click-by-click dashboard export flow here?
The references used for this guide document API exports. For dashboard navigation, consult the current product interface rather than relying on unverified menu instructions.


