> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gravixlayer.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Capture & Downloads

> Screenshots, PDFs, file downloads, and live watch URLs

Getting output out of the browser: page screenshots (viewport, full page, or a
single element), PDF rendering, file downloads with their bytes, and a live
watch URL a human can open.

CLI and cURL examples assume `$RT` holds a `browser-small` runtime id with
browser `b1` open (see
[Browser Sessions](/documentation/agentruntime/browser-use/browser)).

## Endpoints

| Method | Path | Description |
| - | - | - |
| POST | `/v1/agents/runtime/{runtime_id}/browser/{browser_id}/screenshot` | Page capture (base64) |
| POST | `/v1/agents/runtime/{runtime_id}/browser/{browser_id}/targets/{target_id}/pdf` | Render a tab to PDF |
| GET | `/v1/agents/runtime/{runtime_id}/browser/{browser_id}/downloads` | List downloads |
| POST | `/v1/agents/runtime/{runtime_id}/browser/{browser_id}/downloads` | Wait for a download |
| GET | `/v1/agents/runtime/{runtime_id}/browser/{browser_id}/downloads/{download_id}` | Download bytes or metadata |
| POST | `/v1/agents/runtime/{runtime_id}/browser/{browser_id}/view` | Mint a live-watch URL |

## Screenshot

`screenshot` captures the page — the viewport by default, `full_page` for the
whole scrollable document, or `element` to clip to one element. Returns
`{data, format, width, height}` with `data` base64.

```python Python theme={"dark"}
import base64
from gravixlayer import GravixLayer

client = GravixLayer()  # reads GRAVIXLAYER_API_KEY
sandbox = client.runtime.create(template="browser-small")
bid = sandbox.browser.open(url="https://example.com")["browser_id"]

shot = sandbox.browser.screenshot(bid, full_page=True)
with open("page.png", "wb") as f:
    f.write(base64.b64decode(shot["data"]))

# One element — any target form (ref, css, text, …)
el = sandbox.browser.screenshot(bid, element={"by": "css", "value": "h1"})
print(el["width"], el["height"])
sandbox.kill()
```

```typescript TypeScript theme={"dark"}
import { writeFileSync } from 'node:fs';
import { GravixLayer } from 'gravixlayer';

const client = new GravixLayer(); // reads GRAVIXLAYER_API_KEY
const sandbox = await client.runtime.create({ template: 'browser-small' });
const bid = (await sandbox.browser.open({ url: 'https://example.com' })).browserId;

const shot = await sandbox.browser.screenshot(bid, { fullPage: true });
writeFileSync('page.png', Buffer.from(shot.data, 'base64'));

// One element — any target form (ref, css, text, …)
const el = await sandbox.browser.screenshot(bid, { element: { by: 'css', value: 'h1' } });
console.log(el.width, el.height);
await sandbox.kill();
```

```bash CLI theme={"dark"}
gravixlayer runtime browser navigate "$RT" --browser b1 https://example.com
gravixlayer runtime browser screenshot "$RT" --browser b1 --out page.png --full-page
gravixlayer runtime browser screenshot "$RT" --browser b1 --out h1.png --element "css:h1"
```

```bash cURL theme={"dark"}
API="https://api.gravixlayer.ai/v1"

curl -sS -X POST "$API/agents/runtime/$RT/browser/b1/navigate" \
  -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com"}'

curl -sS -X POST "$API/agents/runtime/$RT/browser/b1/screenshot" \
  -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"full_page":true,"format":"png"}' | jq -r .data | base64 -d > page.png
```

| Parameter | Type | Required | Description |
| - | - | - | - |
| `target_id` | string | No | Tab (empty = current tab) |
| `format` | string | No | `png` (default) or `jpeg` |
| `full_page` | bool | No | Whole scrollable page |
| `element` | ElementTarget | No | Clip to one element — see [Targeting elements](/documentation/agentruntime/browser-use/actions#targeting-elements) |
| `quality` | int | No | JPEG quality 1–100 |
| `wait_stable_ms` | int | No | Wait for a pixel-quiet frame first |
| `timeout_ms` | int | No | Overall timeout |

## PDF

`pdf` renders a tab to PDF — invoices, reports, printable views. The tab's
`target_id` is in the path; read it from `targets`. Returns `{data, format}`
with `data` base64.

```python Python theme={"dark"}
import base64
from gravixlayer import GravixLayer

client = GravixLayer()
sandbox = client.runtime.create(template="browser-small")
bid = sandbox.browser.open(url="https://example.com")["browser_id"]
tid = sandbox.browser.targets(bid)["targets"][0]["target_id"]

pdf = sandbox.browser.pdf(bid, tid, landscape=True,
                          margins_in={"top": 0.5, "bottom": 0.5})
with open("page.pdf", "wb") as f:
    f.write(base64.b64decode(pdf["data"]))
sandbox.kill()
```

```typescript TypeScript theme={"dark"}
import { writeFileSync } from 'node:fs';
import { GravixLayer } from 'gravixlayer';

const client = new GravixLayer();
const sandbox = await client.runtime.create({ template: 'browser-small' });
const bid = (await sandbox.browser.open({ url: 'https://example.com' })).browserId;
const tid = (await sandbox.browser.targets(bid)).targets[0].targetId;

const pdf = await sandbox.browser.pdf(bid, tid, {
  landscape: true,
  marginsIn: { top: 0.5, bottom: 0.5 },
});
writeFileSync('page.pdf', Buffer.from(pdf.data, 'base64'));
await sandbox.kill();
```

```bash CLI theme={"dark"}
TID=$(gravixlayer runtime browser targets "$RT" --browser b1 --output json \
  | jq -r '.targets[0].target_id')
gravixlayer runtime browser pdf "$RT" --browser b1 "$TID" --out page.pdf --landscape
```

```bash cURL theme={"dark"}
API="https://api.gravixlayer.ai/v1"

TID=$(curl -sS -X POST "$API/agents/runtime/$RT/browser/b1/targets" \
  -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}' | jq -r '.targets[0].target_id')

curl -sS -X POST "$API/agents/runtime/$RT/browser/b1/targets/$TID/pdf" \
  -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"landscape":true,"print_background":true,"margin_top_in":0.5,"margin_bottom_in":0.5}' \
  | jq -r .data | base64 -d > page.pdf
```

| Parameter | Type | Required | Description |
| - | - | - | - |
| `landscape` | bool | No | Landscape orientation |
| `print_background` | bool | No | Include background graphics (default `true`) |
| `page_ranges` | string | No | e.g. `1-3,5` |
| `paper_width_in`, `paper_height_in` | float | No | Paper size in inches |
| `margin_top_in`, `margin_bottom_in`, `margin_left_in`, `margin_right_in` | float | No | Margins in inches — the SDKs take `margins_in` / `marginsIn` as `{top, bottom, left, right}` |

## Downloads

Files the page downloads are saved inside the runtime. `GET /downloads` lists
them; `POST /downloads` with `wait_name` blocks until a file whose name
contains `wait_name` finishes — the pattern after clicking a download link —
and returns the list, or `408` after `timeout_ms` (default 30000).
`GET /downloads/{download_id}` returns `{entry, data}` with the file's bytes
base64 in `data` (`null` with `?meta_only=true`).

```python Python theme={"dark"}
import base64
from gravixlayer import GravixLayer

client = GravixLayer()
sandbox = client.runtime.create(template="browser-small")
page = "data:text/html,<a download=report.csv href=data:text/csv,id,name>Export</a>"
bid = sandbox.browser.open(url=page)["browser_id"]

sandbox.browser.click(bid, {"by": "text", "value": "Export"})

# Block until the file lands, then fetch its bytes
dls = sandbox.browser.downloads(bid, wait_name="report", timeout_ms=30_000)
entry = next(d for d in dls["downloads"] if "report" in d["filename"])
got = sandbox.browser.download(bid, entry["id"])
with open(entry["filename"], "wb") as f:
    f.write(base64.b64decode(got["data"]))
sandbox.kill()
```

```typescript TypeScript theme={"dark"}
import { writeFileSync } from 'node:fs';
import { GravixLayer } from 'gravixlayer';

const client = new GravixLayer();
const sandbox = await client.runtime.create({ template: 'browser-small' });
const page = 'data:text/html,<a download=report.csv href=data:text/csv,id,name>Export</a>';
const bid = (await sandbox.browser.open({ url: page })).browserId;

await sandbox.browser.click(bid, { by: 'text', value: 'Export' });

// Block until the file lands, then fetch its bytes
const dls = await sandbox.browser.downloads(bid, { waitName: 'report', timeoutMs: 30_000 });
const entry = dls.find((d) => d.filename.includes('report'))!;
const got = await sandbox.browser.download(bid, entry.id);
writeFileSync(entry.filename, Buffer.from(got.data!, 'base64'));
await sandbox.kill();
```

```bash CLI theme={"dark"}
gravixlayer runtime browser navigate "$RT" --browser b1 \
  "data:text/html,<a download=report.csv href=data:text/csv,id,name>Export</a>"
gravixlayer runtime browser action "$RT" --browser b1 click --target "text:Export"

gravixlayer runtime browser downloads "$RT" --browser b1
DID=$(gravixlayer runtime browser downloads "$RT" --browser b1 --output json \
  | jq -r '.downloads[0].id')
gravixlayer runtime browser download "$RT" --browser b1 "$DID"   # saves under its filename
```

```bash cURL theme={"dark"}
API="https://api.gravixlayer.ai/v1"

curl -sS -X POST "$API/agents/runtime/$RT/browser/b1/navigate" \
  -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"data:text/html,<a download=report.csv href=data:text/csv,id,name>Export</a>"}'

curl -sS -X POST "$API/agents/runtime/$RT/browser/b1/actions/click" \
  -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target":{"by":"text","value":"Export"}}'

# Wait for a download whose name contains "report"
DID=$(curl -sS -X POST "$API/agents/runtime/$RT/browser/b1/downloads" \
  -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"wait_name":"report","timeout_ms":30000}' | jq -r '.downloads[0].id')

# Metadata only
curl -sS "$API/agents/runtime/$RT/browser/b1/downloads/$DID?meta_only=true" \
  -H "Authorization: Bearer $GRAVIXLAYER_API_KEY"

# Bytes
curl -sS "$API/agents/runtime/$RT/browser/b1/downloads/$DID" \
  -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" | jq -r .data | base64 -d > report.csv
```

Each download entry is `{id, filename, path, bytes, state, mime, url}` —
`state` is in progress while the file transfers, then `completed` or
`canceled`. In TypeScript, `downloads` returns the entry array directly; in
Python it returns `{"downloads": [...]}`.

## Live view

`view` publishes a private watch URL for a browser — the display's view when
the browser is headed, or a screencast of the tab (`target_id`, empty = current
tab) when it is headless. Open **`browser_url`** — it carries a one-time auth
token. The token is returned only the first time a view URL is published;
later calls extend `expires_at` (one hour) but return `browser_url` without
it, so keep the first one.

```python Python theme={"dark"}
from gravixlayer import GravixLayer

client = GravixLayer()
sandbox = client.runtime.create(template="browser-small")
sandbox.display.enable()                      # headed browser on the display
bid = sandbox.browser.open(url="https://example.com")["browser_id"]

v = sandbox.browser.view(bid, fps=10)
print(v["browser_url"])  # open this to watch live
# The URL stops working when the runtime is killed.
```

```typescript TypeScript theme={"dark"}
import { GravixLayer } from 'gravixlayer';

const client = new GravixLayer();
const sandbox = await client.runtime.create({ template: 'browser-small' });
await sandbox.display.enable(); // headed browser on the display
const bid = (await sandbox.browser.open({ url: 'https://example.com' })).browserId;

const v = await sandbox.browser.view(bid, { fps: 10 });
console.log(v.browserUrl); // open this to watch live
// The URL stops working when the runtime is killed.
```

```bash CLI theme={"dark"}
gravixlayer runtime browser view "$RT" --browser b1 --fps 10 --quality 80   # prints browser_url
```

```bash cURL theme={"dark"}
API="https://api.gravixlayer.ai/v1"

curl -sS -X POST "$API/agents/runtime/$RT/browser/b1/view" \
  -H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fps":10,"quality":80}' | jq -r .browser_url
```

The call returns `201` with the web-service record — `browser_url`, `url`,
`port`, `expires_at`, and `token` (first publish only). `fps` defaults to 15
and caps at 30; `quality` is JPEG quality 1–100.

## Notes

* Screenshots, PDFs, and download bytes come back base64 — decode before
  writing to disk (the CLI writes files for you; cURL needs the
  `jq | base64 -d` hop).
* For anything visible but not downloadable — chart canvases, video frames —
  take a screenshot; PDF is for print-formatted output.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.